3 API3.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
| Part | Meaning |
|---|---|
route query parameter | Required. One of the five routes. |
invoice_ref query parameter | Required. The ERP's own document id, up to 100 characters. |
client query parameter | Optional. A client's own key may leave it out or name its own client. |
Idempotency-Key header | Required, 8 to 100 characters. |
Content-Type header | application/xml or text/xml. application/pdf is stored and queued the same way. |
Which file each route takes:
| Route | Accepts |
|---|---|
DE-XRECHNUNG | UBL, CII |
FR-PA | UBL, CII |
PEPPOL | UBL |
RO-EFACTURA | UBL |
PL-KSEF | FA(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.xmlimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PL-KSEF&invoice_ref=INV-2026-0042"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/xml")
.header("Idempotency-Key", "order-2026-0042")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("fa3-pl-ksef.xml")))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}import { readFile } from 'node:fs/promises';
const response = await fetch('https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PL-KSEF&invoice_ref=INV-2026-0042', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/xml',
'Idempotency-Key': 'order-2026-0042',
},
body: await readFile('fa3-pl-ksef.xml'),
});
console.log(response.status);
console.log(await response.text());{
"links": {
"self": "/invoices/inv_d249e33382ce2911876b7295",
"events": "/invoices/inv_d249e33382ce2911876b7295/events"
},
"id": "inv_d249e33382ce2911876b7295",
"state": "queued"
}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.xmlimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0051"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/xml")
.header("Idempotency-Key", "order-2026-0051")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("not-an-invoice.xml")))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}import { readFile } from 'node:fs/promises';
const response = await fetch('https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0051', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/xml',
'Idempotency-Key': 'order-2026-0051',
},
body: await readFile('not-an-invoice.xml'),
});
console.log(response.status);
console.log(await response.text());{
"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
}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.xmlimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0052"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/xml")
.header("Idempotency-Key", "order-2026-0052")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("with-doctype.xml")))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}import { readFile } from 'node:fs/promises';
const response = await fetch('https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0052', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/xml',
'Idempotency-Key': 'order-2026-0052',
},
body: await readFile('with-doctype.xml'),
});
console.log(response.status);
console.log(await response.text());{
"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
}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.txtimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0053"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "text/plain")
.header("Idempotency-Key", "order-2026-0053")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("hello.txt")))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}import { readFile } from 'node:fs/promises';
const response = await fetch('https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0053', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'text/plain',
'Idempotency-Key': 'order-2026-0053',
},
body: await readFile('hello.txt'),
});
console.log(response.status);
console.log(await response.text());{
"type": "https://eurinvoice.com/problems/unsupported-media",
"title": "Not UBL, CII or FA(3)",
"status": 415
}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.xmlimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0054"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/xml")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("ubl-peppol.xml")))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}import { readFile } from 'node:fs/promises';
const response = await fetch('https://api-sandbox-eu.eurinvoice.com/invoices/xml?route=PEPPOL&invoice_ref=INV-2026-0054', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/xml',
},
body: await readFile('ubl-peppol.xml'),
});
console.log(response.status);
console.log(await response.text());{
"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
}Answers
| Status | Meaning |
|---|---|
202 | Accepted and queued. Location holds the invoice URL. |
400 | A query parameter or the Idempotency-Key is missing or wrong. |
401 | No key, or an unknown key. |
403 | The key lacks the submit scope, or names another client (forbidden). |
409 | The key was used with a different body (idempotency-conflict), or its first request is still running (request-in-progress). |
413 | The body is over 5 MB (payload-too-large). |
415 | The content type is not XML or PDF (unsupported-media). |
422 | A refused file: EI-XML-DTD, EI-XML-SYNTAX or EI-XML-TYPE. |
429 | Too many requests for the key. Wait for Retry-After seconds. |
503 | Another request for the same document is still being stored (busy). Retry after Retry-After seconds. |