3 API3.1
Simulazione: POST /validate
Esegue gli stessi controlli dell’invio. Non archivia e non invia nulla.
- Nella sandbox
In parole semplici
Una simulazione controlla una fattura come farebbe un invio reale e non invia nulla, così un partner può trovare ogni problema prima che la fattura di un cliente venga inviata.
POST /validate esegue gli stessi controlli di un invio e risponde con un report. Non mette nulla in coda e non invia nulla. La chiamata richiede una chiave con lo scope submit. Il corpo è JSON, fino a 5 MB.
Suggerimento
Iniziare da qui quando si mappa un nuovo cliente.
La richiesta
| Campo | Significato |
|---|---|
invoice_ref | Obbligatorio. L’id del documento nell’ERP, fino a 100 caratteri. Riportato in ogni evento di stato. |
route | Obbligatorio. DE-XRECHNUNG, PEPPOL, FR-PA, PL-KSEF o RO-EFACTURA. |
document | Una fattura nel modello canonico. Inviare questo oppure un export, non entrambi. |
export, connector | Un export dell’ERP così come l’ERP lo ha scritto, con connector impostato a business-central o sap-b1. Inviare questo oppure un document, non entrambi. Su un canale diverso dalla Germania il report inizia con un livello mapping. mapping_version sceglie una versione diversa da quella attiva (vedere versioni di mappatura). |
formats | I documenti da costruire dove il canale consente una scelta. Germania: uno o più tra xrechnung-ubl (il predefinito), xrechnung-cii e zugferd; KoSIT viene eseguito una volta per formato, e per il PDF vengono eseguiti anche Mustang e veraPDF. Francia: ubl, cii o facturx. |
environment | Facoltativo. Deve corrispondere all’ambiente della chiave. |
erp_totals | I totali calcolati dall’ERP: payable_amount, currency e facoltativamente tax_amount, come stringhe. Se differiscono dai totali che il servizio calcola dalle righe, il report contiene una segnalazione EI-TOTALS-MISMATCH su erp_totals.payable_amount. |
L’elenco completo dei campi è nel riferimento.
Una fattura che supera i controlli
La richiesta di esempio è validate-de-ok.json, una fattura tedesca inventata. Il report riporta valid: true, un documento con il suo SHA-256 e quattro livelli superati.
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"
}
]
}Una fattura che non supera i controlli
La stessa fattura senza il nome del venditore, validate-de-missing-seller-name.json. Una simulazione risponde comunque 200. valid è false, e ogni segnalazione indica il campo e chi lo corregge. Le due righe evidenziate sono quelle da guardare: il code del catalogo e il field nei dati del cliente.
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"
}
]
}Leggere il report
validètruesolo quando tutti i livelli sono stati superati.- I
layersvengono eseguiti in ordine:schema,mapping,pre-check, poi i validatori propri del canale, con il nome di ciò che è stato eseguito (per esempioKoSIT-XRechnung-3.0.2). - Ogni segnalazione ha un
codedel catalogo, ilfield,who_fixes(usoerp), unfix_hint, unmessagee il livellosource. Errori e catalogo elenca tutti i codici. documentselenca ciò che è stato generato, con il suo SHA-256 e, per un file di 2 MiB o meno, i suoi byte incontent_base64. È presente quando la fattura è valida.
Altre risposte
| Stato | Significato |
|---|---|
200 | Un report, valido o no. |
400 | La richiesta non si può leggere: non è JSON, un campo è errato, oppure sono presenti sia document sia export. |
401 | Nessuna chiave, o una chiave sconosciuta. |
403 | La chiave non ha lo scope submit. |
413 | Il corpo supera 5 MB (payload-too-large). |
422 | Un numero oltre i limiti, per esempio uno di più di 40 caratteri (EI-SCHEMA, con il nome del campo). Ogni altra segnalazione arriva nel report 200. |
429 | Troppe richieste per la chiave. Attendere Retry-After secondi. |
503 | Tutti i validatori sono occupati (busy). Riprovare dopo Retry-After secondi. |
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
}