> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maple.inc/llms.txt
> Use this file to discover all available pages before exploring further.

# Eventos de webhook

> El catálogo de tipos de eventos de webhook y la carga útil que lleva cada uno.

<Note>
  Las cargas útiles aquí documentadas reflejan lo que Maple emite, pero todavía no tienen un esquema formal: pueden
  agregarse campos nuevos. Valide de forma defensiva (ignore los campos desconocidos) y trate `GET /v1/orders/{orderId}`
  como la fuente autorizada del estado actual de un pedido. La lista vigente de tipos de eventos siempre está en
  `GET /v1/webhook_event_types`.
</Note>

Todos los webhooks se entregan en el mismo [sobre firmado](/es/developer-api/concepts/webhooks); solo cambia `data` según `type`. Esta página documenta cada tipo de evento. Para firma, entrega, reintentos y reenvío, consulte [Webhooks](/es/developer-api/concepts/webhooks).

## Eventos de pedidos

Los webhooks de pedidos son de dos tipos, y distinguirlos es la clave para usarlos bien:

* **`order.notification` es el evento sobre el que usted cumple el pedido.** Le entrega el contenido del pedido para actuar, se dispara una sola vez en el traspaso y su entrega se considera crítica. Construya sobre él su ciclo de aceptar / rechazar / listo / completar.
* **`order.created`, `order.paid` y `order.cancelled` son eventos de ciclo de vida.** Cada uno informa un momento de la vida del pedido con datos resumidos, para seguimiento y conciliación. Como `order.notification` se dispara solo una vez y nunca se actualiza, estos eventos le permiten enterarse de lo que ocurre antes o después de esa instantánea, sobre todo una cancelación o un pago que se liquida más tarde.

Para conocer el orden en que se disparan durante la vida de un pedido, consulte [Cuándo se disparan los webhooks](/es/developer-api/concepts/order-lifecycle).

| Tipo | Se dispara cuando | Suscríbase para… | `data` |
| - | - | - | - |
| `order.validation_requested` | Antes de la notificación: Maple le pide confirmar que el pedido se puede cumplir (solo si usted se suscribe) | Validar de antemano la disponibilidad y los precios antes de cobrar al cliente | Contenido completo del pedido (misma estructura que `order.notification`) |
| `order.notification` | El pedido se le entrega para cumplirlo, después de la validación y del control de pago | **Recibir y cumplir pedidos**: el núcleo de una integración | Contenido completo del pedido (vea abajo) |
| `order.created` | Se crea un pedido, antes y con menos detalle que la notificación | Reflejar los pedidos nuevos para análisis; detectar pedidos que nunca le llegan (por ejemplo, rechazados en la validación) | `order_id`, `location_id`, `status`, `total`, `items`, `created_at` |
| `order.paid` | El pago se liquida, lo que puede ocurrir *después* del traspaso (pago en el local, pago mediante enlace) | Conciliar el pago sin consultas repetidas | `order_id`, `location_id`, `status`, `amount`, `payment_method`, `payment_source` |
| `order.cancelled` | El cliente o el local cancela, a menudo *después* de haberle notificado | Dejar de preparar un pedido cancelado | `order_id`, `location_id`, `status`, `reason` |

### ¿A qué eventos de pedidos debo suscribirme?

* **Para cumplir pedidos (un POS):** `order.notification` y `order.cancelled`: reciba los pedidos y deténgase cuando uno se cancele. Agregue `order.validation_requested` si valida de antemano.
* **Para reportes o conciliación (un OMS, un panel, analítica):** también `order.created` y `order.paid`, para reflejar el ciclo de vida del pedido y del pago.

### La carga útil de `order.notification`

`order.notification` (y `order.validation_requested`) llevan el contenido del pedido en `data`, suficiente para empezar a cumplirlo, con la estructura de `GET /v1/orders/{orderId}`:

```json theme={null}
{
  "order_id": "ord_...",
  "location_id": "str_...",
  "fulfillment_type": "delivery",
  "scheduled_for": null,
  "delivery_address": {
    "street": "123 Main Street",
    "unit": "Apt 4B",
    "city": "New York",
    "state": "NY",
    "zip": "10001",
    "notes": "Leave at the side door"
  },
  "customer": { "name": "Alex", "phone": "+14155551234", "phone_last_four": "1234" },
  "line_items": [
    {
      "name": "Latte",
      "menu_entity_id": "itm-latte",
      "quantity": 1,
      "base_price": 450,
      "modifiers": [{ "name": "Oat milk", "menu_entity_id": "mod-oat", "quantity": 1, "price": 75 }]
    }
  ],
  "totals": { "currency": "USD", "subtotal": 525, "tax": 42, "surcharge": 0, "tip": 0, "delivery_fee": 599, "delivery_tip": 0, "total": 1166 }
}
```

