Generate an IRN
This guide walks through registering an invoice on NIC IRP and getting a stable record back on your side.
Prerequisites
- A production or sandbox OAuth client (see Authentication).
- An IRP credential uploaded against the seller GSTIN (see Set up IRN credentials). Without one, the call fails with
400 irp_credentials.not_configured.
Request anatomy
The request body groups fields by purpose. The top-level keys are:
{
"documentDetails": { ... },
"transactionDetails": { ... },
"seller": { ... },
"buyer": { ... },
"shipTo": { ... }, // optional, only if shipping party differs from buyer
"dispatchFrom": { ... }, // optional, only if dispatch address differs from seller
"items": [ ... ],
"valueDetails": { ... },
"eWayBillDetails": { ... } // optional — issues a linked EWB in the same call
}Document details
Identifies the source document.
| Field | Notes |
|---|---|
type | INV invoice, CRN credit note, DBN debit note. |
number | Your own document number, up to 16 chars. |
date | YYYY-MM-DD. |
Transaction details
Describes the supply.
| Field | Notes |
|---|---|
taxScheme | GST (the only value supported). |
supplyType | B2B, B2C, SEZWP, SEZWOP, EXPWP, EXPWOP, DEXP. |
reverseCharge | "Y" / "N". Defaults to no on the wire if omitted. |
Seller and buyer
Both parties carry the same shape: gstin, legalName, tradeName (optional), address1, address2 (optional), location, pincode, stateCode, plus placeOfSupplyStateCode on the buyer for B2B/SEZ supplies.
State and place-of-supply codes are NIC's two-character codes (e.g. 36 Telangana, 02 Himachal Pradesh).
Items
Each line carries the description, HSN, quantity / unit, unit price, and the tax split. The split must be either CGST + SGST (intra-state) or IGST (inter-state) — never both — depending on whether the supply crosses state lines.
{
"serialNumber": "1",
"productDescription": "Consulting services",
"isService": "Y",
"hsnCode": "998314",
"quantity": 1,
"unit": "NOS",
"unitPrice": 10000,
"totalAmount": 10000,
"assessableAmount": 10000,
"gstRate": 18,
"igstAmount": 1800,
"totalItemValue": 11800
}Value details
Roll-up of all line totals. NIC re-runs the arithmetic on its side — if your totals don't match the line sum within the small tolerance NIC allows, the call fails with 422 validation_error.
Minimal happy path
POST /v1/einvoices/generate HTTP/1.1
Host: api.in.onefinops.com
Authorization: Bearer eyJhbGciOi...
gstin: 36AMBPG7773M002
Content-Type: application/json
X-Request-Id: 4f1d8a2c-…Body: see the Quickstart for a full minimal B2B example.
Response (200 OK):
{
"irn": "a1b2c3d4e5f6...",
"ackNumber": 112324567890123,
"ackDate": "2026-05-14T11:42:18.000Z",
"status": "ACT",
"signedInvoice": "eyJhbGciOi...",
"signedQRCode": "eyJhbGciOi...",
"message": "E-Invoice generated successfully"
}What to do with the response:
- Persist
irnagainst your invoice. It's the durable handle for everything downstream — refetch, cancel, link to an EWB. - Decide whether to store
signedInvoiceandsignedQRCode. They're large. If you can refetch on demand, do that — callGET /v1/einvoices/irn?irn=…later. If you do persist them (for offline printing pipelines, for instance), they don't expire on our side. - Render the QR for printing.
POST /v1/einvoices/qrimagetakes the signed QR JWS and returns a PNG ready to place on the printed invoice.
Duplicate detection (DUPIRN)
NIC IRP is itself idempotent on (sellerGstin, docType, docNumber, financialYear). If you re-submit the same tuple, NIC returns the existing IRN — not a fresh one — and OneFinOps surfaces this verbatim:
{
"irn": "<the existing IRN>",
"ackNumber": …,
"ackDate": "…",
"status": "ACT",
"message": "2150 : Duplicate IRN",
"infoCode": "DUPIRN"
}If you need to distinguish a fresh generate from a replay programmatically, branch on infoCode == "DUPIRN" rather than parsing the message string.
OneFinOps applies the same dedup against its own cache before calling NIC — so even if NIC has gone idle on you, you'll see a consistent envelope.
Failure paths
| Status | Body code | What it means | Your move |
|---|---|---|---|
| 400 | irp_credentials.not_configured | No IRP credential found for seller.gstin. | Upload via Set up IRN credentials. |
| 401 | auth.invalid_token | Token missing, malformed, or expired. | Mint a fresh token. |
| 403 | auth.entitlement_missing | Plan doesn't include e-invoicing. | Contact account manager. |
| 422 | validation_error | Body shape or arithmetic failed validation. | Inspect details[] in the response. |
| 502 | upstream.failure | NIC IRP refused for a domain reason — bad GSTIN, fiscal-year mismatch, GSTIN suspended, etc. | Read upstream.code / upstream.message and fix the source data. |
| 503 | upstream.unavailable | NIC IRP unreachable (timeout, connectivity). | Retry after backoff. |
Storage advice
Treat the OneFinOps record as the durable source. After registration:
- Pin
irn, the matchingdocumentDetails.number, andstatusagainst your invoice row. - Refetch
signedInvoiceandsignedQRCodeon demand. They don't change post-registration. - Re-fetch with
GET /v1/einvoices/irn?irn=…when downstream systems need the current status (after a cancel, for example).
Where to next
- Cancel an IRN — for the 24-hour cancellation window.
- Generate IRN with E-Way Bill — issue both in one call.
- Errors — full error code table.
