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 per submission attempt.

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.

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. The PSB itself uses a retry policy of up to 8 attempts over approximately 35 hours for 5xx errors.

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.

View the full API documentation