Este es el **contenido** del pedido, no su estado actual: no incluye `status` ni `payment`. Para el estado actual y autorizado (estado, pago, impuesto por artículo, marcas de tiempo), consulte [`GET /v1/orders/{orderId}`](/es/developer-api/concepts/order-lifecycle). Los eventos de ciclo de vida llevan únicamente los campos resumidos indicados arriba.

`scheduled_for` es `null` en los pedidos para el momento (ASAP). Cuando tiene valor (ISO 8601, UTC), el cliente eligió esa hora de recogida o entrega: la notificación igual llega de inmediato, así que prepare el pedido para `scheduled_for`, no al recibirlo.

`delivery_address` es `null` en los pedidos para recoger y en los pedidos a domicilio sin dirección guardada. Cuando está presente, se incluyen las seis claves; `notes` contiene las instrucciones de entrega, y `unit` o `notes` pueden ser `null`.

### No es un flujo de estados

Maple **no** emite un webhook por cada cambio de estado. Las transiciones que usted mismo ejecuta (`accept`, `ready`, `complete`) no se le devuelven, y no hay un evento para cuando el pedido llega a `IN_DELIVERY` ni para cuando el pago pasa a `refunded` / `voided` / `failed`. Consulte el recurso del pedido para conocer el estado actual; vea [Ciclo de vida del pedido](/es/developer-api/concepts/order-lifecycle).

## Eventos de reservas

Los eventos de reservas se entregan a cada app activa a la que se le haya otorgado el local, cuyos alcances (scopes) permitidos incluyan `bookings:read` y cuya suscripción coincida con el tipo de evento. No es necesario que la app sea dueña de la conexión con el POS. El indicador de despliegue de reservas del local debe estar habilitado.

| Tipo | Cambio informado |
| - | - |
| `booking.created` | Reserva creada o vista por primera vez desde su proveedor |
| `booking.confirmed` | Solicitud confirmada |
| `booking.updated` | Reserva modificada |
| `booking.cancelled` | Reserva cancelada |
| `booking.declined` | Solicitud rechazada |
| `booking.seated` | Grupo sentado |
| `booking.completed` | Servicio completado |
| `booking.no_show` | Grupo marcado como ausente (no-show) |

Los ocho usan la misma estructura de `data`. El `booking` incluido coincide con el recurso GET:

```json theme={null}
{
  "location_id": "str_example",
  "previous_status": null,
  "booking": {
    "object": "booking",
    "id": "bkg_example",
    "livemode": false,
    "created": 1789063200,
    "version": 1,
    "location_id": "str_example",
    "status": "confirmed",
    "service_state": null,
    "confirmation_code": "AB1234",
    "starts_at": "2026-09-12T22:00:00.000Z",
    "starts_at_local": "2026-09-12T18:00",
    "service_date": "2026-09-12",
    "duration_minutes": 90,
    "party_size": 2,
    "guest": { "first_name": "Alex", "last_name": "Quinn", "phone": "+12125551234", "phone_last_four": "1234", "email": null },
    "notes": null,
    "channel": "api_partner",
    "provider": "maple",
    "cancellation_policy": null,
    "updated_at": "2026-09-10T18:01:00.000Z"
  }
}
```

La carga útil es el **estado más reciente de la reserva en el primer envío**, no una instantánea inmutable de la transición. `previous_status` es `null`. Por lo tanto, el nombre de un evento puede describir un cambio anterior al estado actual de la reserva incluida. Una vez registrados para un destinatario, los reintentos conservan esa carga útil y la identidad del evento.

