Statuses
Status events and queue states.
- In the sandboxevent shape
- Not in the sandbox yetrail statuses
In plain words
Every invoice has a state, such as queued or rejected, and a history of events that says what happened to it. This is how a client or partner finds out whether an invoice went through. The hosted sandbox holds no rail credential yet, so the events that come from a country connection appear only when a route is connected.
An invoice has two kinds of status. Status events say what happened to it. The queue state says where it is now.
Queue state
GET /invoices/{id} returns the state.
| State | Meaning |
|---|---|
received | The invoice was accepted at intake. |
validated | The invoice passed every check. |
validation_failed | The official rules refused the document. It goes to the care list. |
source_error | The ERP data could not be read. |
queued | Accepted and waiting. |
submitting | A send was tried and its answer was lost, so the route may hold the invoice. The worker settles it as submitted or dead_letter. |
submitted | The route has the invoice. |
ready | Germany's final state. The XRechnung or ZUGFeRD is validated and stored for the partner to deliver. Nothing was sent. |
accepted | The route accepted it. |
delivered | The invoice reached the buyer's side. |
rejected | The route refused it for good. It goes to the care list. |
dead_letter | Transient failures used up their retries. It goes to the care list. |
cancelled | Stopped before submission (see cancel). |
queued and submitting are internal steps between validated and submitted, and no status event reports them.
Status events
All routes use the same event shape. GET /invoices/{id}/events returns them, and a webhook delivers the same body (see webhooks).
| Status | Meaning |
|---|---|
received | The invoice was accepted at intake. |
validated | The invoice passed every check. |
source_error | The ERP data could not be read. Carries errors. |
validation_failed | A check failed. Carries errors. |
submitted | The route has the invoice. |
accepted | The route accepted it. Carries legal_id, the route's own reference. |
rejected | The route refused it. Carries errors. |
delivered | The invoice reached the buyer's side. |
buyer_status | The buyer answered. buyer_status is one of acknowledged, in_process, under_query, conditionally_accepted, rejected, approved, disputed or paid. |
Fields on every event: event_id, sequence, occurred_at, invoice_ref, invoice_number, country_route, environment, status and document_sha256. Some events add legal_id, buyer_status, errors (the same items as a dry-run finding) and route, which holds the route's submission_id and its native status in raw.
Tip
Order events by sequence, not by time.
The schema enforces three rules: accepted carries legal_id, the three failure statuses carry errors, and buyer_status carries a buyer_status.
Which events occur
In the sandboxsandboxIntake writes received, with sequence 1. The service then runs the route's validators and writes validated, or validation_failed when a check fails. After that each move of the invoice writes one event: submitted, accepted, delivered or rejected. For Germany nothing follows validated, because the invoice ends at ready. See the recorded events for an example.
On the hosted sandbox no rail credential is stored yet. A route that needs one reaches submitted without anything being sent, and Germany ends at ready. In production a route with no credential retries and then dead-letters the invoice.
The events that come from a rail (accepted, delivered and buyer_status) need a connected route. The mapping from each rail's own statuses is built and tested, and has run against the test systems of KSeF, a Peppol access point and a French platform. It is not connected on the hosted sandbox yet.
Final status by route
Not in the sandbox yetrails| Route | Final status | What it carries | Failure |
|---|---|---|---|
PL-KSEF | accepted | The KSeF number as legal_id. | rejected with the KSeF code, for example KSEF-440 for a duplicate. |
RO-EFACTURA | accepted when ANAF's state is ok | The ANAF upload index. | rejected when the state is nok, with ANAF's error code. The upload follows ANAF's documentation and has not been tried; only its validators have run. |
PEPPOL | delivered | The access point's document id. | rejected when the access point refuses it or reports a failure. |
FR-PA | delivered, then buyer_status events | The platform's invoice id. The French code, its label and any note travel in route.raw. | rejected when the platform refuses it, for example fr:213. |
DE-XRECHNUNG | No authority answers. The built and checked file is the result. | Delivery follows the channel, Peppol or email. | The 422 at intake. No rail answer follows. |
- Transient rail errors never become events. They retry (see limits).
- A French status code the service does not map gives no event and raises an alert, so it is not dropped.
- A buyer a rail cannot reach. For Peppol, the service checks the scheme code of the buyer's id, not whether the buyer is registered. An access point may report a buyer that is not on Peppol as not reachable, and the mapping turns that into
rejectedwithEI-PEPPOL-NO-ROUTE. That follows the access point's documentation and has not been confirmed on a live access point. A French buyer without a platform address should fail, not deliver; that has not been confirmed either.