Idempotency: preventing duplicate submissions

Idempotency in the eConnect PSB API: how to prevent duplicate submissions with the X-EConnect-DocumentId header.

When sending invoices and other documents through an API there is always a risk of duplicate submissions. A network timeout, a restart of your application or an unexpected error can leave you unsure whether a document was actually processed. Without protection you could end up sending the same document again, resulting in duplicate invoices.

The PSB API offers a built-in idempotency mechanism that solves this problem. By including a unique documentId with every upload, the PSB recognises duplicate attempts and prevents the same document from being processed twice.

How it works

The idempotency mechanism revolves around the HTTP header X-EConnect-DocumentId. When sending a document you add this header with a unique value that identifies the document.

POST /api/v1/{partyId}/salesInvoice/send HTTP/1.1
Host: psb.econnect.eu
Authorization: Bearer {token}
Content-Type: application/xml
X-EConnect-DocumentId: 550e8400-e29b-41d4-a716-446655440000

<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
  ...
</Invoice>

The PSB processes the document and stores the documentId. If you send the same request again (for example as a retry after a timeout), the PSB recognises that the documentId already exists and returns a 409 Conflict response instead of processing the document a second time.

HTTP/1.1 409 Conflict

That 409 is not an error in the traditional sense. It is a confirmation that the document was already processed successfully. Your application can safely mark the request as completed.

Requirements for the documentId

The documentId you include in the X-EConnect-DocumentId header must meet a few requirements:

RequirementExplanationAt least 6 charactersShorter values are rejectedNo special charactersCharacters such as @ and _ are not allowedUnique per documentEach document must receive its own documentId

Important: never use the invoice number as documentId. An invoice number can be reused for a credit note or a corrected invoice, leading to conflicts. Use a UUID/GUID instead, generated once per document and reused on retry.

A UUID is the recommended choice. It is guaranteed to be unique and widely supported in all programming languages.

Good:   550e8400-e29b-41d4-a716-446655440000  (UUID)
Good:   DOC2026030800142                       (custom sequence, as long as it is unique)
Bad:    INV-2026-001                           (invoice number, do not use)
Bad:    ab@cd                                  (special characters)
Bad:    abc                                    (too short)
Implementing retry logic

Idempotency becomes most valuable in combination with retry logic. If an API call fails due to a network error or a 5xx server error, you want to retry the request without the risk of duplicate processing.

The recommended approach works as follows:

  1. Generate a unique documentId (UUID) before sending the request.
  2. Send the document with the X-EConnect-DocumentId header.
  3. If you receive a 200 OK: the document has been processed, done.
  4. If you receive a 409 Conflict: the document was already processed in a previous attempt, done.
  5. If you receive a 5xx error or a timeout: wait and retry the request with the same documentId.
  6. If you receive a 4xx error (other than 409): there is a problem with the request itself. Retrying is pointless; the error needs to be fixed.

Send document with X-EConnect-DocumentId

Response?

Processed

Already processed, safe to complete

Wait (exponential backoff)

Fix error, do not retry

Tip: use exponential backoff for retries. Start with a short wait time (for example 1 second) and double it with each subsequent attempt, up to a maximum of, say, 60 seconds.

For document delivery the PSB uses a retry policy of up to 8 attempts over about 72 hours (about 3 days). That is separate from HTTP 5xx retries on your own API calls or webhooks: whether a delivery failure is retried depends on the delivery channel.

Which endpoints support idempotency?

The X-EConnect-DocumentId header is supported on all endpoints that upload documents to the PSB. The most important ones are:

EndpointFunctionPOST /api/v1/{partyId}/salesInvoice/sendSend a sales invoicePOST /api/v1/{partyId}/generic/sendSend a generic document (self-billing, despatch advice)POST /api/v1/{partyId}/purchaseOrder/sendSend an order

For receive endpoints (downloading documents) idempotency does not apply: retrieving a document is inherently idempotent, as it does not modify any data. Note that inbound Peppol traffic does not use X-EConnect-DocumentId for duplicate detection.

Scope and limits

Idempotency via X-EConnect-DocumentId applies to outbound upload endpoints. It does not function as a duplicate mechanism for Validate/Transform endpoints or inbound Peppol reception.

In addition, different routes have different document and attachment limits:

Route / networkLimitNotesPeppol BIS (document + attachments)100 MBNetwork limit for exchanges over PeppolSimpler Invoicing UBL 2.010 MBLimit on the SI-UBL 2.0 routePOST /salesInvoice/send request24 MBWebserver limit per request including overheadIDR upload15 MBLimit for IDR intake

Embedded attachments are supported as inline base64 only (no separate attachment upload endpoint).

Summary

Idempotency is a small mechanism with a big impact. By consistently including an X-EConnect-DocumentId with every document upload, you protect yourself against duplicate submissions. Combined with retry logic and exponential backoff, you build a robust integration that withstands network issues and temporary server errors.

In short Include the X-EConnect-DocumentId header with a unique UUID for every document upload. On a retry the PSB returns 409 Conflict if the document has already been processed. Never use the invoice number as documentId.

Frequently asked questions
Why must I not use the invoice number as documentId?

An invoice number can reappear on a credit note or a corrected invoice. Use a UUID (v4) per document and reuse it on retry, so the 409 check is tied to the document and not to the invoice number.

What happens if I do not send an X-EConnect-DocumentId?

The PSB then generates a documentId itself. The downside is that after a network error you cannot tell whether the document was already processed. By sending your own documentId you can retry safely: a duplicate upload returns a 409 Conflict.

Which endpoints does idempotency apply to?

Idempotency applies to all write endpoints that upload documents, such as sending invoices, orders and generic documents. It does not apply to download endpoints (retrieving documents), because retrieval does not change data.

View the full API documentation