Cada evento original de la bandeja de salida recibe una identidad estable por app y entorno. Dos cambios en la misma reserva siguen siendo distintos aun cuando ambos se envíen con la misma versión de la reserva. Elimine duplicados por ID de evento y concilie por `id`/`version` de la reserva; no dependa del orden de entrega. El consumidor independiente para desarrolladores no avanza el cursor de comunicaciones con los invitados. En esta versión no se reenvían eventos del plano de sala; los cambios de la lista de espera tienen sus propios [eventos](#eventos-de-lista-de-espera).

Si falla el encolado para un destinatario, no se detiene el encolado para las demás apps o suscripciones elegibles. Los reintentos reutilizan la misma identidad de evento por suscripción. La publicación de eventos de reservas usa como máximo tres intentos de envío, cada uno con reintentos internos acotados. Los eventos internos mal formados y los intentos de envío agotados se conservan para que un operador los investigue, en lugar de bloquear los eventos siguientes o reintentar indefinidamente. Esto es independiente de los [reintentos de entrega HTTP de webhooks](/es/developer-api/concepts/webhooks). Use `GET /v1/bookings?updated_since=…` para conciliar el estado actual de las reservas después de un hueco en las entregas.

## Eventos de lista de espera

Los eventos de lista de espera llegan a las mismas apps que los de reservas: cada app activa a la que se le haya otorgado el local, cuyos alcances permitidos incluyan `bookings:read` y cuya suscripción coincida con el tipo de evento. Se envían para los locales nativos de Maple mientras el indicador de despliegue de reservas del local esté habilitado. Consulte [Administre la lista de espera](/es/developer-api/guides/run-the-waitlist).

| Tipo | Cambio informado |
| - | - |
| `waitlist_entry.created` | Un grupo se unió a la lista de espera |
| `waitlist_entry.notified` | Maple envió un SMS al grupo avisándole que su mesa está lista |
| `waitlist_entry.seated` | El grupo se sentó en una reserva de cliente sin reserva (walk-in) |
| `waitlist_entry.removed` | El grupo se retiró (`removed_by_guest`) o el establecimiento lo eliminó (`removed_by_venue`) |
| `waitlist_entry.expired` | Un grupo notificado no respondió a tiempo |

Los cinco usan la misma estructura de `data`. El `waitlist_entry` incluido coincide con `GET /v1/waitlist_entries/{entryId}`:

```json theme={null}
{
  "location_id": "str_example",
  "waitlist_entry": {
    "object": "waitlist_entry",
    "id": "bkw_example",
    "livemode": false,
    "created": 1789063200,
    "location_id": "str_example",
    "status": "seated",
    "party_size": 2,
    "position": null,
    "quoted_wait": { "parties_ahead": 1, "wait_minutes": { "min": 15, "max": 30 } },
    "joined_at": "2026-09-10T18:00:00.000Z",
    "notified_at": "2026-09-10T18:20:00.000Z",
    "booking_id": "bkg_example",
    "channel": "api_partner",
    "guest": { "first_name": "Alex", "last_name": "Quinn", "phone": "+12125551234", "phone_last_four": "1234", "email": null }
  }
}
```

Igual que en los eventos de reservas, la carga útil es el **estado más reciente de la entrada en el primer envío**: un `waitlist_entry.created` entregado después de que el grupo se sentó ya muestra `seated`. Use el tipo de evento para saber qué ocurrió y `waitlist_entry.status` para saber en qué estado está ahora la entrada. Cada cambio tiene su propio ID de evento por app y entorno; elimine duplicados por ID de evento y no dependa del orden de entrega. Los intentos de entrega, los reintentos y la cuarentena de eventos internos mal formados siguen las reglas de los eventos de reservas descritas arriba. Sentar al grupo también crea una reserva de cliente sin reserva (walk-in), que se informa mediante los eventos de reservas a los que usted se suscriba.

## Eventos de local (`store`)

Estos eventos siguen su acceso a un local: el [ciclo de vida de la conexión](/es/developer-api/concepts/entities):

| Tipo | Cuándo se dispara | `data` (indicativo) |
| - | - | - |
| `store.provisioned` | Un comercio otorgó a su app acceso a un local | `location_id` |
| `store.deprovisioned` | Se revocó un permiso; usted perdió el acceso al local | `location_id` |
| `store.status.changed` | Cambió su conexión con un local | `location_id`, `status` (`connected` / `disconnected`) |

## Eventos de menú

| Tipo | Cuándo se dispara | `data` (indicativo) |
| - | - | - |
| `menu.sync.completed` | Se completó una sincronización de menú para un local | `location_id` |
| `menu.sync.failed` | Falló una sincronización de menú para un local | `location_id` |

Consulte [Publique un menú](/es/developer-api/guides/publish-menu).

## Evento de prueba

`webhook.test` se entrega a pedido mediante `POST /v1/webhook_subscriptions/{id}/test`. Úselo para verificar su controlador antes de recibir tráfico real. La actividad real nunca lo emite.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.