Invocie

Tech

Multi-region e-invoicing API ڈیزائن کرنا: میدان سے سیکھے گئے سبق

اگر آپ ایسا infrastructure بنا رہے ہیں جو clearance اور post-audit دونوں ممالک کو serve کرے، تو abstractions درست کرنے کا ایک ہی موقع ہے۔ یہ وہ ہے جو ہم نے مشکل سے سیکھا۔

Invocie Team · 4 دسمبر، 2025 · 6 منٹ کا پڑھنا


We built Invocie's compliance engine to handle MENA clearance, EU Peppol, and global post-audit out of one codebase. The architecture took three iterations to settle. These are the design choices that survived.

1. Strategy Pattern at the country level, not the region level

Region is too coarse. Saudi (clearance, ZATCA, 15%) and the UAE (interoperable, FTA, 5%) are both "MENA" but architecturally very different. We dispatch by ISO country code first, region second, with a Default fallback.

function pickStrategy(t: { country_code: string; tax_region: string }) {
  if (MENA.includes(t.country_code)) return new MENAStrategy();
  if (EU.includes(t.country_code))   return new EUStrategy();
  if (t.tax_region === "MENA") return new MENAStrategy();
  if (t.tax_region === "EU")   return new EUStrategy();
  return new DefaultStrategy();
}

2. Decimal everywhere, never floats

We use BigInt with fixed-point scaling (10000x for 4-decimal precision) in performance paths and decimal.js where the SDK is friendlier. The only forbidden type for monetary values is JavaScript's number — we caught three rounding bugs in pre-production tracing back to a stray Number().

3. Async-by-default, sync-by-exception

The HTTP route that creates an invoice never blocks on the government API. It writes to the database, enqueues a job, and returns 201. The worker handles the gov submission with retries (exponential backoff, max 6 attempts, jitter). This insulates the user-facing API from gov-side latency, and it makes retries safe even when ZATCA has a bad afternoon.

4. Separate the canonical model from the wire format

Our internal Invoice type is the same regardless of country. Each strategy's buildArtifacts() turns it into the country-specific wire format (TLV QR, UBL 2.1 XML, or just a Default JSON). The canonical model never knows about XML. The XML never escapes the strategy. This makes adding India IRP later a one-file change.

5. Logging is part of the contract

Every gov interaction writes a ComplianceLog row with prev_hash → hash chaining. When auditors come — and they will come — you don't want to be reconstructing what happened from app logs. The DB row is the receipt.


متعلقہ پڑھائی

Integrating UAE E-Invoicing With Your ERP: A Technical Guide

A technical walkthrough for the Head of IT and ERP transformation lead: how UAE PINT maps onto SAP, Oracle, Microsoft Dynamics, and custom ERPs, the data you must clean first, and the integration patterns that survive production.

UBL 2.1 آسان زبان میں: جدید e-invoicing کے پیچھے کا XML معیار

دنیا کا تقریباً ہر بڑا e-invoicing حکم پردے کے پیچھے UBL 2.1 جاری کرتا ہے۔ ان حصوں کا آسان زبان میں جائزہ جنہیں آپ کو واقعی سمجھنا ہے۔

Tamper-evident audit trail کے لیے Hash Chain

ZATCA انہیں لازم قرار دیتی ہے، EU auditors انہیں پسند کرتے ہیں، اور implement کرنا سستا ہے۔ دیکھیں کہ chained SHA-256 invoice ledger کو ایسی چیز میں کیسے بدل دیتا ہے جس کی integrity آپ ثابت کر سکیں۔

ہر مارکیٹ میں کمپلائنٹ انوائسز بھیجیں

ZATCA، FTA، Peppol اور عالمی پوسٹ-آڈٹ — ایک API۔

ہماری ٹیم سے بات کریں