E-Invoice IRN Generation: What Actually Happens to Your Invoice
- E-invoicing means registering the invoice, not emailing it. Your system sends structured JSON to an Invoice Registration Portal (IRP) and gets back an IRN and a signed QR code.
- The IRN is a 64-character hash of four fields â supplier GSTIN, document type, document number, financial year â so the same invoice can never be registered twice.
- Most integration failures are mundane: mandatory fields you never collected, HSN codes, place of supply, rounding.
- Cancellation on the IRP is all-or-nothing and time-limited. After the window closes, corrections go through the GST return, not the portal.
- Applicability is set by notification and has been lowered repeatedly. Check the current CBIC/GSTN notification for your turnover â not a figure printed in an article.
- What e-invoicing actually changes
- What an IRN is and what it is derived from
- The round trip, step by step
- Where JSON schema integrations break
- Why the QR code is signed
- Cancellation, amendment, and the window you get
- What flows downstream once an IRN exists
- Idempotency and duplicate IRNs
- Sandbox versus production discipline
- What happens when the IRP is unreachable
- Common questions
Somebody has told you the invoice has to be registered before it is valid, and you are trying to work out what that means for the billing code you already have. Short answer: e-invoicing does not mean sending the customer a machine-readable file. It means your system submits the invoice to a government Invoice Registration Portal before the document is final, the IRP validates it, assigns an Invoice Reference Number, digitally signs it and returns a QR code â and an invoice that was never registered is not a valid tax invoice, however correct the arithmetic on it is.
That single inversion â the invoice is not finished until a third party says so â is what breaks existing billing systems. Everything below follows from it.
What e-invoicing actually changes
E-invoicing under GST is a registration step, not a delivery format. The taxpayer still raises the invoice in their own system and still numbers it themselves. What changes is that the data must first be reported to an IRP in a prescribed JSON schema, and the IRP's response becomes part of the invoice. The common misreadings each produce a different wrong architecture:
| What people assume | What is actually true |
|---|---|
| "E-invoice means we email a PDF instead of posting one." | The delivery channel is irrelevant. Registration with the IRP is the whole requirement. |
| "The government generates our invoice numbers now." | You generate the document number. The IRP generates the IRN, a different identifier derived from yours. |
| "We can register invoices in a nightly batch." | Registration is tied to a reporting window and downstream steps wait on it. Batching is a decision with consequences, not a free one. |
| "It only applies to big companies." | Applicability is set by notification and has been lowered repeatedly. Check the current CBIC/GSTN notification for your turnover band. |
On thresholds specifically: every turnover figure written down for e-invoicing has been superseded at least once. Whether it applies, from which date, and with which exemptions is a question for the current notification and your own advisor â not for a hard-coded constant. If you must encode it, make it configuration with an effective-from date.
What an IRN is and what it is derived from
An Invoice Reference Number (IRN) is a 64-character hexadecimal hash that uniquely identifies one registered invoice in the GST system. It is not a sequence number and not a random token. It is computed deterministically by hashing four fields of the invoice itself with SHA-256: the supplier GSTIN, the document type (invoice, credit note or debit note), the document number exactly as you issued it, and the financial year in the YYYY-YY form the schema expects.
Three consequences fall out of that, and they matter more than the algorithm does:
Identical key fields produce an identical hash and the IRP rejects it as a duplicate, which makes the portal the authority on whether your invoice number has already been used this year.
If two branches on the same GSTIN can independently mint INV-1042, one of them loses. Per-GSTIN, per-financial-year uniqueness becomes a hard constraint enforced outside your database.
The inputs are all yours, so you can hash locally and use the result as your own idempotency key.
Note what the IRN is not derived from: line items, amounts, tax rates, the buyer. Change the price on a registered invoice and the IRN would not change, which is precisely why the IRP will not let you change it at all.
The round trip, step by step
Stripped of vendor-specific packaging, the flow is the same everywhere:
- Build the payload. Map your invoice into the prescribed JSON schema â supplier and buyer blocks, optional dispatch and ship-to blocks, item list, value and tax totals, document metadata.
- Authenticate. Get a session token from the IRP or your GST Suvidha Provider. Tokens expire; cache and refresh rather than fetching one per invoice.
- Submit. The IRP validates the schema, checks both GSTINs, and checks the document number has not already been registered.
- Receive. On success you get the IRN, an acknowledgement number and date, and a signed QR code payload.
- Persist before anything else. Write the IRN, acknowledgement details and QR payload against the invoice row in the same transaction that marks it issued â before you render a PDF or fire a webhook.
- Print. The QR code goes on the document you give the buyer.
Step five is the one teams get wrong. Render first and persist second, and a crash in between leaves an invoice registered with the government and unknown to your own system â the worst available state, because you can neither re-register it nor reproduce the QR.
Where JSON schema integrations break
The schema is large, but failures cluster. Almost all first-week rejections are one of these:
| Failure | What it looks like | The actual fix |
|---|---|---|
| Mandatory fields you never collected | Rejection on a field your UI does not have â buyer state code, PIN code, unit of measure on a service line | Backfill in the source system. A default injected at the mapping layer is a lie that reaches a tax record. |
| HSN / SAC codes | Missing, too short, or copied from a similar product years ago | Make it a required, validated field on the product master, not free text on the line. |
| Place of supply | Intra-state tax computed where inter-state was due, or vice versa | Derive it explicitly from the transaction, and assert the CGST/SGST-versus-IGST split agrees before you submit. |
| Rounding | Totals differing from the schema's expectation by a paisa or two | Round where the schema rounds, in the same order, using decimal arithmetic. Floats in a tax total are a bug waiting for a tolerance window. |
| Stale or wrong GSTINs | Buyer GSTIN rejected as invalid or inactive at the moment of registration | Validate and verify upstream, at onboarding, not at invoice time. |
The last row fails at the worst possible moment: a buyer GSTIN that was fine when the customer was created can be cancelled months later, and you find out when an invoice bounces on a Friday evening. Verify at customer creation and re-check on a schedule â the difference between a format check and a real lookup is in GSTIN verification versus format validation, and the process side in GST vendor onboarding automation in an ERP. Our own GSTIN API exists because we kept rebuilding that lookup per client.
Validate your payload locally first. The schema is published. Running your JSON against it in your own test suite turns a whole class of production rejections into a failing unit test, and it costs one afternoon.
Why the QR code is signed
The QR code returned by the IRP is not a link and not decoration. It contains a digitally signed payload â key invoice fields plus the IRN â signed by the portal. Without it, a printed invoice is an assertion by the supplier. With it, anyone holding the document can verify offline that the portal saw these exact values: this supplier GSTIN, this buyer GSTIN, this document number and date, this total, this IRN. A tampered amount breaks the signature; an invoice that was never registered has no signature to break.
So store the signed payload exactly as the IRP returned it, byte for byte, and regenerate the QR image from it when you print â re-encoding the fields yourself produces a code that will not verify. And treat scannability as a real constraint on your invoice template, not something to squeeze when the layout gets tight.
Cancellation, amendment, and the window you get
This is the part that surprises people used to editable drafts.
Cancellation on the IRP is all-or-nothing and time-limited. You can cancel a registered IRN entirely, within a short window after generation, with a reason. You cannot cancel it partially and you cannot edit it, and once the window closes the IRP will not accept a cancellation at all. That window has historically been narrow â hours, not days â and is set by the rules in force, so confirm the current one rather than assuming the number you remember.
There is no amend operation on the IRP. If a registered invoice is wrong and the window has passed, the correction happens through the GST return, in the amendment tables, or through a credit or debit note â itself a document that must be registered and gets its own IRN. The IRP records what was reported; the return is where the position gets corrected.
Design consequence: if your product lets users edit an invoice after it is issued, that feature has to change. Registration becomes the point of no return in your UI â edit affordance removed, credit-note flow in its place â or your users will edit a document whose government-registered twin no longer matches it.
One more trap: a cancelled IRN does not free up the invoice number. Because the IRN is derived from that number, re-registering it produces the same hash the IRP has already seen. Cancellation means issuing a fresh number, so your numbering must tolerate gaps and any report assuming an unbroken sequence needs revisiting.
What flows downstream once an IRN exists
The compensation is that registration is a single reporting event several other obligations hang off. Once an invoice carries an IRN:
- Return data is pre-populated. Registered invoice details flow into the supplier's outward-supply return data and the buyer's auto-drafted statement instead of being keyed in again. That is also how a registered invoice reaches your customer's input tax credit on its own â the mechanism that makes suppliers' filing behaviour a live exposure for their buyers, covered in vendor GST verification and input tax credit.
- E-way bill generation is linked. Where a movement of goods needs an e-way bill, the registered invoice data can drive it rather than being re-entered, with the IRN tying the two records together.
- Filing status becomes observable. Whether a counterparty is actually filing becomes a queryable fact rather than a phone call â see checking GST return filing status programmatically.
The trade is one extra synchronous dependency at invoice time in exchange for several downstream re-keying steps disappearing. Usually a good trade â but only if you actually delete the re-keying. Bolt e-invoicing on while keeping the manual return-prep spreadsheet and you get the cost and none of the benefit.
Idempotency and duplicate IRNs
Every real integration eventually hits this: you POST an invoice, the connection times out, and you do not know whether the IRP registered it. Retrying blindly is how you end up with a duplicate-IRN error in a log at 2am. Four things make that survivable.
Hash the four key fields yourself and store the result on the invoice row. You now have a stable identifier for this attempt that does not depend on the network.
draft â pending â registered â cancelled, plus rejected. A boolean is_einvoiced column cannot represent "we submitted and do not know" â the state you most need to represent.
A duplicate error means the invoice is registered â your first attempt landed. Fetch the existing registration details, store them, move to registered. An integration that pages a human on duplicates trains that human to ignore alerts.
Registration belongs in a queued job with bounded retries and backoff, and the response must be persisted in a single transaction with the status change.
A useful invariant to assert in tests: for any invoice in state registered, the stored IRN, acknowledgement number and signed QR payload are all non-null. If any one can be missing, some code path persisted a partial response.
Sandbox versus production discipline
The IRP ecosystem provides a sandbox, and the temptation is to treat it as a staging clone. Never let a sandbox credential and a production credential be interchangeable at runtime: different base URLs, different credential names, and a startup assertion that refuses to boot a production build against a sandbox endpoint. Registering real invoices against a sandbox produces IRNs that do not exist; registering test invoices against production produces tax records you then have to cancel.
And do not test against a live endpoint by default. Run your suite against recorded fixtures â real captured responses for success, duplicate, schema rejection, timeout and expired token â so it is fast, offline and deterministic, and keep a small sandbox smoke test on a schedule to catch contract drift. Fixtures are also the only sane way to handle the error catalogue: the IRP returns many coded errors, and every code you handle specially should be pinned by a test.
What happens when the IRP is unreachable
This is the operational question that separates a working billing product from a demo, and it is almost always answered late. Registration puts a synchronous third-party dependency into the one workflow your business cannot pause, so decide explicitly what happens when it is down:
- Do not block the user on the round trip. Accept the invoice, queue the registration, show its state honestly. A spinner tied to a government endpoint is a support-ticket generator.
- Make "awaiting registration" a first-class, visible state. Finance needs a queue they can watch drain. Hiding it in a jobs table is how a backlog goes unnoticed for a week.
- Decide whether goods move. Whether an invoice can be acted on commercially before its IRN exists is your business's call and your advisor's â but the code has to encode an answer.
- Back off, do not hammer. Exponential backoff with jitter and a cap; retry storms against a recovering portal help nobody.
- Alert on queue age, not individual errors. The signal is "oldest unregistered invoice is four hours old", not "one request failed".
- Keep a documented manual path, and let your system accept an externally-generated IRN being written onto an invoice.
If you are choosing between building this and buying billing software that has already done it, outage behaviour is one of the better questions to interrogate a vendor with â the general framing is in custom software versus SaaS for a small business.
Common questions
Is an invoice without an IRN valid? Where e-invoicing applies to the supplier, an invoice never registered with an IRP is not a valid tax invoice, and the buyer's ability to claim credit on it is compromised. That is why the requirement has teeth. Whether e-invoicing applies to a particular business is a question for the current CBIC/GSTN notification and that business's own advisor.
Who generates the IRN â me or the portal? The Invoice Registration Portal generates and returns it. You can compute the same hash locally from supplier GSTIN, document type, document number and financial year, which is useful as an idempotency key, but a self-computed hash is not a registration. Only the portal's response, with its acknowledgement details and signed QR, means the invoice is registered.
Can I edit a registered e-invoice? No. The IRP has no amend operation. Within a short window after generation you can cancel the IRN entirely and issue a fresh invoice under a new number; after that, corrections go through the GST return or through a credit or debit note, which is itself registered and receives its own IRN. Confirm the current cancellation window before relying on it.
What turnover triggers e-invoicing? Deliberately not answered here. Applicability is set by notification, the threshold has been lowered repeatedly, and any figure printed in an article ages badly. Check the current CBIC/GSTN notification for your turnover band and effective date, and treat it as configuration in your system rather than a constant in code.
Do I need a GST Suvidha Provider to integrate? Not necessarily, though most teams end up using one. A GSP or ASP absorbs authentication, schema versioning and the error catalogue, at the cost of an extra dependency and a contract. Either way the mechanism is unchanged: the IRN, the signed QR and the cancellation rules belong to the portal, not the intermediary.
How does this relate to supplier invoices we receive? Opposite direction. E-invoicing is about registering what you issue; pulling structured data out of documents suppliers send you is a separate problem, covered in automating invoice document extraction. A happy side effect is that a registered inbound invoice arrives with a signed QR you can verify rather than parse hopefully.
E-invoicing puts a third party inside your invoice lifecycle: the document is not a valid tax invoice until an IRP has registered it and returned an IRN and a signed QR code. Because the IRN is a hash of your own supplier GSTIN, document type, document number and financial year, registration is naturally idempotent â use that as your idempotency key, treat duplicate errors as success, and model registration as a state machine rather than a boolean. Get the payload right at the source, never reuse a number after cancellation, and decide up front what happens when the portal is unreachable.
DL Minds Team
Digital marketing and web development expert at DL Minds. Passionate about helping businesses grow through innovative technology solutions and strategic digital marketing.