Webhook
Cuando una empresa tiene habilitado el POS externo, NubeFood notifica cada orden enviando un POST a la URL de callback que configuraste. Este documento describe cómo configurar tu webhook y el payload que enviamos.
Configurar el webhook
Podés configurar tu propio webhook (URL de callback + secret) con tu access token (Authorization: Bearer <access token>). El endpoint opera sobre el webhook de tu empresa (el companyId sale del token). Hay un webhook por empresa: PUT lo crea o lo reemplaza.
Cuerpo de la consulta
URL a la que enviaremos las notificaciones (http/https).
Secreto que enviaremos en el header x-webhook-secret. Enviá "" para limpiarlo; si se omite, se conserva el actual.
Habilita/deshabilita el envío (default true al crear).
Ejemplo.
curl -v -X PUT
--url 'https://api.public.lumarketo.cl/webhook'
--header 'Authorization: Bearer <access_token>'
--data '{ "callbackUrl": "https://tu-pos.com/webhook", "secret": "un-secreto-compartido" }'Respuesta: { success, message, data: { callbackUrl, active, hasSecret } }.
Para consultar la configuración actual (sin exponer el secret):
Devuelve { callbackUrl, active, hasSecret } (o data: null si no hay webhook configurado).
La solicitud que enviamos
<tu-callbackUrl>
- Método:
POST - Content-Type:
application/json - Cuerpo: el objeto de la orden normalizada (ver estructura abajo).
- Disparo: al crear/confirmar la orden y en cada cambio de estado (mientras el webhook esté activo). Cada notificación trae el snapshot de la orden con su
statusactual.
Tu endpoint debe responder 2xx para confirmar la recepción.
Validación de origen (header secreto)
Si configuraste un secret para el webhook, cada request incluye el header:
x-webhook-secret: <tu-secret>
Validá ese header en tu endpoint y rechazá las solicitudes cuyo valor no coincida con el secret acordado. Si no configuraste un secret, el header no se envía.
Estructura del cuerpo
Sucursal de la orden.
extId de integración de la sucursal (o el id interno si no tiene extId).
ID interno de la orden en NubeFood.
Estado actual de la orden en el momento de la notificación (cambia en cada cambio de estado). Ver 'Estados posibles' más abajo.
Número de orden correlativo de la empresa (companyOrderNumber).
ID de la empresa (company) dueña de la orden.
Nombre legible de la orden: '#{code} - {nombre cliente} - {deliveryType} - Nubefood'.
Fecha de creación de la orden (ISO).
'delivery' si la orden tiene envío; 'pickup' si es retiro.
Total a pagar de la orden (incluye envío).
Total de los productos, sin el costo de envío (total − deliveryFee).
Costo de envío.
Descuento aplicado por cupón.
Fecha/hora de entrega estimada (o '' si no aplica).
true si la orden es programada.
Fecha programada (solo presente si isScheduled = true).
Dirección de entrega. Solo se incluye cuando deliveryType = 'delivery'.
Latitud.
Longitud.
Dirección completa.
Número.
Calle.
País.
Región/estado.
Ciudad.
Código postal.
Teléfono de contacto.
Detalles adicionales (depto, referencia, etc.).
Datos del cliente.
Nombre.
Apellido.
Email.
Teléfono.
Productos de la orden.
Producto.
extId de integración del producto para esa sucursal. Es null si el ítem tiene modificadores/adicionales.
Nombre del producto.
Cantidad pedida del producto.
Instrucciones/comentario del ítem.
Precio unitario final (con descuentos): bestPrice / cantidad.
Precio unitario de lista (sin descuentos): price / cantidad.
Precio final del ítem incluyendo adicionales (bestPrice + adicionales).
Precio de lista del ítem incluyendo adicionales (price + adicionales).
Adicionales/modificadores del ítem.
Reservado (actualmente null a nivel modificador).
Nombre del modificador.
Nombre corto del modificador.
Mapa { modifierId: cantidad }.
Mapa { extId: cantidad } (extId de integración del modificador para la sucursal).
Opciones del modificador: { optionId, externalId, name, price }.
Estados posibles (status)
El campo status puede tomar estos valores (ciclo de vida de la orden):
status | Significado |
|---|---|
pending | Esperando confirmación del método de pago |
payment-pending | En espera del pago |
payment-approved | El pago fue aprobado |
payment-canceled | El pago fue cancelado u ocurrió un error |
picker-pending | Pendiente (por tomar) |
inProcess | En proceso (aceptada / en preparación) |
ready | Lista para despachar |
routed | En camino (delivery con el pedido) |
dispatched | Entregado |
cancel | Cancelada |
refund | Reembolsada |
shippingError | Error en el envío |
Ejemplo
{
"store": { "externalId": "1546626" },
"internalOrderId": "652f0a1b2c3d4e5f60718293",
"status": "inProcess",
"couponDiscount": 0,
"amountToPay": 15900,
"deliveryFee": 2500,
"amount": 13400,
"websiteId": "63ebadc353f9eb8978f057a0",
"code": 1042,
"createdAt": "2026-07-22T18:30:00.000Z",
"deliveryTime": "2026-07-22T19:15:00.000Z",
"isScheduled": false,
"deliveryType": "delivery",
"address": {
"lat": -33.4489,
"lng": -70.6693,
"address": "Av. Siempre Viva 742, Santiago",
"streetNumber": "742",
"streetAddress": "Av. Siempre Viva",
"country": "CL",
"state": "Región Metropolitana",
"city": "Santiago",
"zipCode": "",
"phoneNumber": "+56912345678",
"details": "Depto 4B"
},
"user": {
"firstName": "Juan",
"lastName": "Pérez",
"email": "juan.perez@mail.com",
"phoneNumber": "+56912345678"
},
"name": "#1042 - Juan Pérez - delivery - Nubefood",
"items": [
{
"product": { "externalId": "777", "name": "Hamburguesa clásica" },
"comment": "Sin cebolla",
"amount": 2,
"unitPrice": 5450,
"baseUnitPrice": 5950,
"productPrice": 11900,
"productBasePrice": 11900,
"modifiers": [
{
"externalId": null,
"name": "Extra queso",
"shortName": "Extra queso",
"description": [],
"countById": { "652a1b2c3d4e5f6071829300": 1 },
"countByExternalId": { "Q-01": 1 },
"options": [
{
"optionId": "652a1b2c3d4e5f6071829300",
"externalId": "Q-01",
"name": "Extra queso",
"price": 500
}
]
}
]
}
]
}Notas: el campo address solo viene en órdenes de delivery. En
pickup se omite. Los importes van en la moneda de la empresa. El
externalId de producto/modificador corresponde al id de integración
(Fudo/Toteat) mapeado para esa sucursal.