API de FlavosoWebhooks y eventosWebhooks

Webhooks

Flavoso notifica cada cambio al instante a tu servidor con un POST firmado: configuración, recepción, confirmación, reintentos y registro.

Cómo funcionan los webhooks

Cuando algo cambia en un negocio que ha conectado tu app, se produce un evento, y Flavoso lo envía con un POST a la dirección del webhook de tu app. Tu app no tiene que consultar constantemente: un pedido nuevo suele llegar en pocos segundos.

Cambio en el negocio

Panel, cocina, app móvil, impresora de tickets o API

Evento

Sobre con id, type, data; congelado en el primer envío

Entrega

POST a tu dirección, firmado con Flavoso-Signature

Entregado

tu servidor responde con 2xx en 10 segundos

Si no: nuevo intento 8 intentos a lo largo de casi dos días

  1. 1de inmediato
  2. 21 min
  3. 35 min
  4. 430 min
  5. 52 h
  6. 66 h
  7. 712 h
  8. 824 h

Si fallan al menos 10 intentos seguidos durante 24 horas, la dirección se desactiva y recibes un e-mail.

Lo que se haya perdido lo recuperas con GET /events, hasta 30 días atrás.

Una app tiene exactamente un webhook. A él llegan los eventos de todos los negocios que han conectado tu app, siempre que la conexión tenga el permiso de lectura correspondiente (consulta Permisos y eventos). Además recibe los eventos sobre tus propias conexiones (app.*).

Configuración

  1. 1

    Introducir la dirección

    Una dirección https, accesible desde internet, de 500 caracteres como máximo. Flavoso no acepta direcciones de redes privadas.

    Consola › App › Webhooks

  2. 2

    Elegir los eventos

    Solo lo que necesita tu app. Una caja necesita order.*, a menudo menu.* y store.*, y siempre app.disconnected.

  3. 3

    Copiar el secreto de firma

    Empieza por whsec_. Con él tu servidor comprueba cada entrega. Puedes volver a mostrarlo o renovarlo en cualquier momento en la consola, en Webhooks.

  4. 4

    Enviar un evento de prueba

    Comprueba todo el camino: dirección, firma, respuesta. El resultado aparece debajo, en las entregas.

«Crear un nuevo secreto de firma» sustituye el secreto de firma; durante 24 horas, Flavoso firma con los dos. Puedes desactivar un webhook y volver a activarlo, o eliminarlo: en ese caso desaparecen la dirección, el secreto y todas las entregas con su registro. Los eventos en sí siguen disponibles 30 días a través de GET /events.

El sobre

Cada entrega es un sobre JSON. Es el mismo para el webhook y para GET /events:

CampoSignificado
idIdentificador del evento (evt_…). Con él reconoces los duplicados.
objectSiempre event.
typeEl tipo, por ejemplo order.created. Consulta Tipos de eventos.
created_atCuándo se produjo el cambio.
api_versionLa fecha de versión, como en Flavoso-Api-Version.
livemodefalse en el negocio de prueba.
tenant_idEl negocio.
connection_idLa conexión de tu app con este negocio. Con ella encuentras los tokens correspondientes.
dataEl contenido: data.object es el objeto en el mismo formato que devuelven las rutas y, según el tipo, además previous_status, changed o previous.
{
  "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": []
        }
      ]
    }
  }
}

Además llegan estas cabeceras:

CabeceraSignificado
Flavoso-SignatureLa firma; consulta Comprobar las firmas.
Flavoso-Event-IdLo mismo que id en el sobre.
Flavoso-Event-TypeLo mismo que type.
Flavoso-Delivery-AttemptEl número de envío de esta entrega, empezando por 1. Cuenta cada envío, automático o reenviado a mano.
Content-Typeapplication/json
User-AgentFlavoso-Webhooks/1.0 (+https://docs.flavoso.com/en/api), para que reconozcas las entregas en tus registros.
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",...}

Recibir y confirmar

Una entrega se considera recibida si tu servidor responde con cualquier 2xx en un plazo de 10 segundos. El contenido del cuerpo de tu respuesta no importa.

  • Primero comprueba la firma, después responde y luego procesa: un procesamiento largo antes de la respuesta agota el plazo, y Flavoso vuelve a enviar la misma entrega.
  • Una redirección (3xx) cuenta como fallo. Registra la dirección definitiva.
  • Guarda el id de cada evento procesado y omite los duplicados.
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);

