E-invoice lifecycle
This page explains what happens to a document from the moment you send it to POST /v1/send until it reaches a final outcome, which parts happen while your request is open, which happen afterwards, and how you find out the result. It applies to every country and every way of getting data in: the API, CSV upload, the dashboard and every accounting or payment integration.
200. The answer is in the body: a clearanceStatus, an outcome and a terminal flag. A failed validation, a document that needs information, a hold and a tax authority rejection are each a status on a stored document, not an error status code and not a dropped request. You can always find the document again, see why it is in its status and act on it.Stored first, then processed
- Envelope check. Authentication, plan access, rate limit, valid JSON, correct field types and the identifying fields. Only a request that fails here is answered with an error status (
400,401,403,413or429), and nothing is stored. - Store. The document is saved exactly as you sent it, with status
RECEIVED. From this point it cannot disappear. - Process, in the same request. Clearvo normalises and enriches the data, runs the validation rules, resolves the tax code, works out which mandate applies, checks that your setup is complete, then generates the country's document and checks it against the schema. Each step either moves the document on or stops it in exactly one status.
- Respond with
200. The body carries the status the document has reached. - Finish asynchronously, where a tax authority or network is involved. Submission to the authority, clearance polling and delivery happen after your request has returned. The status changes and you are told through
GET /v1/statusor a webhook.
Nothing that was accepted is lost, and nothing waits in a state forever without someone being told.
What is synchronous and what is not
These steps always happen before POST /v1/send returns: the envelope check, storing the document, normalisation, enrichment, validation rules, tax code resolution, mandate resolution, setup checks, and generating and schema-checking the document.
What happens after that depends on how the country works:
| Country type | Examples | When the request returns | How you get the final status |
|---|---|---|---|
| Issued by Clearvo, no authority call per document | Spain (VeriFactu), Portugal, Germany | The document is issued before the request returns. clearanceStatus: ACCEPTED, terminal: true. | Nothing more to wait for. |
| Authority or network answers after submission | Italy, Poland, Romania, Hungary, Argentina, France, Saudi Arabia, Peppol countries | The document is stored, generated and queued for submission. clearanceStatus: PENDING, terminal: false, with nextPollAfter. | GET /v1/status until terminal: true, or a webhook. Some authorities answer within seconds, others take minutes or longer. |
| Reported later in aggregate | France e-reporting, Spain SII in batch mode | The document joins a reporting period. clearanceStatus: ACCUMULATED. | Status moves when the period is submitted. Reminders and webhooks follow the reporting deadline. |
| Country not open yet | Portugal (live sends), Greece, Malaysia, Israel, Egypt, Jordan, when the country is not yet enabled for your account | Stored and held. clearanceStatus: HELD_AWAITING_AUTHORIZATION, errorCode: MANDATE_SUPPORT_NOT_OPERATIONAL, terminal: false. Still 200. | Nothing for you to do and no need to resend. Clearvo holds the document and sends it automatically once the country is enabled for your account. Follow it with GET /v1/status or the webhook. |
| No obligation | A country or date with no mandate for this entity | Recorded and retained. NO_MANDATE or NOT_SUPPORTED, terminal: true. | Nothing more to wait for. |
A 200 never means the authority has accepted the document. Read outcome and clearanceStatus, and keep checking while terminal is false.
HTTP status codes
| Code | Meaning |
|---|---|
200 | Clearvo holds a record of your document. Everything else is in the body, including a validation failure (REJECTED or NEEDS_INFO with errors[]), a hold, no obligation, and an aggregate-report acceptance (ACCUMULATED). Every body that comes from a stored document, including a rejection, carries its id. Branch on outcome, never on the status code alone. Re-sending an identical document returns the stored result with idempotent: true; if it is still being processed, you get its id and RECEIVED, which is the only way to find it. ok comes from the status alone: it is false for REJECTED, NEEDS_INFO, SETUP_NEEDED (for example France NEEDS_INFO, Portugal SETUP_NEEDED) and HELD_PLATFORM_FAULT, and true for every other status, and it is the same on every replay (a replay carries the same error, errors[], fixUrl and nextStep). It is not the outcome, so branch on outcome. A rejection carries error (code, message, fixUrl) and one errors[] entry per failed check. When enabled for your account, a temporary problem that interrupts processing after the document is stored gives 200 with RECEIVED and a PROCESSING_DELAYED warning: do not resend, Clearvo finishes it. When it is not enabled, such a failure is a 503 (see below). A dryRun answers the same 200 body (dryRun: true, ok: false when a real send would be stored as a rejection or hold) and stores nothing. |
400 | The request cannot be read: invalid JSON, no country or invoiceNumber, a malformed header, an unrecognised country code, or a platform-set field such as channel or source. Nothing is stored. A document that is well formed but fails a validation check is not a 400: it is stored and answered 200. |
401, 403 | Missing or invalid key, a plan that does not include the product, or an entity the key cannot use. |
409 | IDEMPOTENT_BODY_MISMATCH: you re-sent a document that has already been processed with different content. The existing document is not changed, and the refused attempt is recorded in its history as a refused_resend event. Send the change as a correction instead. |
413, 429 | Request too large, or rate limit reached. Retry after the interval in Retry-After. |
503 | INGEST_UNAVAILABLE: Clearvo truly could not store the document. Nothing was recorded. Retry the same request with the same body and x-idempotency-key, after the Retry-After seconds. A 503 with Retry-After is also how a temporary failure before the document is stored is answered. When enabled for your account, a temporary storage problem is instead answered 200 with RECEIVED, and Clearvo completes the processing itself. |
The key rule for integrations: a 2xx means "stored", not "succeeded". Check outcome before you mark a document as sent in your own system. POST /v1/invoices/{id}/retry follows the same rule: if the authority rejects the retried document, the answer is 200 with ok: false and clearanceStatus: REJECTED.
Response fields
| Field | Description |
|---|---|
id, referenceId | The Clearvo id of the stored document, and the reference to use with GET /v1/status. |
clearanceStatus | One status from the list below. |
outcome | A coarse result that is the same for every country: CLEARED, REJECTED, ACCUMULATED, NEEDS_INFO, NO_OBLIGATION, HELD or PROCESSING. CLEARED means processing continues normally, it does not by itself mean the authority has answered. PROCESSING means the document is stored (RECEIVED) but not processed yet: poll GET /v1/status or wait for the invoice.status_changed webhook. UNROUTABLE is NEEDS_INFO: only you can move it. UNDELIVERED is HELD. RECEIVED and UNROUTABLE are no longer CLEARED. |
statusClass | Who the document is waiting for: IN_FLIGHT, WAIT_MERCHANT, WAIT_PLATFORM, DONE_OK, DONE_REJECTED or DONE_NA. |
terminal | true when the status will not change again. |
nextStep | What has to happen next, who does it and where, or null when nothing is outstanding. See below. |
errors[], warnings[] | Every failed check and every warning, collected together rather than stopping at the first. Two warnings come from identity handling: IDEMPOTENCY_KEY_REUSED_ACROSS_DOCUMENTS and NO_IDENTITY_NO_DEDUP, see below. |
reviewRequired | true when somebody has to look at the document before it can move on. |
nextPollAfter | The earliest sensible time to ask again while the document is not terminal. |
statusClass and nextStep are returned by POST /v1/send (including the bodies for stored rejections and holds), GET /v1/status and GET /v1/invoices/{id}.
nextStep
| Field | Description |
|---|---|
actor | Who has to act: merchant (you), platform (us), authority or system. system means we are already working on it and nothing is needed from you. |
message | What to do, in plain words. |
fixUrl | Where you can fix it yourself. Only present when you can. |
nextStep is null when nothing is outstanding, for example for ACCEPTED, DELIVERED, CANCELLED, DUPLICATE, NO_MANDATE, EXCLUDED and NOT_SUPPORTED.
Statuses
There is one status model for every country. The class tells you who, if anyone, has to act.
In progress: we are working on it (IN_FLIGHT)
| Status | Terminal | Meaning and what to do |
|---|---|---|
RECEIVED | No | Stored, processing has not finished. Normally you only see this for a moment. If processing is interrupted, we restart it automatically. Nothing for you to do. |
PENDING | No | Submitted to the authority or network, waiting for the answer. Poll GET /v1/status after nextPollAfter, or wait for the webhook. |
ACCUMULATED | No, until the period is reported | Accepted into a reporting period and will be reported in aggregate. Nothing to do unless the period asks you to review it. |
Waiting for you (WAIT_MERCHANT)
| Status | Terminal | Meaning and what to do |
|---|---|---|
NEEDS_INFO | No | A fact is missing or a value is invalid, and you can correct it. errors[] says which and fixUrl where. Resend the corrected document to POST /v1/send with the same invoice number to re-run the stored one. |
SETUP_NEEDED | No | Something in your setup is missing, for example credentials for a country. Add it and the document continues by itself. |
HELD_UNMAPPED_TAX_CODE | No | A line used a tax code you have not configured. Add the code under POST /v1/tax/client-codes and the document continues by itself. |
OBLIGATION_DISABLED | No | The obligation this document falls under is switched off for your entity. Switch it on and the document continues. |
UNROUTABLE | No | Outcome NEEDS_INFO. Peppol only: the customer is not reachable on the network. Check the customer's Peppol identifier, or retry with POST /v1/invoices/{id}/deliver once the customer is registered. |
RECEIVED_NEEDS_REVIEW | No | A document you received that did not pass the checks on arrival. Review it and decide how to handle it. Nothing sent to you is dropped. |
A document waiting for you never expires. When enabled for your account, Clearvo reminds the entity's users by email on day 3 and day 7, then in a weekly digest, until it is resolved. Reminders are not on for every account, so watch GET /v1/status or the invoice.status_changed webhook rather than relying on them.
Waiting for us (WAIT_PLATFORM)
| Status | Terminal | Meaning and what to do |
|---|---|---|
HELD_AWAITING_AUTHORIZATION | No | We cannot submit to this authority for your account yet, for example for Portugal (live sends), Greece, Malaysia, Israel, Egypt or Jordan. errorCode is MANDATE_SUPPORT_NOT_OPERATIONAL. We hold the document and send it automatically once the country is enabled for your account. You do not need to resend it. |
HELD_UNKNOWN_MANDATE, HELD_UNMAPPED_DECISION, HELD_PLATFORM_FAULT | No | We need to complete a configuration step or look into an answer from an authority. It is not a problem with your data. We are alerted and continue the document when it is resolved. |
UNDELIVERED | No | Outcome HELD. Delivery to the customer failed. Retried automatically where the country allows it, otherwise through POST /v1/invoices/{id}/deliver. |
Finished (DONE_OK, DONE_REJECTED, DONE_NA)
| Status | Terminal | Meaning and what to do |
|---|---|---|
ACCEPTED | Yes | Cleared or registered by the authority, or issued by Clearvo where no authority call is needed. |
DELIVERED | Yes | Delivered to the customer over a real network (Peppol, or Italy SDI with a real routing code). |
CANCELLED | Yes | Cleared earlier and since cancelled with the authority (DONE_OK). |
REJECTED | Yes | The authority, or a validation rule that is an error for that country, refused the document. errors[] and nextStep explain why. Resend the corrected document to POST /v1/send with the same invoice number (or use Fix & Resubmit in the dashboard). |
DUPLICATE | Yes | The same document was already submitted. No action unless it was unintended. |
NO_MANDATE | Yes | No e-invoicing mandate applies for this country and date. The document is recorded and retained. Nothing to do. |
EXCLUDED | Yes | A skip rule you or Clearvo configured put this document out of scope. It is recorded, not submitted. |
NOT_SUPPORTED | Yes | Dated before the date Clearvo supports this mandate. errorCode is MANDATE_NOT_SUPPORTED. Recorded, never submitted. See below. |
NO_MANDATE, EXCLUDED, NOT_SUPPORTED and DUPLICATE are in the class DONE_NA: nothing was or will be submitted, and they are finished outcomes, not errors.
No obligation and not supported
A document that needs no e-invoicing is a normal, finished result, shown with outcome: NO_OBLIGATION. It is never held and never needs action.
A document is only submitted when its document date is on or after both the date the obligation started for your entity and the date Clearvo began supporting that country's mandate. A document dated earlier than the date Clearvo supports the mandate is NOT_SUPPORTED: it stays visible in your list and is never submitted later, even if support is added afterwards. This stops old documents being sent to an authority by accident when a country goes live. A document dated on or after the support start date for a country that is not yet enabled for your account is not NOT_SUPPORTED: it is held with HELD_AWAITING_AUTHORIZATION with 200 and nothing needed from you. Clearvo sends it automatically once the country is enabled for your account; you do not need to resend it. This applies to live Portugal sends, Greece, Malaysia, Israel, Egypt and Jordan.
How you find out the final status
1. The response to POST /v1/send
The status as it was when the request ended. For countries where the document is issued in the request, that is already final.
2. Poll GET /v1/status
GET /v1/status (and GET /v1/invoices/{id}) reads the stored status. It does not call the authority, so polling cannot cause extra submissions. Call it until terminal is true, using nextPollAfter to space the calls. It works for any document Clearvo has accepted, including one that is still RECEIVED.
3. Webhooks
Webhooks tell you when the status changes, so you do not have to poll. Register an endpoint with POST /v1/webhooks.
invoice.status_changedfires on every status change of a document:RECEIVEDwhen it is stored, a hold, a release, a retry, an authority answer. Choose the statuses you care about with thestatusesfield when you register, for example["NEEDS_INFO", "SETUP_NEEDED"]to be told when you must act, or["ACCEPTED", "REJECTED"]for the final answer. Leavestatusesout to receive every change. It is not included in"*": list it by name inevents. An unknown status, orstatuseswithoutinvoice.status_changedinevents, is a400. The payload is lean:eventId(the same on every delivery retry, so dedupe on it),seq(increases with every status change of one invoice; deliveries can arrive out of order, so order an invoice's events byseqand ignore one lower than the highest you have applied),id,from(empty for the first status),to,statusClass,terminal,nextStep, areasonwith a code, a message, who caused the change (authority,rule,system,merchantorplatform) and afixUrlwhen you can act, andat. FetchGET /v1/invoices/{id}for the full detail. Partner webhooks that cover every organisation take the samestatusesfield.- The existing events keep working, for example
invoice.acceptedandinvoice.rejected, with their existing payloads. New integrations should useinvoice.status_changed. If you subscribe to both, you receive two deliveries for one change, each with its own delivery id. - Reminders are not webhooks, and there is no separate "needs attention" or "released" event: choose the statuses you care about on
invoice.status_changedinstead. Where reminders are enabled they arrive by email and in the dashboard.
Webhooks are retried for up to 10 attempts and signed, see Webhooks & events.
Retries and identity
- Clearvo identifies a document by its own key, built from the document type, country, invoice number and, for purchases, the supplier and date. This is the only thing used to detect a duplicate.
x-idempotency-keyis optional. It never blocks a document. If you reuse a key for a different document, Clearvo processes the new document under its own identity and returns the warningIDEMPOTENCY_KEY_REUSED_ACROSS_DOCUMENTSinwarnings[]. It no longer returns409 IDEMPOTENCY_KEY_REUSED.- A document with no identifying fields (no usable invoice number) is no longer refused. It is stored under your
x-idempotency-keyif you sent one, otherwise under an identity Clearvo creates, and the response carries the warningNO_IDENTITY_NO_DEDUP: duplicates cannot be detected. A blind retry of such a document creates a second record. The errorMISSING_IDENTITY_FIELDno longer exists. - An identical re-send replays the stored result. A re-send of a document that is waiting for you (
NEEDS_INFO,REJECTEDor a hold) with changed content re-runs the stored document. A changed re-send of a document that has already been processed is refused with409 IDEMPOTENT_BODY_MISMATCHand recorded in its history as arefused_resendevent.
Sandbox
The sandbox uses the same API and the same lifecycle as live. Sandbox documents are accepted and stored the same way, and the authority step is simulated, see Sandbox & testing. Sandbox and live data are kept apart: a sandbox key never touches a live document.
Tax calculations are different
A tax calculation is an immediate request and response, with nothing pending afterwards, so it has its own, simpler lifecycle. See Tax Calculations.