Skip to main content

Overview

This page is the reference for error handling. It shows the error body formats, the status codes of each endpoint, the frequent validation rules and the correct retry behaviour.

Error body formats

The API uses three formats. Read the HTTP status code first, then parse the body.

Error with a text message

Most errors return a JSON object with one field, detail, that contains a string.
404 Not Found

Request validation error (422)

When a request does not match the schema of the endpoint (a missing field, a wrong type, a wrong date format), detail is an array. Each item identifies one field.
422 Unprocessable Entity
array
The path to the field. The first item is the part of the request (body, query or path).
string
The description of the problem.
string
The machine-readable error type, for example missing.
Some endpoints also return 422 with a text message in detail, for example "Invalid file type". Your code must accept a string and an array in detail.

Validation result

The validation endpoints (POST /api/validate/json, POST /api/validate/ubl and POST /api/documents/{document_id}/validate) return a success status when the document breaks a rule: 201 Created for the two /api/validate/ endpoints and 200 OK for the validation of a stored document. The result is in the body: is_valid is false and issues contains the rule failures.
201 Created
string
required
The text of the rule that failed.
string
required
The issue type, for example error.
string
The identifier of the rule, for example BR-CO-15 or PEPPOL-EN16931-R120. A failure of the XML schema has the value xsd-validation.
string
The severity. An issue with the value fatal makes the document invalid.
string
The position in the generated UBL where the rule failed.
string
The test expression of the rule.
string
required
The rule set that found the issue.

HTTP status codes

The same status code can have different causes on different endpoints. A failure to derive the Peppol IDs gives 406 when you create a document and 400 when you send it. A Peppol ID that is not owned by your company gives 406 when you create a document and 409 when you send it.

Create document errors (406)

POST /api/documents/ returns 406 Not Acceptable for four causes. No document is created.
The API derives the Peppol IDs from the tax IDs and the company IDs of the vendor and the customer. Make sure that vendor_tax_id and customer_tax_id (or the company IDs) are present and correct.
The Peppol ID that the API derived from the vendor is not registered for the company of the API key. The comparison ignores upper and lower case and spaces at the start and the end. Use the vendor identifiers of your company. Use GET /api/me/ to see the Peppol IDs of your company.For a self-billing document, the API examines the receiver, and the message starts with Derived receiver. See Ownership rule.
The API calculates the totals from the lines and compares them with your values. The message can also start with Total tax mismatch, Total discount mismatch, Invoice total mismatch or Amount due. See Invoice totals and calculations.
detail contains the messages of the rules that failed, without the rule identifiers. Send the same payload to POST /api/validate/json to get the full list of issues with rule_id. Then see Frequent validation rules.
Validation is not a separate mandatory call. POST /api/documents/ rejects a payload that does not pass the same rules. Use POST /api/validate/json while you develop, because it returns all rule failures and the generated UBL.

Send errors

POST /api/documents/{document_id}/send does these checks in sequence.

Peppol ID routing

When you send a document, the API finds the sender and receiver Peppol IDs in this order:
  1. The query parameters of the send request.
  2. The Peppol IDs that the API stored with the UBL of the document.
  3. The identifiers in the document: vendor_tax_id or vendor_company_id for the sender, and customer_peppol_id, customer_tax_id or customer_company_id for the receiver.
For a Belgian party, the API derives scheme 0208 and the enterprise number: the tax ID BE1018265814 gives the Peppol ID 0208:1018265814. For other countries, the derived scheme can be different from the scheme that the receiver registered. Thus the best practice is to give all four query parameters:
cURL
string
Scheme of the sender Peppol ID. Example: 0208.
string
Identifier of the sender, without the scheme. Example: 1018265814.
string
Scheme of the receiver Peppol ID. Example: 0208.
string
Identifier of the receiver, without the scheme. Example: 0848934496.
The API returns 400 if it cannot find a complete sender and receiver Peppol ID. It returns 409 if the sender Peppol ID is not one of the peppol_ids of your company.
Before you send, make sure that the receiver is registered on the Peppol network with the Peppol ID that you use. See Look up Peppol participants.

Frequent validation rules

For the full procedure, see Validation during development.

A document is in state FAILED

