Asynchronous responses (202)
What a 202 Accepted means, how to resolve it to a final document status by polling the list endpoints, and why some countries need you to keep polling after a document has succeeded.
Not every document can be processed while you wait. When a country or route works asynchronously, or eezi cannot process your document serially, Create invoice and Create credit note return 202 Accepted instead of 200 OK. The document is stored and will be processed, but its final status is not yet known. This page describes the recommended way to pick that status up.
Short answerA
202means accepted, not done. Do not treat it as success. Once an hour, call List invoices and List credit notes with amodifiedwindow covering the last hour, and process every document whose status has changed. Keep doing this for the life of your integration — in some countries a document's status changes again after it has already succeeded.
What a 202 looks like
The response body is the document as stored, with a pending … status. The id is the handle you use from now on:
{
"id": "inv_01H3YH8RCFSK96H15ADYNQRVTD",
"ref": "DC230613-003",
"status": "pending response",
"type": "Sent",
"created": "2023-06-27T13:39:11.375Z",
"modified": "2023-06-27T13:39:11.375Z",
"routeRef": "mck_01H3YH8REVCFET714XZ2AB6Z5A"
// …the rest of the document
}The same applies to credit notes (crd_… ids).
Reading a document's status
status tells you where a document is in its life. The rule is simple:
| Status | Meaning | What to do |
|---|---|---|
Anything starting with pending | Still in flight — eezi is waiting on a submission, a response from the authority or network, or a follow-up. | Nothing yet. It will change. |
success | Cleared, reported or delivered as required. | Record the result, e.g. routeRef and any attachments. |
error | Failed. error.name and error.message say why. | Fix and resubmit, or handle the rejection. See Common Errors. |
voided | Cancelled after submission. | Record it. |
paid, rejected | A lifecycle update from the recipient, after the document had already succeeded. | See Countries with status updates after success. |
Never hard-code the list of pending … values. New in-flight states can appear as routes evolve; test for the pending prefix instead.
Resolving the 202
You could read each pending document by id (GET /invoice/{id}, GET /credit-note/{id}) until it settles. That works for a one-off check, but not for volume: it costs one request per document per attempt and you have to track every outstanding id yourself.
The recommended approach is to poll the list endpoints on a schedule and let the modified field tell you what changed. modified is updated whenever a document changes — including the moment a pending … status resolves. Every hour:
- Query
GET /invoicesandGET /credit-noteswithq=modified:[start TO end], where the window covers the last hour. - Page through the results with
limit(max500) andskipuntil you have read alltotalmatches. - For each document, look at
statusand act on it — skip anything stillpending …, recordsuccess, handleerror. - Move the window forward and repeat.
Generic: everything that changed
The simplest query. You get every document touched in the window and decide what to do per status:
GET /invoices?q=modified:[2024-06-01T09:00:00.000Z TO 2024-06-01T09:59:59.999Z]&limit=500
GET /credit-notes?q=modified:[2024-06-01T09:00:00.000Z TO 2024-06-01T09:59:59.999Z]&limit=500Specific: only the outcomes you care about
Add a status condition to receive only documents that have landed in a particular state. One query per outcome keeps each result set small and lets you route it to different handling:
# Succeeded in the last hour
GET /invoices?q=modified:[2024-06-01T09:00:00.000Z TO 2024-06-01T09:59:59.999Z] AND status:success&limit=500
# Failed in the last hour
GET /invoices?q=modified:[2024-06-01T09:00:00.000Z TO 2024-06-01T09:59:59.999Z] AND status:error&limit=500
# Paid in the last hour (countries with lifecycle updates)
GET /invoices?q=modified:[2024-06-01T09:00:00.000Z TO 2024-06-01T09:59:59.999Z] AND status:paid&limit=500
# Rejected by the recipient in the last hour
GET /invoices?q=modified:[2024-06-01T09:00:00.000Z TO 2024-06-01T09:59:59.999Z] AND status:rejected&limit=500Swap /invoices for /credit-notes — the syntax is identical. Add AND type:Sent or AND type:Received to limit to one direction. The full filter syntax and every filterable field are on Listing filters.
Join conditions with
AND. Without it the terms are treated as OR and the result set widens. Dates are ISO 8601 in UTC.
Making the poll reliable
- Overlap the windows. Start each window a few minutes before the previous one ended, or from the
modifiedvalue of the last document you processed. A missed run then heals itself on the next one. - Be idempotent. The same document can appear in two consecutive polls. Key your processing on
id+statusso seeing it twice is harmless. - Poll both resources. Invoices and credit notes are separate endpoints; a schedule that only reads
/invoicesmisses credit note outcomes. - Hourly is the recommended cadence. It comfortably covers batch-scheduled submissions. If you need something closer to real time for a specific document, read it by id — but keep the hourly poll as your source of truth.
Countries with status updates after success
In most countries success and error are the end of the road. In some, the document keeps living after it has succeeded: the recipient, their platform or the authority sends lifecycle updates, and eezi applies them to the document. status changes again — for example from success to paid or rejected — and modified moves with it.
This means you cannot stop watching a document once it has succeeded. The hourly modified poll above already covers this: a document that becomes paid three weeks after clearing will show up in that hour's window like any other change. The only thing you must not do is filter these documents out of your integration because they were already "done".
| Country | Route | Statuses after success | Details |
|---|---|---|---|
| France | E-invoicing (UBL) | paid, rejected | Lifecycle status — includes rejectCode and rejectReason |
| France | E-reporting | paid | Lifecycle status |
The same mechanism works in the other direction: for documents you receive (type:Received) in these countries, you are the one expected to send the lifecycle update, using Update invoice status (POST /invoice/{id}/status) and Update credit note status (POST /credit-note/{id}/status).
France: polling is not optionalUnder the French mandate a
rejectedinvoice has been refused by the buyer and needs to be corrected or credited, and payment statuses are part of your e-reporting obligations. If you integrate for France, run the hourlymodifiedpoll indefinitely and handlerejectedandpaidon documents that had already reachedsuccess.
Updated about 4 hours ago