Poll status / async retries
NIC's IRP isn't always fast. We never block your request waiting on a slow upstream — instead, the API returns a queued or failed_retriable record and our worker keeps trying in the background.
State machine
┌──────────► generated ──► (cancelled, optional)
pending → queued ────┤
├──────────► failed_retriable ──► generated (retry succeeded)
│ └──► failed_terminal (gave up)
└──────────► failed_terminal (rejected by NIC immediately)
not_applicable (record exists for non-IRN flow)
| Status | Meaning |
|---|---|
pending | Record created, not yet sent to IRP. Transient. |
queued | Sent to IRP; awaiting acknowledgement. Worker may retry. |
generated | IRN issued. Final happy state. |
cancelled | IRN was cancelled (within 24h). |
failed_retriable | Transient failure (timeout, 5xx). Worker is retrying. |
failed_terminal | NIC rejected for a domain reason; no further retries. |
not_applicable | Record exists for an invoice that doesn't require an IRN. |
generated, cancelled, failed_terminal, and not_applicable are terminal — once you see them, the state won't change again on its own.
The cheap status endpoint
Polling the full GET /v1/einvoices/{id} works, but pulls the signed invoice + QR on every poll — bytes you don't need until status flips. Use the lightweight projection instead:
GET /v1/einvoices/{id}/status HTTP/1.1
Host: api.in.onefinops.com
Authorization: Bearer ...{
"id": "einv_01HRXY...",
"object": "einvoice.status",
"status": "queued",
"irn": null,
"errorCode": null,
"errorMessage": null,
"retryCount": 1,
"nextRetryAt": "2026-05-04T11:43:18Z"
}Once status flips to generated (or another terminal), do one full GET to capture signedInvoice, signedQrCode, ackNumber, etc.
Polling strategy
- Prefer webhooks. Subscribe to
einvoice.generatedandeinvoice.failed; our worker will tell you the moment state flips. - If you must poll, back off. Start at 5–10 seconds and double, capped at ~60 seconds.
- Stop once you hit a terminal state. Continuing to poll after
generatedwastes both ends. - Trust
nextRetryAt. If the field is set, our worker is going to retry at that timestamp anyway — polling more often than that buys nothing.
Detecting "stuck" requests
A record sitting in queued or failed_retriable past retryCount: 5 and several minutes is an indicator either NIC is having a bad day or the credential / payload has a problem the worker keeps hitting. Email [email protected] with the id and requestId and we'll dig in.
Updated about 5 hours ago