After an accepted send call, the document is in state TRANSIT. The transmission occurs in the background. If all transmission attempts fail, the state becomes FAILED and the document.sent.failed webhook event is sent. See Retry behaviour for the number of attempts.
1

Read the timeline

GET /api/documents/{document_id}/timeline returns the events of the document. Each transmission attempt that failed is an event with event_type send_failed. The details object shows the sender and receiver Peppol IDs that the API used.
cURL
200 OK
The values in this example are illustrative.
2

Examine the receiver

Make sure that the receiver Peppol ID in details is correct. Then call GET /api/validate/peppol-id?peppol_id=0208:0848934496 to see if the receiver is registered on the Peppol network. See Look up Peppol participants.
3

Send again

Call POST /api/documents/{document_id}/send again. The API accepts a send call for a document in state FAILED. If the Peppol IDs were wrong, give the correct IDs as query parameters. See Send a failed document again.
The timeline does not contain the technical reason of a failed transmission. If the receiver is registered and the document fails again, contact support@e-invoice.be with the document ID.
For all states and transitions, see Document lifecycle and delivery tracking.

Retries and idempotency

Which errors to retry

Rate limits

The rate limit applies to each API key and only to these endpoints:
  • POST /api/documents/
  • POST /api/documents/ubl
  • POST /api/validate/json
  • POST /api/validate/ubl
When you exceed the limit, the API returns 429 with a Retry-After header that contains a number of seconds.
429 Too Many Requests
Do not write a fixed limit into your code. Read Retry-After and wait.

No idempotency key

The API has no idempotency key. If you repeat POST /api/documents/, the API creates a second draft with the same invoice_id. A send call is different: a second send call for a document in state TRANSIT or SENT returns 405 and does not transmit the document again. If a create call ends without a response (a timeout or a network error), find out if the document exists before you create it again. Search the drafts for your invoice number. This list contains documents in the states DRAFT, TRANSIT and FAILED. For documents that are sent, use GET /api/outbox/ with the same search parameter. Find duplicates before a retry gives the full procedure.
200 OK
The response is shortened. The search parameter finds a part of the invoice number, the vendor name, the customer name or the note, thus compare invoice_id for an exact match.

Troubleshooting

The endpoint expects a multipart/form-data upload with a part that has the name file. You sent the XML or the PDF as the raw request body. With cURL, use -F "file=@invoice.xml" and do not set the Content-Type header manually. See Send UBL documents and Create documents from PDF.
Authentication required means that the request has no Authorization: Bearer header. Invalid authentication means that the API key is not known or is deleted. Make sure that the header has the format Authorization: Bearer <key> and that the key is the key of the company that you want to use. See Authentication.
The create and validate endpoints have a rate limit for each API key. Read the Retry-After header, wait, then continue. Send the requests in sequence, not in parallel.
Read the state with GET /api/documents/{document_id}.
  • DRAFT: the document was not sent. Call the send endpoint.
  • TRANSIT: the transmission is in progress.
  • FAILED: see A document is in state FAILED.
  • SENT: the access point of the receiver accepted the document. Ask the customer to look in the software that is connected to their Peppol ID. Read the timeline to see which receiver Peppol ID was used.
If you use a sandbox company, the document is not sent on the Peppol network. See Test mode and sandbox companies.
A sandbox company sends each document as an email with the UBL file to the contact email address of your company, not to the customer. Make sure that the contact email address is set, and look in the spam folder. If the company has no contact email address, the send call returns 400 with Tenant is in test mode but no company email is set. See Test mode and sandbox companies.
The signature is calculated on the full event as JSON with sorted keys, not on the data field only. Make sure that you use the secret of the correct webhook and that you serialise the payload as the Webhooks guide shows.
A sandbox company does not receive documents from the Peppol network, and a document that you send to your own company does not go into the inbox. Use Simulate inbound to put a document into the inbox. See Receive documents.

Next Steps

Validation during development

Find all rule failures of a payload before you create a document.

Document lifecycle and delivery tracking

Learn the states of a document and the transitions between them.

Webhooks

Receive an event when a document is sent or fails.

Invoice totals and calculations

Calculate totals that pass the validation rules.