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

  1. 1subito
  2. 21 min
  3. 35 min
  4. 430 min
  5. 52 h
  6. 66 h
  7. 712 h
  8. 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. 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. 2

    Scegli gli eventi

    Solo ciò che serve alla tua app. Una cassa ha bisogno di order.*, spesso di menu.* e store.*, sempre di app.disconnected.

  3. 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. 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:

CampoSignificato
idIdentificativo dell'evento (evt_…). Serve a riconoscere i duplicati.
objectSempre event.
typeIl tipo, per esempio order.created. Vedi Tipi di evento.
created_atQuando è avvenuta la modifica.
api_versionLa data di versione, come in Flavoso-Api-Version.
livemodefalse per il locale di prova.
tenant_idIl locale.
connection_idIl collegamento della tua app a questo locale. Ti serve per trovare i token giusti.
dataIl 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:

IntestazioneSignificato
Flavoso-SignatureLa firma, vedi Verificare le firme.
Flavoso-Event-IdUguale a id nella busta.
Flavoso-Event-TypeUguale a type.
Flavoso-Delivery-AttemptIl numero progressivo dell'invio di questa consegna, a partire da 1. Conta ogni invio, automatico o rinviato a mano.
Content-Typeapplication/json
User-AgentFlavoso-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'id di 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.

TentativoAttesa dal precedente
1subito
21 min
35 min
430 min
52 h
66 h
712 h
824 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_at dell'oggetto: data.object.updated_at è il momento della modifica che l'evento segnala. Tieni lo stato con l'updated_at più recente e ignora quelli più vecchi.
  • Duplicati: sono possibili, per esempio quando la tua risposta si perde per strada. Riconoscili dall'id dell'evento.
  • Stato nella busta: data.object viene costruito al primo invio e poi congelato; per ordini e prenotazioni, status e updated_at sono quelli della modifica che l'evento segnala. Se ti serve con certezza lo stato attuale, rileggi l'oggetto con GET.
  • Campi della tua app: external_id e acknowledged_at negli eventi sono sempre null, 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.