Docs

3 API3.3

3.3

Submit XML: POST /invoices/xml

UBL, CII or FA(3) XML.

  • In the sandbox

In plain words

This call submits an invoice that already exists as a finished XML file. It gets a safety check and the route's own validators, and goes to the queue if it passes.

POST /invoices/xml takes a finished UBL, CII or FA(3) file. No mapping happens. The service checks the file for safety and type, runs the official validators for the route, then queues it and sends it unchanged. For FA(3) the checks are the schema plus KSeF's file and date rules.

Note

A 202 means the file passed the safety check and is queued. To check a file before you send it, send the invoice as JSON to POST /validate.

The request

PartMeaning
route query parameterRequired. One of the five routes.
invoice_ref query parameterRequired. The ERP's own document id, up to 100 characters.
client query parameterOptional. A client's own key may leave it out or name its own client.
Idempotency-Key headerRequired, 8 to 100 characters.
Content-Type headerapplication/xml or text/xml. application/pdf is stored and queued the same way.

Which file each route takes:

RouteAccepts
DE-XRECHNUNGUBL, CII
FR-PAUBL, CII
PEPPOLUBL
RO-EFACTURAUBL
PL-KSEFFA(3)

An accepted file

The sample is fa3-pl-ksef.xml, a Polish FA(3) file with invented parties. The state is queued.

curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PL-KSEF&invoice_ref=INV-2026-0042" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/xml" \
  -H "Idempotency-Key: order-2026-0042" \
  --data-binary @fa3-pl-ksef.xml
Response202 Accepted
{
  "links": {
    "self": "/invoices/inv_d249e33382ce2911876b7295",
    "events": "/invoices/inv_d249e33382ce2911876b7295/events"
  },
  "id": "inv_d249e33382ce2911876b7295",
  "state": "queued"
}
Recorded on 7 Oct 2026.

A file sent twice

The same file sent again for the same client and route is the invoice already held. The answer carries duplicate_of, the id of the first invoice, and nothing new is sent. A submission that ended rejected, validation_failed or cancelled does not count, so the file can be sent again.

Refused files

XML that is well formed but not an invoice gets 422 with EI-XML-TYPE.

curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0051" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/xml" \
  -H "Idempotency-Key: order-2026-0051" \
  --data-binary @not-an-invoice.xml
Response422 Unprocessable Content
{
  "type": "https://eurinvoice.com/problems/validation-failed",
  "title": "The invoice did not pass the checks",
  "errors": [
    {
      "code": "EI-XML-TYPE",
      "fix_hint": "Send the invoice itself, in the format agreed for the route.",
      "who_fixes": "erp",
      "source": "XML-safety",
      "message": "The file is not an invoice in a format this route accepts. Please send the invoice in the agreed format."
    }
  ],
  "status": 422
}
Recorded on 7 Oct 2026. The file is [not-an-invoice.xml](/samples/not-an-invoice.xml).

A file with a DOCTYPE gets 422 with EI-XML-DTD, before any validator reads it. A file that is not well formed gets EI-XML-SYNTAX.

curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0052" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/xml" \
  -H "Idempotency-Key: order-2026-0052" \
  --data-binary @with-doctype.xml
Response422 Unprocessable Content
{
  "type": "https://eurinvoice.com/problems/validation-failed",
  "title": "The invoice did not pass the checks",
  "errors": [
    {
      "code": "EI-XML-DTD",
      "fix_hint": "Export the invoice without the DOCTYPE line. If the ERP adds one on purpose, raise it with the ERP vendor: no e-invoicing format uses it.",
      "who_fixes": "erp",
      "source": "XML-safety",
      "message": "The invoice file contains a DOCTYPE declaration, which e-invoices never use, so we refused it for security before reading it. Export it again without the DOCTYPE line."
    }
  ],
  "status": 422
}
Recorded on 7 Oct 2026. The file is [with-doctype.xml](/samples/with-doctype.xml).

A content type that is not XML or PDF gets 415.

curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0053" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: text/plain" \
  -H "Idempotency-Key: order-2026-0053" \
  --data-binary @hello.txt
Response415 Unsupported Media Type
{
  "type": "https://eurinvoice.com/problems/unsupported-media",
  "title": "Not UBL, CII or FA(3)",
  "status": 415
}
Recorded on 7 Oct 2026.

A missing or short Idempotency-Key gets 400.

curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0054" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/xml" \
  --data-binary @ubl-peppol.xml
Response400 Bad Request
{
  "detail": "Idempotency-Key must be between 8 and 100 characters.",
  "type": "https://eurinvoice.com/problems/bad-request",
  "title": "The request could not be read",
  "status": 400
}
Recorded on 7 Oct 2026.

Answers

StatusMeaning
202Accepted and queued. Location holds the invoice URL.
400A query parameter or the Idempotency-Key is missing or wrong.
401No key, or an unknown key.
403The key lacks the submit scope, or names another client (forbidden).
409The key was used with a different body (idempotency-conflict), or its first request is still running (request-in-progress).
413The body is over 5 MB (payload-too-large).
415The content type is not XML or PDF (unsupported-media).
422A refused file: EI-XML-DTD, EI-XML-SYNTAX or EI-XML-TYPE.
429Too many requests for the key. Wait for Retry-After seconds.
503Another request for the same document is still being stored (busy). Retry after Retry-After seconds.

On this page