Reintentos

Todo lo que no sea 2xx cuenta como fallo: un código de error, un tiempo de espera agotado, una redirección, un servidor inaccesible. Entonces Flavoso vuelve a intentarlo, 8 intentos en total a lo largo de casi dos días. Una caja apagada durante la noche lo recibe todo igualmente por la mañana.

IntentoEspera desde el anterior
1de inmediato
21 min
35 min
430 min
52 h
66 h
712 h
824 h

Las esperas cuentan siempre desde el intento anterior. Flavoso-Delivery-Attempt cuenta cada envío, también los manuales. Cada intento envía el mismo sobre, byte a byte, con una firma nueva.

Desactivación por errores persistentes

Si fallan al menos 10 intentos seguidos y durante 24 horas no llega nada, Flavoso desactiva el webhook y te envía un e-mail. En ese caso, las entregas pendientes se omiten.

Una vez solucionado el problema, vuelve a activarlo en la consola y reenvía las entregas perdidas con «Reenviar», o recupéralas con GET /events, hasta 30 días atrás.

Orden y duplicados

  • Orden: no está garantizado. Los eventos de un mismo objeto pueden llegar desordenados, por ejemplo un reintento después de un evento posterior. Gana el estado más reciente según el updated_at del objeto: data.object.updated_at es el momento del cambio que comunica el evento. Quédate con el estado de updated_at más reciente e ignora los más antiguos.
  • Duplicados: son posibles, por ejemplo si tu respuesta se pierde por el camino. Lo que cuenta es el id del evento.
  • Estado en el sobre: data.object se construye en el primer envío y después queda congelado; en pedidos y reservas, status y updated_at son los del cambio que comunica el evento. Si necesitas tener la certeza del estado actual, vuelve a leer el objeto con GET.
  • Campos de tu app: external_id y acknowledged_at aparecen siempre como null en los eventos, porque el mismo sobre va a todos los destinatarios. Las respuestas de las rutas sí los llevan.

Entregas y reenvío

En Webhooks están todas las entregas a tu dirección, de todos los negocios conectados, filtrables por estado, tipo, negocio y periodo. La vista de detalle de una entrega muestra el sobre, las cabeceras enviadas con la firma y cada intento: momento, automático o manual, estado HTTP, duración, error y el principio de la respuesta de tu servidor (hasta 2.000 caracteres).

«Reenviar» vuelve a enviar una entrega, con el mismo sobre y el mismo id. No cuenta para los 8 intentos automáticos. «Reenviar» y «Enviar un evento de prueba» se pueden usar en total como máximo 10 veces por minuto y app, incluidos los botones de la pestaña Eventos del negocio de prueba.

Eventos de prueba

«Enviar un evento de prueba» envía a tu dirección el tipo que elijas, incluso uno al que no estés suscrito, o bien ping. Los datos vienen de tu negocio de prueba cuando los hay y, si no, son datos de ejemplo; livemode es siempre false. A partir de ahí, es una entrega como cualquier otra: firmada, con reintentos y en el registro. Para ello, la conexión con el negocio de prueba necesita el permiso de lectura correspondiente.

Lo que haces de verdad en el negocio de prueba desencadena eventos reales: un pedido de prueba, order.created; un cambio de estado en la consola, order.status_changed; una pausa, store.paused.

Para desarrollar en tu propio ordenador necesitas una dirección pública, por ejemplo mediante un túnel. O usas GET /events, que no la necesita.

Webhooks propios de un negocio

Un propietario también puede configurar él mismo webhooks para su negocio, sin app, por ejemplo para un sistema propio o un servicio de automatización: en el panel, en Ajustes, Integraciones, hasta cinco direcciones. Tienen el mismo formato; allí connection_id es null y no hay eventos app.*. Más información en el manual de Flavoso.

¿Algo no ha quedado claro? Escribe a support@flavoso.com e indica el identificador de X-Request-Id. Así podremos encontrar tu solicitud en el registro.