FttElGuida sviluppatori

Gestire i webhook

Ricevi fatture ed esiti sul tuo backend e recupera via API gli aggiornamenti che non arrivano.

Configurare gli endpoint#

I due URL si configurano con PATCH /machine/accounts/me, autenticato con la chiave dell’azienda:

http
PATCH /machine/accounts/me HTTP/1.1
x-api-key: <API_KEY>
Content-Type: application/json

{
  "invoiceStatusWebhookUrl": "https://gestionale.example/webhooks/SEGRETO_CASUALE/stati",
  "inboundInvoiceWebhookUrl": "https://gestionale.example/webhooks/SEGRETO_CASUALE/ricevute"
}

Sostituisci gli URL di esempio con endpoint HTTPS pubblici e un segreto casuale lungo, diverso per account. Invia una stringa vuota nel relativo campo per disabilitarlo. Il servizio esegue un POST JSON con Content-Type: application/json.

Eventi e payload#

invoice.status.updated viene inviato quando una notifica SdI cambia lo stato della fattura. Esempio completo:

json
{
  "event": "invoice.status.updated",
  "invoice": {
    "id": "invoice_123",
    "accountId": "account_123",
    "direction": "OUTBOUND",
    "status": "DELIVERED",
    "filename": "IT12345678901A2026_00001.xml",
    "senderFilename": "fattura.xml",
    "invoiceNumber": "FT-2026-001",
    "sdiIdentifier": "123456789",
    "counterpartyVat": "00000000000",
    "counterpartyFiscal": null,
    "totalAmount": "100.00",
    "issuedAt": "2026-10-01T00:00:00.000Z",
    "receivedAt": "2026-10-01T10:00:00.000Z"
  },
  "previousStatus": "SENT",
  "currentStatus": "DELIVERED",
  "notificationId": "notification_456"
}

invoice.received viene inviato dopo la memorizzazione di una nuova fattura in ingresso. Contiene event e lo stesso oggetto invoice, con direzione INBOUND e stato RECEIVED; non contiene previousStatus, currentStatus o notificationId.

totalAmount è una stringa decimale o null. I dati fiscali, le date e gli identificativi non disponibili possono essere nulli; anche previousStatus e notificationId possono esserlo. Il webhook non contiene i file: recuperali dal dettaglio macchina.

Accettazione, duplicati e recupero#

La consegna è best effort: il timeout predefinito è cinque secondi, configurabile dal gestore. Errori di rete, timeout e risposte non 2xx vengono registrati; non è prevista una coda di ritentativi automatici. Un problema del ricevitore non blocca la memorizzazione della fattura.

  1. Associa l’URL segreto al tuo account locale; non scegliere la chiave API basandoti soltanto sul payload ricevuto.
  2. Valida il JSON, accoda in modo persistente il lavoro e restituisci rapidamente un 2xx.
  3. Per gli stati, deduplica usando account, tipo evento e notificationId quando presente. Per le ricevute usa account, tipo evento e invoice.id. In assenza di notificationId, rendi idempotente l’aggiornamento per fattura.
  4. Nel worker rileggi GET /machine/invoices/{id} e aggiorna il gestionale dal dato corrente. Evita di applicare ciecamente gli stati nell’ordine di arrivo dei webhook.
  5. Ignora i tipi evento sconosciuti e prevedi una riconciliazione periodica: lista delle ricevute con finestre sovrapposte e rilettura delle fatture in attesa di esito.

Endpoint di test#

La rotta di test invia un campione all’URL già configurato: POST /accounts/me/webhooks/test, che richiede un JWT dell’account, non la chiave API:

http
POST /accounts/me/webhooks/test HTTP/1.1
Authorization: Bearer <JWT_ACCOUNT>
Content-Type: application/json

{
  "kind": "invoiceStatus",
  "scenario": "deliveryReceipt"
}

Scenari disponibili: deliveryReceipt, deliveryFailure, rejection, outcomeAccepted, outcomeRefused, deadlineExpiry, transmissionCertification. Per una ricevuta usa { "kind": "inboundInvoice" }.

I campioni includono l’header x-fttel-webhook-test: true e i campi JSON test: true, sentAt e account, oltre a dati dimostrativi. Questi elementi non sono garantiti nei webhook di produzione. Mantieni separata l’elaborazione dei test e non considerarne gli id come record reali da recuperare.