3 API3.2
JSON indienen: POST /invoices
Canonieke JSON of een ERP-export.
- In de sandbox
In gewone woorden
Deze aanroep dient een factuur in: als ze elke controle doorstaat, zet de dienst ze in de wachtrij; zo niet, dan noemt het antwoord het veld dat niet slaagde en komt er niets in de wachtrij.
POST /invoices controleert de factuur zoals een proefrun. Als ze slaagt, zet de dienst ze in de wachtrij en antwoordt hij 202 met een ID. Als een controle mislukt, is het antwoord 422 en komt er niets in de wachtrij. De aanroep vereist een sleutel met de scope submit en een Idempotency-Key.
Het verzoek
| Onderdeel | Betekenis |
|---|---|
Header Idempotency-Key | Verplicht, 8 tot 100 tekens. |
invoice_ref | Verplicht. De eigen document-ID van het ERP, maximaal 100 tekens. |
route | Optioneel. Een van de vijf verzendkanalen. Als u het weglaat, kiest de dienst het op basis van de factuur (het land van verkoper en koper, het profiel en de opgeslagen toegangsgegevens van de eindklant). Past geen enkele regel, dan is het antwoord 422, EI-ROUTE-UNDECIDED of EI-ROUTE-PEPPOL-UNKNOWN. |
document | Eén factuur in het canonieke model. Stuur dit of een export met een connector, niet allebei. |
export, connector | Een ERP-export zoals het ERP hem schreef, met connector op business-central of sap-b1. De dienst mapt hem met de live mappingversie van de connector, of met de mapping_version die u noemt (zie mappingversies). Een bevinding in de mapping geeft 422 en noemt het ERP-veld. De export wordt bij de factuur bewaard. |
formats | Optioneel. Noem er hooguit één: het document dat wordt opgebouwd, gecontroleerd en verzonden. |
environment | Optioneel. Als u het meestuurt, moet het overeenkomen met de omgeving van uw sleutel, anders is het antwoord 400. |
client | Optioneel. De eigen sleutel van een eindklant mag het weglaten of de eigen eindklant noemen; elke andere eindklant geeft 403. De limieten van de netwerken worden per eindklant geteld (zie limieten). |
De body is beperkt tot 5 MB. In productie wordt een export alleen gelezen als de connectorinstellingen van de eindklant de eigen verkoper- en betaalgegevens van de eindklant bevatten; zonder die gegevens is het antwoord 422, connector-settings-missing, met wat ontbreekt. De sandbox leest hem met de voorbeeldgegevens van de connector.
Een geaccepteerde factuur
Het voorbeeld is submit-de.json. Location bevat de URL van de factuur, en links verwijst naar de factuur en haar statusberichten. De status is queued: er is niets verzonden.
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"
}Een factuur die een controle niet doorstaat
Dezelfde aanroep met de naam van de verkoper verwijderd, submit-de-missing-seller-name.json. Het antwoord is een problem-document met een lijst errors. Elke fout is een bevinding zoals die in een rapport van een proefrun. De gemarkeerde regels zijn de code en het veld dat moet worden gecorrigeerd.
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
}Idempotentie
- Dezelfde sleutel met dezelfde body geeft opnieuw het eerste antwoord, met dezelfde ID.
- Dezelfde sleutel met een andere body geeft
409. - Ook een
422wordt als antwoord opgeslagen. Stuur een gecorrigeerde factuur met een nieuwe sleutel. - Een opgeslagen antwoord wordt bewaard zolang de gegevens van de eindklant worden bewaard.
- Een tweede verzoek met een sleutel waarvan het eerste verzoek nog loopt, krijgt
409,request-in-progress. Een sleutel waarvan het verzoek nooit is beantwoord omdat de server stopte, komt na 15 minuten weer vrij.
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
}Een document dat u al eerder stuurde
Een document dat identiek is aan een actief document, voor dezelfde eindklant en hetzelfde verzendkanaal, wordt onder een nieuwe sleutel opnieuw geaccepteerd. Het antwoord bevat duplicate_of, de ID van de eerste factuur, en er komt niets nieuws in de wachtrij.
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"
}Antwoorden
| Status | Betekenis |
|---|---|
202 | Geaccepteerd en in de wachtrij gezet, of een duplicaat van een actieve factuur. |
400 | De body is geen geldige JSON, een veld is fout, of de Idempotency-Key ontbreekt of is niet 8 tot 100 tekens lang. |
401 | Geen sleutel, of een onbekende sleutel. |
403 | De sleutel mist de scope submit, of noemt een andere eindklant (forbidden). |
409 | De sleutel werd gebruikt met een andere body (idempotency-conflict), of het eerste verzoek ermee loopt nog (request-in-progress). |
413 | De body is groter dan 5 MB (payload-too-large). |
422 | De factuur heeft een controle niet doorstaan. errors zegt wat er mis is en wie het oplost. |
429 | Te veel aanvragen voor de sleutel. Wacht het aantal seconden in Retry-After. |
503 | Een ander verzoek voor hetzelfde document wordt nog opgeslagen (busy). Er is niets geschreven en de sleutel kan opnieuw worden gebruikt. Probeer het opnieuw na het aantal seconden in Retry-After. |
Waarschuwing
Na een 202 verzendt u nooit opnieuw. Fouten aan de kant van het netwerk die vanzelf kunnen overgaan, proberen we volgens ons schema opnieuw, en een definitieve afwijzing gaat naar de opvolgingslijst.