Outbound · Vos lo implementás

Webhook Spec

Este documento describe el contrato outbound que BipBip usa para entregar órdenes nuevas a tu POS. Es el endpoint que tu sistema debe implementar y exponer para que BipBip pueda llamarlo.

Esta es la contraparte de la REST API

BipBip → tu POS = webhook (esta página). Tu POS → BipBip = REST API. La guía de integración explica cómo encajan.

Transport contract

Contrato de transporte cerrado — estos parámetros son fijos y no se negocian por merchant.

Parámetro Valor
Path de creación POST {tuBaseUrl}/v1/order/{remoteId}
Path de eventos (multiplexed) POST {tuBaseUrl}/v1/order/{remoteId}/{remoteOrderId}
Eventos en este path order.cancelled, order.driver_assigned, order.delivered — distinguilos por X-Bipbip-Event-Type
Versionado En el path (/v1/) — futuras versiones pueden correr en paralelo
Body JSON — schemas Order, OrderCancellation, OrderDriverAssigned, OrderDelivered
Timeout 30 segundos por intento
ACK (creación) HTTP 200 con { remoteOrderId } — obligatorio
ACK (eventos) HTTP 200 — body ignorado

Headers firmados

BipBip firma cada request con HMAC-SHA256 sobre {timestamp}.{rawBody} usando el secret compartido durante onboarding. Consultá la guía de verificación HMAC para el algoritmo completo y los code samples.

Header Descripción
X-Bipbip-Signature-256 HMAC-SHA256 en formato sha256=<hex> (lowercase)
X-Bipbip-Timestamp Unix epoch segundos. Rechazá si supera 300s de skew.
X-Bipbip-Event-Type order.created, order.cancelled, order.driver_assigned o order.delivered — usalo para rutear al handler correcto
X-Bipbip-Delivery-Id UUID único por dispatch. Usar para deduplicación.

Política de reintentos

BipBip implementa at-least-once delivery con exponential backoff.

  • 5xx o error de red → BipBip reintenta (hasta maxRetries, default 5)
  • 4xx → terminal, BipBip no reintenta
  • Timeout > 30s → trata el intento como fallo y reintenta
  • HTTP 200 sin remoteOrderId → trata como fallo y reintenta
  • Todos los reintentos llevan el mismo X-Bipbip-Delivery-Id — deduplicá con ese UUID

Si agotás los reintentos

Si BipBip agota todos los reintentos sin éxito, la orden se cancela automáticamente y se envía un webhook order.cancelled (si el creation llegó a tu POS alguna vez).

Endpoints

Tu POS debe exponer estos dos endpoints. El segundo path multiplexea tres tipos de evento — usá el header X-Bipbip-Event-Type para rutear al handler correcto.

POST /v1/order/{remoteId}

Entrega de una orden nueva (order.created). Verificá la firma HMAC, deduplicá con X-Bipbip-Delivery-Id, persistí la orden en tu POS y respondé HTTP 200 con { remoteOrderId } en el body. El valor de remoteOrderId es obligatorio — BipBip lo usa para componer la URL de los eventos siguientes.

Example Response
{
  "remoteOrderId": "POS-2026-04-11-00142"
}
POST /v1/order/{remoteId}/{remoteOrderId}

Eventos posteriores de una orden — multiplexa tres tipos según X-Bipbip-Event-Type: order.cancelled (cancelar la orden en tu POS), order.driver_assigned (driver asignado, informativo: actualizá la pantalla operativa si lo querés), order.delivered (entregada al cliente, terminal: marcala como entregada). Verificá HMAC, procesá el evento y respondé HTTP 200 (body ignorado). Solo se envían si el creation webhook llegó con éxito.

Eventos atados al éxito del creation

Si el creation webhook (order.created) nunca llegó a tu POS con HTTP 200, BipBip no envía ninguno de los eventos posteriores (cancelled, driver_assigned, delivered) para esa orden.

Schemas

Los cuerpos JSON que BipBip envía y el ACK que esperamos de vuelta.

Order

Payload enviado por BipBip en POST /v1/order/{remoteId} (eventType order.created).

