3 API3.2
JSON übermitteln: POST /invoices
Kanonisches JSON oder ein ERP-Export.
- In der Sandbox
In einfachen Worten
Dieser Aufruf übermittelt eine Rechnung: Besteht sie jede Prüfung, reiht der Service sie in die Warteschlange ein, und wenn nicht, nennt die Antwort das Feld, bei dem die Prüfung fehlgeschlagen ist, und nichts wird eingereiht.
POST /invoices prüft die Rechnung wie ein Probelauf. Besteht sie, reiht der Service sie in die Warteschlange ein und antwortet mit 202 und einer ID. Schlägt eine Prüfung fehl, ist die Antwort 422, und nichts wird eingereiht. Der Aufruf braucht einen Schlüssel mit dem Scope submit und einen Idempotency-Key.
Die Anfrage
| Teil | Bedeutung |
|---|---|
Header Idempotency-Key | Pflicht, 8 bis 100 Zeichen. |
invoice_ref | Pflicht. Die eigene Beleg-ID des ERP, bis zu 100 Zeichen. |
route | Optional. Einer der fünf Übermittlungswege. Fehlt er, wählt der Service ihn anhand der Rechnung (Länder von Verkäufer und Käufer, das Profil und die gespeicherten Zugangsdaten des Kunden). Passt keine Regel, lautet die Antwort 422, EI-ROUTE-UNDECIDED oder EI-ROUTE-PEPPOL-UNKNOWN. |
document | Eine Rechnung im kanonischen Modell. Senden Sie dieses Feld oder einen export mit einem connector, nicht beides. |
export, connector | Ein ERP-Export, so wie das ERP ihn geschrieben hat, mit connector auf business-central oder sap-b1. Der Service mappt ihn mit der Live-Mapping-Version des Connectors oder mit der von Ihnen genannten mapping_version (siehe Mapping-Versionen). Ein Befund im Mapping führt zu 422 und nennt das ERP-Feld. Der Export wird mit der Rechnung aufbewahrt. |
formats | Optional. Nennen Sie höchstens eines: das Dokument, das erstellt, geprüft und gesendet wird. |
environment | Optional. Wenn Sie es senden, muss es der Umgebung Ihres Schlüssels entsprechen, sonst ist die Antwort 400. |
client | Optional. Ein Kundenschlüssel darf es weglassen oder seinen eigenen Kunden nennen; jeder andere Kunde führt zu 403. Die Obergrenzen der Netze werden je Kunde gezählt (siehe Limits). |
Der Body ist auf 5 MB begrenzt. In der Produktion wird ein Export nur gelesen, wenn die Connector-Einstellungen des Kunden dessen eigene Verkäufer- und Zahlungsangaben enthalten; ohne sie lautet die Antwort 422, connector-settings-missing, mit dem Hinweis, was fehlt. Die Sandbox liest ihn mit den Beispielangaben des Connectors.
Eine angenommene Rechnung
Das Beispiel ist submit-de.json. Location enthält die URL der Rechnung, und links zeigt auf die Rechnung und ihre Ereignisse. Der Zustand ist queued: Es wurde nichts gesendet.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-0001" \
--data-binary @submit-de.jsonimport 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"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "order-2026-0001")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("submit-de.json")))
.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', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
'Idempotency-Key': 'order-2026-0001',
},
body: await readFile('submit-de.json'),
});
console.log(response.status);
console.log(await response.text());{
"links": {
"self": "/invoices/inv_936a93e38de84e7b0a1d7681",
"events": "/invoices/inv_936a93e38de84e7b0a1d7681/events"
},
"id": "inv_936a93e38de84e7b0a1d7681",
"state": "queued"
}Eine Rechnung, die eine Prüfung nicht besteht
Derselbe Aufruf ohne den Namen des Verkäufers, submit-de-missing-seller-name.json. Die Antwort ist ein Problem-Dokument mit einer Liste errors. Jeder Fehler ist ein Befund wie in einem Bericht des Probelaufs. Die hervorgehobenen Zeilen sind der Code und das zu behebende Feld.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-0002" \
--data-binary @submit-de-missing-seller-name.jsonimport 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"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "order-2026-0002")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("submit-de-missing-seller-name.json")))
.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', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
'Idempotency-Key': 'order-2026-0002',
},
body: await readFile('submit-de-missing-seller-name.json'),
});
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-SCHEMA",
"field": "seller.name",
"related": [
{
"code": "Art.226(5)",
"source": "pre-check"
}
],
"fix_hint": "Read the JSON path in the error and correct the client mapping.",
"who_fixes": "us",
"source": "schema",
"message": "We could not read this invoice from your export. We are correcting our mapping; if a field is missing in the ERP we will tell you which one."
},
{
"code": "Art.226(5)",
"field": "seller.name",
"related": [
{
"code": "EI-SCHEMA",
"source": "schema"
}
],
"fix_hint": "Complete the party's name and address in the master data.",
"who_fixes": "erp",
"source": "pre-check",
"message": "A company name or street address is missing. Complete the company or customer record in the ERP."
}
],
"status": 422
}Idempotenz
- Derselbe Schlüssel mit demselben Body liefert die erste Antwort erneut, mit derselben ID.
- Derselbe Schlüssel mit einem anderen Body ergibt
409. - Auch eine Antwort mit
422wird gespeichert. Senden Sie eine korrigierte Rechnung mit einem neuen Schlüssel. - Eine gespeicherte Antwort wird so lange aufbewahrt, wie die Daten des Kunden aufbewahrt werden.
- Eine zweite Anfrage mit einem Schlüssel, dessen erste Anfrage noch läuft, erhält
409,request-in-progress. Ein Schlüssel, dessen Anfrage nie beantwortet wurde, weil der Server angehalten wurde, wird nach 15 Minuten freigegeben.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-0001" \
--data-binary @submit-de.jsonimport 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"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "order-2026-0001")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("submit-de.json")))
.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', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
'Idempotency-Key': 'order-2026-0001',
},
body: await readFile('submit-de.json'),
});
console.log(response.status);
console.log(await response.text());{
"links": {
"self": "/invoices/inv_936a93e38de84e7b0a1d7681",
"events": "/invoices/inv_936a93e38de84e7b0a1d7681/events"
},
"id": "inv_936a93e38de84e7b0a1d7681",
"state": "queued"
}curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-0001" \
--data-binary @submit-de-changed.jsonimport 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"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "order-2026-0001")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("submit-de-changed.json")))
.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', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
'Idempotency-Key': 'order-2026-0001',
},
body: await readFile('submit-de-changed.json'),
});
console.log(response.status);
console.log(await response.text());{
"type": "https://eurinvoice.com/problems/idempotency-conflict",
"title": "This Idempotency-Key was already used with a different body",
"status": 409
}Ein Dokument, das Sie schon gesendet haben
Ein Dokument, das für denselben Kunden und Übermittlungsweg mit einem aktiven Dokument identisch ist, wird unter einem neuen Schlüssel erneut angenommen. Die Antwort enthält duplicate_of, die ID der ersten Rechnung, und nichts Neues wird eingereiht.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/invoices" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-0003" \
--data-binary @submit-de.jsonimport 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"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "order-2026-0003")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("submit-de.json")))
.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', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
'Idempotency-Key': 'order-2026-0003',
},
body: await readFile('submit-de.json'),
});
console.log(response.status);
console.log(await response.text());{
"links": {
"self": "/invoices/inv_936a93e38de84e7b0a1d7681",
"events": "/invoices/inv_936a93e38de84e7b0a1d7681/events"
},
"id": "inv_936a93e38de84e7b0a1d7681",
"state": "queued",
"duplicate_of": "inv_936a93e38de84e7b0a1d7681"
}Antworten
| Status | Bedeutung |
|---|---|
202 | Angenommen und eingereiht, oder ein Duplikat einer aktiven Rechnung. |
400 | Der Body ist kein gültiges JSON, ein Feld ist falsch, oder der Idempotency-Key fehlt oder hat nicht 8 bis 100 Zeichen. |
401 | Kein Schlüssel oder ein unbekannter Schlüssel. |
403 | Dem Schlüssel fehlt der Scope submit, oder er nennt einen anderen Kunden (forbidden). |
409 | Der Schlüssel wurde mit einem anderen Body verwendet (idempotency-conflict), oder seine erste Anfrage läuft noch (request-in-progress). |
413 | Der Body ist größer als 5 MB (payload-too-large). |
422 | Die Rechnung hat eine Prüfung nicht bestanden. errors sagt, was falsch ist und wer es behebt. |
429 | Zu viele Anfragen für den Schlüssel. Warten Sie Retry-After Sekunden. |
503 | Eine andere Anfrage für dasselbe Dokument wird noch gespeichert (busy). Nichts wurde geschrieben, und der Schlüssel kann erneut verwendet werden. Versuchen Sie es nach Retry-After Sekunden erneut. |
Warnung
Nach einem 202 senden Sie nie erneut. Bei Fehlern auf Seiten des Netzes, die vorübergehend sein können, versuchen wir es nach unserem Zeitplan erneut, und eine endgültige Ablehnung kommt auf die Betreuungsliste.