Your platform issues B2B invoices in a market where tax law requires each invoice to be registered with a government portal before it is valid, and the portal returns a reference number the invoice must carry. The portal's availability is outside your control. How does this change the invoicing architecture?
Show the full answer Hide the answer
What is being tested
Whether you can design around a mandatory synchronous dependency you do not operate and cannot bypass. This is not an integration that can be made asynchronous by choice: without the reference number, the document is not a valid tax invoice.
India's GST e-invoicing regime is the concrete, documented instance. Notification 10/2023 – Central Tax lowered the threshold to businesses with aggregate turnover above ₹5 crore from 1 August 2023, after earlier phases at higher thresholds. Covered businesses upload the invoice to an Invoice Registration Portal, which returns an Invoice Reference Number, a digitally signed invoice and a QR code. Several other jurisdictions impose structurally similar clearance regimes.
The reasoning
Three properties of the obligation drive the design.
The number is required for validity, not for reporting. So the invoice cannot be sent to the customer, and in many flows cannot be recognised in revenue, until clearance succeeds. Any design that treats the portal as a downstream reporting hop will eventually ship an invalid invoice.
The dependency has its own availability, and it is not yours. Treat it as a third party with no SLA you can enforce and plan for multi-hour unavailability, including at month end when every covered business is submitting.
Submission must be exactly-once in effect. A duplicate submission either fails or creates a second registration, and both are a tax problem rather than a software problem.
The design
- Separate document creation from clearance. Create the invoice internally with a stable local identifier and a state of
awaiting_clearance, then clear it through a queue with retries. The customer-facing step is gated on state, not on a synchronous call. - Make the submission idempotent on your own document number, and retain the portal's response (reference number, signed payload, QR) as the authoritative artefact. On an ambiguous timeout, query the portal for the existing registration before resubmitting. Never retry a tax submission blind.
- Model the legal clock separately from the technical one. Clearance deadlines are set in law relative to the invoice date, so the queue needs priority by regulatory deadline rather than first-in-first-out.
- Handle the rejection path as a business flow. A rejected invoice is usually a master-data problem — a counterparty's tax identifier, a tax code, a unit of measure — so rejections must reach someone who can fix the data, not a dead-letter queue.
- Keep an evidence store. The signed response, the submission payload and the timestamps, retained for the statutory period, because the audit asks you to prove what you submitted and when.
What it costs
A queue, a state machine on the invoice, a reconciliation job against the portal's own records, and a support process for rejections. Also a market-specific module: the clearance regimes differ enough that a single canonical implementation across jurisdictions becomes a worse abstraction than separate adapters behind a common interface. This is the case where per-market divergence is correct and a canonical model is the mistake.
How it fails
- Blind retries creating duplicate registrations, which require a credit note and an explanation.
- Invoices stuck in
awaiting_clearancewith nobody owning the queue, discovered at month end when revenue does not reconcile. - A portal schema change on a government timetable, which is a hard external deadline you did not set.
- Clock skew on a signed payload, where a timestamp outside the portal's tolerance rejects an otherwise valid submission.
When this is the wrong answer
Where the obligation is genuinely periodic reporting rather than per-document clearance, do not put the regulator on the transaction path: batch, reconcile and submit on schedule, which is simpler and sufficient. The design above is forced only by validity-at-issuance regimes. And below the turnover threshold, the correct architecture is none of this, plus a monitored trigger on the threshold, because the obligation arrives with the growth rather than with a decision.