Campo Tipo Descripción
orderKeystringIdentificador opaco BipBip (ord_ + 16 base62)
eventTypeenumSiempre order.created
occurredAtISO-8601Timestamp UTC del evento
correlationIduuidTrace ID para soporte/logs
customerobjectfullName, phone
deliveryobjectaddress, latitude?, longitude?
totalsobjecttotal, subTotal, taxes, deliveryCharge
items[]arrayproductCode, name, quantity, price, tax, modifiers[]
commentstring?Nota del cliente (puede ser null)
dateDeliveryISO-8601Hora objetivo de entrega
Ejemplo completo
{
  "orderKey": "ord_7h3nXpQa2KvLmN9F",
  "eventType": "order.created",
  "occurredAt": "2026-04-11T15:42:00Z",
  "correlationId": "5f8e4b2a-3c1d-4f9e-b8a7-2d6e1c4b5f9a",
  "customer": {
    "fullName": "Ana Martínez",
    "phone": "+50499887766"
  },
  "delivery": {
    "address": "Col. Lomas del Guijarro, calle 2, casa 15, Tegucigalpa",
    "latitude": 14.0818,
    "longitude": -87.2068
  },
  "totals": {
    "total": 285.00,
    "subTotal": 250.00,
    "taxes": 35.00,
    "deliveryCharge": 0.00
  },
  "items": [
    {
      "productCode": "BM-001",
      "name": "Big Mac Combo",
      "quantity": 2,
      "price": 120.00,
      "tax": 18.00,
      "comments": "Sin cebolla",
      "imageUrl": "https://cdn.bipbip.com/products/bm.png",
      "modifiers": [
        { "name": "Extra queso", "price": 15.00, "quantity": 1 }
      ]
    }
  ],
  "comment": "Dejar en portería, favor llamar al llegar",
  "dateDelivery": "2026-04-11T16:15:00Z"
}

OrderCancellation

Payload enviado por BipBip en POST /v1/order/{remoteId}/{remoteOrderId} cuando el cliente cancela una orden.

Campo Tipo Descripción
orderKeystringIdentificador BipBip de la orden
remoteOrderIdstring?El que devolviste en el ACK original (también en el path)
cancelReasonIdinteger?Razón de cancelación (informativo, puede ser null)
previousStatusenumPending / Accepted / Preparing / Ready / DriverAssigned / Unknown
originenumQuién canceló: Customer (cliente final), Operator (operador BackOffice), Timeout (tu POS no aceptó a tiempo) o WebhookDlq (BipBip agotó reintentos del creation)
operatorUserNamestring?Username del operador BackOffice — solo presente cuando origin = Operator
occurredAtISO-8601Timestamp UTC de la cancelación
Ejemplo
{
  "orderKey": "ord_7h3nXpQa2KvLmN9F",
  "remoteOrderId": "POS-2026-04-11-00142",
  "cancelReasonId": 3,
  "previousStatus": "Pending",
  "origin": "Customer",
  "occurredAt": "2026-04-11T15:52:00Z"
}

OrderDriverAssigned

Payload enviado por BipBip en POST /v1/order/{remoteId}/{remoteOrderId} con X-Bipbip-Event-Type: order.driver_assigned cuando un repartidor se asigna a la orden. Es informativo — la orden sigue en su estado activo, no requiere acción más allá de actualizar la pantalla operativa si lo querés.

Campo Tipo Descripción
orderKeystringIdentificador BipBip de la orden
remoteOrderIdstringEl que devolviste en el ACK original (también en el path)
driver.idintegerIdentificador numérico del driver en BipBip
driver.fullNamestringNombre completo del driver
driver.phonestring?Teléfono internacional — puede ser null si el driver no lo registró o lo tiene privado
assignedAtISO-8601Timestamp UTC de la asignación
Ejemplo
{
  "orderKey": "ord_7h3nXpQa2KvLmN9F",
  "remoteOrderId": "POS-2026-04-11-00142",
  "driver": {
    "id": 4218,
    "fullName": "Juan Pérez",
    "phone": "+50498765432"
  },
  "assignedAt": "2026-04-11T16:05:12Z"
}

OrderDelivered

Payload enviado por BipBip en POST /v1/order/{remoteId}/{remoteOrderId} con X-Bipbip-Event-Type: order.delivered cuando la orden se entrega al cliente. Estado terminal — marcala como entregada en tu POS.

Campo Tipo Descripción
orderKeystringIdentificador BipBip de la orden
remoteOrderIdstringEl que devolviste en el ACK original (también en el path)
deliveredAtISO-8601Timestamp UTC de la entrega al cliente
Ejemplo
{
  "orderKey": "ord_7h3nXpQa2KvLmN9F",
  "remoteOrderId": "POS-2026-04-11-00142",
  "deliveredAt": "2026-04-11T16:18:30Z"
}

OrderAck

Tu response al webhook de creación. Campo obligatorio: remoteOrderId.

{
  "remoteOrderId": "POS-2026-04-11-00142"
}

Sin remoteOrderId, BipBip reintenta

Responses con remoteOrderId null, vacío o ausente se tratan como delivery fallido. BipBip retriará hasta agotar maxRetries.