Handling pending or failed IRN responses
The IRN generate call is synchronous. The response tells you immediately whether the IRP accepted or rejected the invoice.
What you get back
| HTTP | What it means | Your move |
|---|---|---|
| 200 | IRN generated. The body has irn, signedQrCode, signedInvoice populated. Status is generated. | Persist the IRN + signed payloads. Done. |
502 upstream.failure | The IRP rejected the request — vendor's reason is in message. Common cases: duplicate IRN, invalid GSTIN, schema validation. | Inspect message; fix the input; retry. Send the same Idempotency-Key only when the body is unchanged. |
| 503 / 504 | Transient — IRP unreachable or timed out. | Retry with the same Idempotency-Key after a backoff (1s → 2s → 4s, jittered). |
| 422 | Your body failed our pre-flight validation. details lists each field. | Fix the body; retry. Don't reuse the Idempotency-Key — the request changed. |
Why there's no separate status-polling endpoint
NIC's IRP is itself synchronous and OneFinOps mirrors that. POST returns the terminal state; there's nothing to poll. For eventual delivery on top of unstable infrastructure, lean on:
Idempotency-Key— a retry with the same key is safe. The first successful run wins; subsequent retries with the same key get the cached response and anIdempotency-Replayed: trueheader.- Webhooks — subscribe to
einvoice.generatedfor live updates if a downstream system (batch worker, queue) is producing IRNs in the background on your behalf.
Cancellations
Cancel is also synchronous: call POST /v1/einvoices/{irn}/cancel, get the updated record back. The cancellation window is 24 hours from generation; a cancel attempt past that returns 409 einvoice.cancel_window_expired.
Updated about 1 hour ago
