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.

FieldNotes
typeINV invoice, CRN credit note, DBN debit note.
numberYour own document number, up to 16 chars.
dateYYYY-MM-DD.

Transaction details

Describes the supply.

FieldNotes
taxSchemeGST (the only value supported).
supplyTypeB2B, 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 irn against your invoice. It's the durable handle for everything downstream — refetch, cancel, link to an EWB.
  • Decide whether to store signedInvoice and signedQRCode. They're large. If you can refetch on demand, do that — call GET /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/qrimage takes 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

StatusBody codeWhat it meansYour move
400irp_credentials.not_configuredNo IRP credential found for seller.gstin.Upload via Set up IRN credentials.
401auth.invalid_tokenToken missing, malformed, or expired.Mint a fresh token.
403auth.entitlement_missingPlan doesn't include e-invoicing.Contact account manager.
422validation_errorBody shape or arithmetic failed validation.Inspect details[] in the response.
502upstream.failureNIC IRP refused for a domain reason — bad GSTIN, fiscal-year mismatch, GSTIN suspended, etc.Read upstream.code / upstream.message and fix the source data.
503upstream.unavailableNIC IRP unreachable (timeout, connectivity).Retry after backoff.

Storage advice

Treat the OneFinOps record as the durable source. After registration:

  • Pin irn, the matching documentDetails.number, and status against your invoice row.
  • Refetch signedInvoice and signedQRCode on 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