3 API3.1
Przebieg próbny: POST /validate
Wykonuje te same kontrole co przesłanie. Niczego nie zapisuje ani nie wysyła.
- W sandboxie
Prostymi słowami
Przebieg próbny sprawdza fakturę tak samo jak prawdziwe przesłanie, ale niczego nie wysyła, więc partner może znaleźć każdy problem, zanim faktura klienta trafi gdziekolwiek.
POST /validate wykonuje te same kontrole co przesłanie i zwraca raport. Niczego nie umieszcza w kolejce i niczego nie wysyła. Wywołanie wymaga klucza z zakresem submit. Treść żądania to JSON, maksymalnie 5 MB.
Wskazówka
Od tego warto zacząć mapowanie nowego klienta.
Żądanie
| Pole | Znaczenie |
|---|---|
invoice_ref | Wymagane. Własny identyfikator dokumentu w ERP, maksymalnie 100 znaków. Powtarzany w każdym zdarzeniu statusu. |
route | Wymagane. DE-XRECHNUNG, PEPPOL, FR-PA, PL-KSEF lub RO-EFACTURA. |
document | Jedna faktura w modelu kanonicznym. Należy wysłać to pole albo export, nie oba. |
export, connector | Eksport z ERP w takiej postaci, w jakiej zapisało go ERP, z connector ustawionym na business-central lub sap-b1. Należy wysłać to pole albo document, nie oba. Dla kanału innego niż niemiecki raport zaczyna się od warstwy mapping. mapping_version wybiera wersję inną niż aktywna (zob. wersje mapowania). |
formats | Dokumenty do zbudowania tam, gdzie kanał pozwala na wybór. Niemcy: dowolne z xrechnung-ubl (domyślnie), xrechnung-cii i zugferd; KoSIT uruchamia się raz dla każdego formatu, a dla PDF dodatkowo Mustang i veraPDF. Francja: ubl, cii lub facturx. |
environment | Opcjonalne. Musi odpowiadać środowisku klucza. |
erp_totals | Sumy obliczone przez Państwa ERP: payable_amount, currency i opcjonalnie tax_amount, jako ciągi znaków. Jeśli różnią się od sum, które usługa oblicza z pozycji, raport zawiera ustalenie EI-TOTALS-MISMATCH dla erp_totals.payable_amount. |
Pełna lista pól jest w dokumentacji referencyjnej.
Faktura, która przechodzi kontrole
Przykładowe żądanie to validate-de-ok.json, fikcyjna faktura niemiecka. Raport zawiera valid: true, jeden dokument z jego SHA-256 i cztery warstwy, które przeszły kontrolę.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/validate" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
--data-binary @validate-de-ok.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/validate"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("validate-de-ok.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/validate', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
},
body: await readFile('validate-de-ok.json'),
});
console.log(response.status);
console.log(await response.text());{
"valid": true,
"route": "DE-XRECHNUNG",
"documents": [
{
"sha256": "e21ab9d5097022bea30bfa9f9fe0a4c7ca9afdbd672b0ce2f9150461db773625",
"kind": "xrechnung-ubl",
"content_base64": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgi... (7,092 characters, shortened for these docs)"
}
],
"layers": [
{
"findings": [],
"passed": true,
"layer": "schema"
},
{
"findings": [],
"passed": true,
"layer": "mapping"
},
{
"findings": [],
"passed": true,
"layer": "pre-check"
},
{
"findings": [],
"passed": true,
"layer": "kosit"
}
]
}Faktura, która nie przechodzi kontroli
Ta sama faktura bez nazwy sprzedawcy, validate-de-missing-seller-name.json. Przebieg próbny nadal zwraca 200. valid ma wartość false, a każde ustalenie wskazuje pole i to, kto ma je poprawić. Najważniejsze są dwa wyróżnione wiersze: code z katalogu i field w danych klienta.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/validate" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
--data-binary @validate-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/validate"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("validate-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/validate', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
},
body: await readFile('validate-de-missing-seller-name.json'),
});
console.log(response.status);
console.log(await response.text());{
"valid": false,
"route": "DE-XRECHNUNG",
"layers": [
{
"findings": [
{
"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."
}
],
"passed": false,
"layer": "schema"
},
{
"findings": [],
"passed": true,
"layer": "mapping"
},
{
"findings": [
{
"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."
}
],
"passed": false,
"layer": "pre-check"
}
]
}Jak czytać raport
validma wartośćtruetylko wtedy, gdy przeszły wszystkie warstwy.layerssą wykonywane w kolejności:schema,mapping,pre-check, a potem walidatory właściwe dla kanału, nazwane według tego, co zostało uruchomione (na przykładKoSIT-XRechnung-3.0.2).- Każde ustalenie ma
codez katalogu,field,who_fixes(usluberp),fix_hint,messagei warstwęsource. Wszystkie kody wymienia strona Błędy i katalog. documentswymienia to, co zostało utworzone, z SHA-256 oraz, dla pliku o rozmiarze do 2 MiB, jego bajty wcontent_base64. Pole występuje, gdy faktura jest poprawna.
Inne odpowiedzi
| Status | Znaczenie |
|---|---|
200 | Raport, niezależnie od tego, czy faktura jest poprawna. |
400 | Nie można odczytać żądania: to nie JSON, pole jest błędne albo występują jednocześnie document i export. |
401 | Brak klucza lub nieznany klucz. |
403 | Klucz nie ma zakresu submit. |
413 | Treść przekracza 5 MB (payload-too-large). |
422 | Liczba poza limitami, na przykład dłuższa niż 40 znaków (EI-SCHEMA, ze wskazaniem pola). Każde inne ustalenie jest w raporcie z odpowiedzi 200. |
429 | Zbyt wiele żądań dla klucza. Należy odczekać liczbę sekund podaną w Retry-After. |
503 | Wszystkie walidatory są zajęte (busy). Należy ponowić po liczbie sekund podanej w Retry-After. |
curl -X POST "https://api-sandbox-eu.eurinvoice.com/validate" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
--data-binary @not-json.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/validate"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("not-json.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/validate', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
},
body: await readFile('not-json.txt'),
});
console.log(response.status);
console.log(await response.text());{
"detail": "The request is not valid JSON.",
"type": "https://eurinvoice.com/problems/bad-request",
"title": "The request could not be read",
"status": 400
}