API di FlavosoWebhook ed eventiWebhook
Webhook
Flavoso segnala subito ogni modifica al tuo server con un POST firmato: configurazione, ricezione, conferma, nuovi tentativi e registro.
Come funzionano i webhook
Quando qualcosa cambia in un locale che ha collegato la tua app, viene generato un evento, e Flavoso lo invia con un POST all'indirizzo webhook della tua app. La tua app non ha bisogno di interrogare di continuo: di solito un nuovo ordine arriva in pochi secondi.
Modifica nel locale
Dashboard, cucina, app per il telefono, stampante per scontrini o API
Evento
Busta con id, type, data; congelata al primo invio
Consegna
POST al tuo indirizzo, firmato con Flavoso-Signature
Consegnato
il tuo server risponde con 2xx entro 10 secondi
Altrimenti: nuovo tentativo 8 tentativi in quasi due giorni
- 1subito
- 21 min
- 35 min
- 430 min
- 52 h
- 66 h
- 712 h
- 824 h
Se per 24 ore falliscono almeno 10 tentativi di fila, l'indirizzo viene disattivato e ricevi un'e-mail.
Ciò che è andato perso lo recuperi con GET /events, fino a 30 giorni indietro.
Un'app ha esattamente un webhook. Lì arrivano gli eventi di tutti i locali che hanno collegato la tua app, purché il collegamento abbia il permesso di lettura corrispondente (vedi Permessi ed eventi). In più arrivano gli eventi dei collegamenti stessi (app.*).
Configurazione
- 1
Inserisci l'indirizzo
Un indirizzo
https, raggiungibile da internet, al massimo 500 caratteri. Flavoso non accetta indirizzi in reti private.Console › App › Webhook
- 2
Scegli gli eventi
Solo ciò che serve alla tua app. Una cassa ha bisogno di
order.*, spesso dimenu.*estore.*, sempre diapp.disconnected. - 3
Copia il segreto di firma
Inizia con
whsec_. Con questo il tuo server verifica ogni consegna. Nella console, sotto Webhook, puoi mostrarlo di nuovo o rinnovarlo in qualsiasi momento. - 4
Invia un evento di prova
Verifica tutto il percorso: indirizzo, firma, risposta. Il risultato compare nelle consegne qui sotto.
«Crea un nuovo segreto di firma» sostituisce il segreto; per 24 ore Flavoso firma con entrambi. Un webhook puoi disattivarlo e riattivarlo, oppure eliminarlo: in quel caso indirizzo, segreto e tutte le consegne con il loro registro spariscono. Gli eventi stessi restano recuperabili per 30 giorni con GET /events.
La busta
Ogni consegna è una busta JSON. È la stessa per il webhook e per GET /events:
| Campo | Significato |
|---|---|
id | Identificativo dell'evento (evt_…). Serve a riconoscere i duplicati. |
object | Sempre event. |
type | Il tipo, per esempio order.created. Vedi Tipi di evento. |
created_at | Quando è avvenuta la modifica. |
api_version | La data di versione, come in Flavoso-Api-Version. |
livemode | false per il locale di prova. |
tenant_id | Il locale. |
connection_id | Il collegamento della tua app a questo locale. Ti serve per trovare i token giusti. |
data | Il contenuto: data.object è l'oggetto nella stessa forma restituita dagli endpoint, più previous_status, changed o previous a seconda del tipo. |
{
"id": "evt_2bf5a9b06b75442a9244e884a1acfc57",
"object": "event",
"type": "order.created",
"created_at": "2026-10-04T17:45:10.410Z",
"api_version": "2026-10-08",
"livemode": true,
"tenant_id": "7d0e5b8a-3c41-4f2e-9a6b-1e2d3c4b5a69",
"connection_id": "4b3f7c1e-9a2d-4e8b-b5f6-0c1d2e3f4a5b",
"data": {
"object": {
"object": "order",
"id": "cce01f52-5188-410f-9659-6ce26ba9b784",
"code": "3271CD",
"type": "delivery",
"status": "pending",
"source": "storefront",
"created_at": "2026-10-04T17:44:59.942Z",
"updated_at": "2026-10-04T17:45:10.118Z",
"requested_for": null,
"currency": "EUR",
"amounts": {
"subtotal": 2490,
"delivery_fee": 250,
"service_fee": 0,
"discount": 0,
"tip": 200,
"total": 2940
},
"tax": {
"included": true,
"lines": [
{
"rate_bps": 700,
"gross": 2421,
"net": 2263,
"tax": 158
},
{
"rate_bps": 1900,
"gross": 319,
"net": 268,
"tax": 51
}
]
},
"payment": {
"method": "online",
"status": "paid",
"paid_at": "2026-10-04T17:45:10.000Z"
},
"customer": {
"name": "Alex",
"phone": "+49 151 00000000"
},
"delivery": {
"address": "Musterstraße 1",
"postal_code": "10115",
"city": "Berlin"
},
"table": null,
"note": "Please ring twice",
"external_id": null,
"acknowledged_at": null,
"items": [
{
"id": "e9c0ce66-7f7f-42cf-a4bf-7d66f87768c1",
"product_id": "303b87c9-58a3-4644-9a8b-2841cc1f89d6",
"name": "Pizza Margherita",
"quantity": 2,
"unit_price": 1100,
"line_total": 2200,
"tax_rate_bps": 700,
"options": [
{
"id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b",
"name": "Extra cheese",
"price_delta": 150,
"group_id": "8e7d6c5b-4a39-4281-b0f9-e8d7c6b5a4f3",
"group_name": "Extras"
}
]
},
{
"id": "0d1e2f3a-4b5c-4d6e-8f70-81a2b3c4d5e6",
"product_id": "6a7b8c9d-0e1f-4a2b-9c3d-4e5f6a7b8c9d",
"name": "Cola 0,33 l",
"quantity": 1,
"unit_price": 290,
"line_total": 290,
"tax_rate_bps": 1900,
"options": []
}
]
}
}
}In più ci sono queste intestazioni:
| Intestazione | Significato |
|---|---|
Flavoso-Signature | La firma, vedi Verificare le firme. |
Flavoso-Event-Id | Uguale a id nella busta. |
Flavoso-Event-Type | Uguale a type. |
Flavoso-Delivery-Attempt | Il numero progressivo dell'invio di questa consegna, a partire da 1. Conta ogni invio, automatico o rinviato a mano. |
Content-Type | application/json |
User-Agent | Flavoso-Webhooks/1.0 (+https://docs.flavoso.com/en/api), così riconosci le consegne nei tuoi log. |
POST /flavoso/webhook HTTP/1.1
Host: pos.example.com
Content-Type: application/json
User-Agent: Flavoso-Webhooks/1.0 (+https://docs.flavoso.com/en/api)
Flavoso-Signature: t=1759598710,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
Flavoso-Event-Id: evt_2bf5a9b06b75442a9244e884a1acfc57
Flavoso-Event-Type: order.created
Flavoso-Delivery-Attempt: 1
{"id":"evt_2bf5a9b06b75442a9244e884a1acfc57","object":"event","type":"order.created",...}Ricevere e confermare
Una consegna è considerata arrivata quando il tuo server risponde con un qualsiasi 2xx entro 10 secondi. Il contenuto del corpo della tua risposta non conta.
- Prima verifica la firma, poi rispondi, poi elabora: un'elaborazione lunga prima della risposta supera il limite di tempo, e Flavoso invia di nuovo la stessa consegna.
- Un reindirizzamento (3xx) conta come fallimento. Inserisci l'indirizzo definitivo.
- Memorizza l'
iddi ogni evento elaborato e salta i duplicati.
import express from "express";
import { verifyFlavosoSignature } from "./flavoso-signature.js"; // see "Verifying signatures"
const app = express();
const SECRET = process.env.FLAVOSO_WEBHOOK_SECRET; // whsec_...
// express.raw: the body stays exactly as it arrived, which the signature needs
app.post("/flavoso/webhook", express.raw({ type: "application/json" }), async (req, res) => {
const raw = req.body.toString("utf8");
if (!verifyFlavosoSignature(raw, req.get("Flavoso-Signature") ?? "", SECRET)) {
return res.status(400).send("invalid signature");
}
const event = JSON.parse(raw);
// Answer within 10 seconds, then work. Duplicates are possible: the event id decides.
res.sendStatus(200);
if (await alreadyHandled(event.id)) return;
await queue.add(event); // your job queue: book the order, update the menu, ...
});
app.listen(3000);Nuovi tentativi
Tutto ciò che non è 2xx conta come fallimento: un codice di errore, un timeout, un reindirizzamento, un server non raggiungibile. Allora Flavoso riprova, 8 tentativi in tutto nell'arco di quasi due giorni. Una cassa spenta durante la notte riceve comunque tutto al mattino.
| Tentativo | Attesa dal precedente |
|---|---|
| 1 | subito |
| 2 | 1 min |
| 3 | 5 min |
| 4 | 30 min |
| 5 | 2 h |
| 6 | 6 h |
| 7 | 12 h |
| 8 | 24 h |
Gli intervalli si contano ogni volta dal tentativo precedente. Flavoso-Delivery-Attempt conta ogni invio, anche quelli a mano. Ogni tentativo invia la stessa busta, byte per byte, con una firma nuova.
Disattivazione dopo errori persistenti
Se falliscono almeno 10 tentativi di fila e per 24 ore non arriva nulla, Flavoso disattiva il webhook e ti scrive un'e-mail. Le consegne in sospeso vengono allora saltate.
Una volta risolto il problema, riattivalo nella console e invia di nuovo le consegne perse con «Rinvia», oppure recuperale con GET /events, fino a 30 giorni indietro.
Ordine e duplicati
- Ordine: non è garantito. Gli eventi di uno stesso oggetto possono arrivare in un ordine diverso, per esempio un nuovo tentativo dopo un evento successivo. Vince lo stato più recente secondo l'
updated_atdell'oggetto:data.object.updated_atè il momento della modifica che l'evento segnala. Tieni lo stato con l'updated_atpiù recente e ignora quelli più vecchi. - Duplicati: sono possibili, per esempio quando la tua risposta si perde per strada. Riconoscili dall'
iddell'evento. - Stato nella busta:
data.objectviene costruito al primo invio e poi congelato; per ordini e prenotazioni,statuseupdated_atsono quelli della modifica che l'evento segnala. Se ti serve con certezza lo stato attuale, rileggi l'oggetto conGET. - Campi della tua app:
external_ideacknowledged_atnegli eventi sono semprenull, perché una busta è identica per tutti i destinatari. Li trovi nelle risposte degli endpoint.
Consegne e rinvio
Sotto Webhook trovi tutte le consegne al tuo indirizzo, da tutti i locali collegati, filtrabili per stato, tipo, locale e periodo. La vista di dettaglio di una consegna mostra la busta, le intestazioni inviate con la firma e ogni tentativo: ora, automatico o manuale, stato HTTP, durata, errore e l'inizio della risposta del tuo server (fino a 2.000 caratteri).
«Rinvia» invia di nuovo una consegna, con la stessa busta e lo stesso id. Non conta tra gli 8 tentativi automatici. Insieme, «Rinvia» e «Invia un evento di prova» si possono usare al massimo 10 volte al minuto per app, compresi i pulsanti della scheda Eventi del locale di prova.
Eventi di prova
«Invia un evento di prova» invia al tuo indirizzo un evento del tipo che scegli, anche di un tipo a cui non sei iscritto; tra i tipi c'è anche ping. I dati vengono dal tuo locale di prova, se ce ne sono, altrimenti sono dati di esempio; livemode è sempre false. Da lì in poi è una consegna come le altre: firmata, con nuovi tentativi e nel registro. Perché funzioni, il collegamento al locale di prova deve avere il permesso di lettura corrispondente.
Le attività reali nel locale di prova generano eventi reali: un ordine di prova order.created, un cambio di stato nella console order.status_changed, una pausa store.paused.
Per sviluppare sul tuo computer ti serve un indirizzo pubblico, per esempio tramite un tunnel. Oppure usa GET /events, che non ne ha bisogno.
Webhook propri di un locale
Un titolare può anche configurare da sé dei webhook per il suo locale, senza app, per esempio per un proprio sistema o per un servizio di automazione: nella dashboard in Impostazioni › Integrazioni, fino a cinque indirizzi. Hanno la stessa forma; lì connection_id è null e non ci sono eventi app.*. Trovi di più nel manuale.
Qualcosa non è chiaro? Scrivi a support@flavoso.com indicando l'identificativo di X-Request-Id. Così troviamo la tua richiesta nel registro.