Outbound · Implementado por el POS

Webhook Spec

Esta página describe el contrato outbound: lo que tu POS recibe cuando BipBip entrega una orden nueva. Tu servidor expone este endpoint, BipBip lo llama.

Esta es la contraparte de la REST API

BipBip → POS = webhook (esta página). 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ámetroValor
Path de creaciónPOST {baseUrl}/v1/order/{remoteId}
Path de actualizacionesPUT {baseUrl}/v1/order/{remoteId}/{remoteOrderId}/events
Eventos en ese pathcancelled, driver_assigned, driver_released, delivered — discriminación por body.event
VersionadoEn el path (/v1/) — futuras versiones pueden correr en paralelo
BodyJSON — schemas Order y OrderUpdateEvent
Timeout15 segundos por intento
ACK (creación)HTTP 200 con { remoteOrderId } — obligatorio
ACK (status update)HTTP 200 — body ignorado
Forward compatStatus desconocidos y campos top-level extra deben tolerarse → 200 OK e ignorar

Headers firmados

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

HeaderDescripción
X-Bipbip-Signature-256HMAC-SHA256 en formato sha256=<hex> (lowercase)
X-Bipbip-TimestampUnix epoch segundos. Se rechaza si supera 300s (5 min) de skew.
X-Bipbip-Event-Typeorder.created en el creation webhook y menu.change.completed.v1 en el de menú. El spec no lo declara en el endpoint de actualizaciones: ahí la discriminación es por body.event.
X-Bipbip-Schema-VersionVersión del schema del payload. Actualmente 1.0. BipBip solo la incrementa ante cambios incompatibles; agregar nuevos valores de status u otros campos es aditivo y no cambia la versión.
X-Bipbip-Delivery-IdUUID único por dispatch. Usar para deduplicación.

Estrategias de autenticación

Además de la firma HMAC —que siempre viaja—, cada endpoint de webhook puede configurar en el Merchant Portal una de tres estrategias para un header de autenticación adicional. La estrategia solo controla si se agrega ese header extra; nunca reemplaza la firma.

EstrategiaQué agrega
hmac_only defaultSolo la firma HMAC-SHA256 (X-Bipbip-Signature-256 + X-Bipbip-Timestamp). No envía header Authorization.
static_headersAgrega headers HTTP arbitrarios (ej. X-Api-Key, Authorization: Bearer <token> estático). Los valores sensibles se cifran con AWS KMS y se desencriptan al momento del dispatch. Soporta rotación dual-window de 24 h.
oauth_client_credentialsBipBip obtiene un Bearer token vía OAuth 2.0 Client Credentials e inyecta Authorization: Bearer <token>. El token se cachea (buffer de 60s antes de expirar); ante un 401 del comercio, BipBip invalida el cache y reintenta una vez con token fresco. Soporta client_secret_post y client_secret_basic, scopes y parámetros extra. Rotación dual-window de 24 h para el client_secret.

La firma HMAC va SIEMPRE — sin importar la estrategia

Las tres estrategias incluyen la firma HMAC en X-Bipbip-Signature-256. La estrategia solo decide si se suma un header de auth adicional — no sustituye la firma.

Tu POS debe validar siempre la firma HMAC, cualquiera sea la estrategia configurada. No hay mTLS ni basic-auth propio.


Política de reintentos

BipBip implementa at-least-once delivery. Los reintentos se reencolan sin backoff exponencial — el siguiente intento llega en cuestión de segundos, no minutos.

  • 5xx o error de red → BipBip reintenta (hasta maxRetries, default 3 intentos totales, configurable por endpoint)
  • 4xx → terminal, BipBip no reintenta
  • Timeout > 15s → trata el intento como fallo y reintenta
  • HTTP 200 sin remoteOrderId (solo creation) → trata como fallo y reintenta
  • Todos los reintentos llevan el mismo X-Bipbip-Delivery-Id — la deduplicación se hace con ese UUID

Reintentos agotados del creation

Si todos los intentos del webhook order.created fallan, BipBip cancela la orden internamente (notifica al cliente) y la orden nunca llega al POS. Los PUT /events que fallan tras todos los intentos se descartan — BipBip no expone un evento de fallo separado.

Endpoints

Tu POS expone estos dos endpoints. El segundo es un endpoint único de novedades — el tipo de evento se discrimina por body.event(cancelled, driver_assigned, driver_released, delivered).

event no es el estado de la orden

event dice qué pasó, no en qué estado quedó la orden. Solo cancelled y delivered tienen contraparte en el estado del recurso.

driver_assigned y driver_released pertenecen al ciclo del repartidor, que corre en paralelo al avance del comercio y no lo modifica. Una orden puede recibir un driver_assigned estando en preparing y quedarse en preparing.

Qué NO hacer: usar event para sobrescribir el estado interno de la orden salvo en esos dos casos. El estado del recurso se consulta con GET /api/v1/Orders/{orderKey} y nunca adopta un valor de repartidor.

POST/v1/order/{remoteId}

Recibir orden nueva

BipBip envía este webhook cuando se crea una orden. El POS verifica la firma HMAC, deduplica con X-Bipbip-Delivery-Id, persiste la orden y responde HTTP 200 con { remoteOrderId } en el body. El valor de remoteOrderId es obligatorio — BipBip lo usa para componer la URL de las actualizaciones siguientes.

Path parameters

remoteIdstringrequired
Identificador de la tienda en el POS (configurado durante onboarding). BipBip lo incluye en la URL para que el POS pueda enrutar a la sucursal correcta.

Headers (firmados por BipBip)

X-Bipbip-Signature-256stringrequired
HMAC-SHA256 sobre {timestamp}.{rawBody}, formato sha256=<hex>.
X-Bipbip-Timestampintegerrequired
Unix epoch en segundos. Rechazar si supera 300s (5 min) de skew con la hora actual del servidor.
X-Bipbip-Event-Typestringrequired
Siempre order.created en este endpoint.
X-Bipbip-Delivery-IdUUIDrequired
UUID único por dispatch. Mismo valor en todos los reintentos — usalo para deduplicación.

Body

(Order)Orderrequired
Payload JSON con los datos completos de la orden. Bajá al schema Order para ver el detalle de cada campo.

Returns — 200 OK (obligatorio)

remoteOrderIdstringrequired
ID interno del POS para esta orden. BipBip lo persiste y lo usa para componer la URL de los PUT /events posteriores.
PUT/v1/order/{remoteId}/{remoteOrderId}/events

Novedades de la orden

Endpoint único para todas las novedades posteriores a la creación. body.event discrimina entre cancelled, driver_assigned, driver_released y delivered. event indica qué ocurrió, no el estado del recurso: solo cancelled y delivered lo modifican. driver_assigned puede recibirse más de una vez por orden (reasignación de conductor). El POS DEBE tolerar valores desconocidos y responder 200 OK ignorándolos. Solo se invoca si el creation webhook respondió con éxito.

Path parameters

remoteIdstringrequired
Identificador de la tienda en el POS.
remoteOrderIdstringrequired
ID interno del POS, devuelto en la respuesta del creation webhook.

Headers (firmados por BipBip)

X-Bipbip-Signature-256stringrequired
HMAC-SHA256 sobre {timestamp}.{rawBody}.
X-Bipbip-Timestampintegerrequired
Unix epoch en segundos.
X-Bipbip-Schema-Versionstringrequired
Versión del schema del body. Actualmente 1.0. Versiones futuras lo incrementan y pueden traer campos top-level nuevos y valores nuevos de event.
X-Bipbip-Delivery-IdUUIDrequired
UUID único por dispatch para deduplicación.

Este endpoint no declara X-Bipbip-Event-Type

El spec lista solo los cuatro headers de arriba. Enrutá por body.event y no hagas que tu handler dependa de la presencia de X-Bipbip-Event-Type acá.

Body — discriminado por event

(OrderUpdateEvent)OrderUpdateEventrequired
Envelope unificado con discriminator event. Cuatro variantes: cancelled (lleva reason; modifica el estado), driver_assigned (lleva driver; puede repetirse; no modifica el estado), driver_released (lleva releasedDriver, reason, expectedNext; informativo, no modifica el estado), delivered (modifica el estado).

Returns — 200 OK

(body)any
Body de la respuesta es ignorado por BipBip. Lo único que importa es el código 200.

Ciclo de vida

Dos carriles en paralelo

El estado que reporta el comercio avanza lineal. La asignación del conductor no es un paso dentro de ese ciclo: corre en paralelo y no lo modifica. BipBip empieza a buscar conductor mientras la orden todavía está en preparing.

Estado de la orden (lo reporta el comercio)

pendingacceptedpreparingreadyhanded_over

Ciclo del repartidor (eventos, no estados)

driver_assigneddriver_released(informativo, sin rollback)driver_assigned(reasignación)delivered

Consecuencia práctica: driver_assigned puede llegar en cualquier momento antes de handed_over, incluso antes de que reportesready. No asumas un orden fijo entreready y driver_assigned.

driver_assigned puede llegar más de una vez

El operador BipBip puede reasignar el conductor antes de la entrega — y el sistema interno también puede rotar conductores automáticamente. Cada reasignación dispara un nuevo driver_assigned con los datos del conductor actualizado, mismo schema que el primero.

Qué hacer: mostrar siempre el conductor más reciente recibido. Qué NO hacer: idempotizar por orderKey + event y descartar el segundo evento — eso te deja mostrando un conductor que ya no es el correcto. Deduplicá por X-Bipbip-Delivery-Id.

El origen interno de la asignación (Auto / Operator / Driver hub) no viaja en el webhook — el payload es idéntico para los tres casos.

driver_released es informativo — NO hagas rollback de estado

Cuando llega driver_released, la orden lógicamente sigue en driver_assigned — no retrocede a ready ni a otro estado anterior.

Qué hacer: limpiar el conductor mostrado en la UI del POS y aguardar el próximo driver_assigned con el conductor nuevo. El campo expectedNext indica el próximo evento esperado (driver_reassignment).

delivered no te blinda contra un cancelled posterior

El evento cancelled puede llegar incluso después de delivered: un reembolso o una incidencia revierten una orden ya entregada.

Qué NO hacer: tratar la entrega como estado final que bloquee una cancelación posterior. De esa cancelación depende la conciliación del cobro.

Las actualizaciones están atadas al éxito del creation

Si el creation webhook (order.created) nunca llegó al POS con HTTP 200, BipBip no envía ningún PUT /events posterior para esa orden.

Forward compatibility — REQUERIDO

BipBip puede agregar valores nuevos a event y campos top-level extrasin incrementar la versión del schema. Tu POS debe:

  • Ignorar elegantemente valores de event que no reconozca → responder 200 OK.
  • No tratar campos top-level desconocidos como errores.

Webhook de cambios de menú

Un tercer endpoint, independiente del ciclo de la orden. BipBip lo llama cuando termina de aplicar un cambio de menú, y trae su propio event type: X-Bipbip-Event-Type: menu.change.completed.v1.

POST/v1/menu/change/{changeKey}

Recibir confirmación de un cambio de menú

BipBip llama este endpoint cuando termina de aplicar un cambio de menú. La aplicación es asíncrona y best-effort por tienda: status agrega el resultado total (applied, partial, failed) y results detalla cada par tienda+entidad. Es una notificación de resultado sin efecto colateral — si se agotan los reintentos, BipBip marca la entrega como fallida internamente pero NO revierte ni cancela ningún cambio ni orden. El POS verifica la firma HMAC, deduplica con X-Bipbip-Delivery-Id y responde 200 OK (body ignorado).

Cuándo dispara

Aplicación vía REST
Cuando BipBip termina de aplicar un cambio de menú que el comercio solicitó vía la REST API entrante (/api/v1/menu/...). El changeKey coincide con el changeId devuelto en el 202 Accepted previo.
Cambio del restaurante
Cuando el restaurante cambia la disponibilidad directamente (no vía API), BipBip mintea el changeKey automáticamente. El payload es idéntico en ambos casos. Podés consultar el estado del cambio con GET /api/v1/menu/changes/{changeKey}.

Path parameters

changeKeystringrequired
Identificador opaco del change request. Formato: chg_ seguido de 16 caracteres base62 (ej: chg_9mZ2kP7qR4tW1xYs). Coincide con el changeId del 202 Accepted previo cuando el cambio se solicitó vía REST.

Headers (firmados por BipBip)

X-Bipbip-Signature-256stringrequired
HMAC-SHA256 sobre {timestamp}.{rawBody}, formato sha256=<hex>.
X-Bipbip-Timestampintegerrequired
Unix epoch en segundos. Rechazar si supera 300s (5 min) de skew.
X-Bipbip-Event-Typestringrequired
Siempre menu.change.completed.v1 en este endpoint. Usalo para enrutar al handler correspondiente.
X-Bipbip-Schema-Versionstringrequired
Versión del schema del payload. Actualmente 1.0.
X-Bipbip-Delivery-IdUUIDrequired
UUID único por dispatch. Mismo valor en todos los reintentos — usalo para deduplicación.

Body

(MenuChangeCompletedWebhook)MenuChangeCompletedWebhookrequired
Resultado agregado del cambio (status) más el detalle por tienda (results). Bajá al schema MenuChangeCompletedWebhook para el detalle de cada campo.

Returns — 200 OK

(body)any
Body de la respuesta es ignorado por BipBip. Reintentos ante 5xx/red; 4xx terminal.

Notificación de resultado, sin efecto colateral

A diferencia de order.created —cuya falla total cancela la orden—, si se agotan los reintentos de este webhook, BipBip marca la entrega como fallida internamente pero no revierte ni cancela ningún cambio ni orden.

Los cambios ya aplicados permanecen aplicados; simplemente no habrás recibido la confirmación. Podés consultar el estado con GET /api/v1/menu/changes/{changeKey}.

Overrides por tienda de modifierOption: se persisten, pero hoy son no-op de cara al cliente

Cuando el cambio confirmado incluye price o name de un modifierOption a nivel de tienda, un resultado applied: true significa que BipBip persistió el override — pero la app de BipBip todavía no lo refleja al cliente final.

La REST API marca estos combos con pendingCustomerRollout: true en GET /api/v1/menu/capabilities.


Schema v1.0

Schemas

Definición de los cuerpos JSON que BipBip envía y del ACK esperado de vuelta. El headerX-Bipbip-Schema-Version: 1.0identifica esta versión. Los cambios aditivos (nuevos valores de status o campos opcionales) no la incrementan — los integradores existentes siguen funcionando si toleran valores desconocidos.

Cada schema declara los campos requeridos (required) y opcionales (optional). Los campos opcionales pueden ausentarse o adoptar el valor null según indique la descripción.

Order

Payload v1.0 que BipBip envía al POS al crearse una nueva orden (POST /v1/order/{remoteId}, X-Bipbip-Event-Type: order.created). Diseñado bajo el principio de minimización de datos: solo se incluyen los campos que el POS necesita para cocinar, facturar y cobrar la orden.

Identificación

orderKeystringrequired
Identificador opaco de la orden en BipBip. Formato: ord_ seguido de 16 caracteres base62. Debe utilizarse al invocar la REST API de BipBip para aceptar, rechazar o avanzar el estado de la orden.
displayCodestringrequired
Código de orden amigable mostrado al cliente en la app de BipBip. Útil para casos de soporte ("mi orden 355156479…"). No es único entre tiendas — combinar con storeRemoteId si se requiere unicidad global.
storeRemoteIdstringrequired
Identificador de la tienda. Corresponde al mismo valor configurado en el BackOffice de BipBip, reflejado en el path de la URL. Se incluye también en el body como defensa ante logs que truncan la URL.
currencystringrequired
Código ISO 4217 (ej: HNL).
createdAtISO-8601required
Timestamp UTC de creación de la orden en BipBip.
expiresAtISO-8601required
Deadline de aceptación. Si la orden no es aceptada antes de este timestamp, BipBip auto-cancela y notifica al comercio mediante webhook de cancelación.

Fulfillment & cliente

fulfillmentFulfillmentrequired
Tipo y tiempos de fulfillment. Discriminator: type = delivery | pickup.
typeenumrequired
delivery (conductor BipBip retira y entrega) | pickup (cliente acude a la tienda).
isExpressbooleanrequired
true si el cliente pagó delivery express → priorizar en cocina. Siempre false en pickup.
prepareByISO-8601required
Timestamp UTC en que la orden debe estar lista. La cocina programa contra este valor.
driverPickupAtISO-8601 | nulloptional
Cuándo el conductor BipBip llegará a retirar. Obligatorio si type=delivery; null en pickup.
customerPickupAtISO-8601 | nulloptional
Cuándo el cliente arribará a la tienda. Obligatorio si type=pickup; null en delivery.
customerCustomer | nulloptional
Información del cliente. Se popula únicamente en órdenes pickup para llamarlo al mostrador. En delivery, null.
firstNamestringrequired
Nombre de pila del cliente. Único campo en v1.0 — minimización de datos. Apellido y datos de contacto NO se exponen al comercio.

Pago y totales

paymentPaymentrequired
Métodos aplicados (combinables: cash + card + bips) y monto a cobrar en handover. La suma de methods[].amount equivale a summary.grandTotal.
methods[]PaymentMethod[]required
Lista de métodos. Cada uno con type (cash | card | bips) y amount.
amountToCollectdecimalrequired
Monto que el comercio debe cobrar al cliente en handover (suma de methods[].amount donde type requiere cobro al handover).
changeFordecimal | nulloptional
Si el cliente pagará en cash y necesita cambio, indica el billete con que pagará (e.g. cliente paga con 500, total 350 → changeFor: 500). null si no aplica.
summarySummaryrequired
Totales agregados destinados a conciliación rápida. Fórmula: grandTotal = subtotal + taxes − discounts + additionalCharges.
subtotaldecimalrequired
Suma de items[].lineTotal antes de impuestos y descuentos.
taxesdecimalrequired
Impuestos totales (suma de items[].tax).
discountsdecimalrequired
Suma de discounts[].amount aplicados a la orden.
additionalChargesdecimalrequired
Suma de charges[].amount (delivery_fee, service_fee, etc.).
grandTotaldecimalrequired
Total final que el cliente paga. Equivale a subtotal + taxes − discounts + additionalCharges.
charges[]Charge[]required
Cargos itemizados agregados a la cuenta del cliente. Array vacío si no aplica ninguno. Cada elemento es un objeto con los campos siguientes.
codeenumrequired
Tipo de cargo. Valores: delivery_fee, service_fee, driver_tip, otros (enum cerrado).
amountdecimalrequired
Monto del cargo.
billedByenumrequired
Quién factura: bipbip | merchant. Determina quién emite el documento fiscal por este cargo.
discounts[]Discount[]required
Descuentos aplicados a la orden. Array vacío si no hay descuentos. Cada descuento declara quién absorbe el costo.
codestringrequired
Identificador del descuento (e.g. "PROMO15", "first_order").
amountdecimalrequired
Monto del descuento.
fundedByenumrequired
Quién absorbe el costo: bipbip | merchant.

Líneas de la orden

items[]Item[]required
Líneas de producto de la orden. Cada item incluye precio, impuesto y modificadores. Mínimo 1.
codestring | nulloptional
Código interno del producto en BipBip. null cuando no exista mapeo BipBip.
remoteCodestring | nulloptional
Código del producto en el catálogo del POS. Fallback: usar code si remoteCode es null.
namestringrequired
Nombre del producto tal como lo ve el cliente.
quantityintegerrequired
Cantidad solicitada.
unitPricedecimalrequired
Precio unitario antes de impuestos y modificadores.
taxdecimalrequired
Impuesto aplicado a esta línea (no al unitPrice).
lineTotaldecimalrequired
Total de la línea: (unitPrice × quantity) + modificadores + tax.
notestring | nulloptional
Nota libre del cliente para esta línea (e.g. "sin cebolla").
modifierGroups[]ItemModifierGroup[]required
Grupos de modificadores aplicados al item. Array vacío si no hubo modificadores.

Notas y facturación

customerNotestring | nulloptional
Nota de texto libre del cliente para toda la orden (ej: "dejar en portería con el guardia, Apt 502"). Adopta el valor null si no existe nota.
invoiceInvoice | nulloptional
Datos para crédito fiscal. null cuando el cliente no lo solicitó (caso predominante: consumidor final).
taxIdstringrequired
RTN del cliente (registro tributario nacional).
businessNamestringrequired
Razón social asociada al RTN para emitir el crédito fiscal.

Fulfillment

Tipo y tiempos del fulfillment. El campo type discrimina la variante: delivery (el conductor de BipBip retira y entrega al cliente) o pickup (el cliente acude a la tienda). Cada variante popula uno solo de los dos timestamps de retiro.

Fields

typeenumrequired
Discriminador del fulfillment. delivery: el conductor de BipBip retira la orden y la entrega. pickup: el cliente acude a la tienda.
isExpressbooleanrequired
true si el cliente pagó delivery express → priorizar en cocina. Siempre false en pickup.
prepareByISO-8601required
Timestamp UTC en que la orden debe estar lista. La cocina programa contra este valor.
driverPickupAtISO-8601 | nulloptional
Cuándo el conductor BipBip llegará a retirar. Obligatorio si type=delivery; null en pickup.
customerPickupAtISO-8601 | nulloptional
Cuándo el cliente arribará a la tienda. Obligatorio si type=pickup; null en delivery.

Customer

Información mínima del cliente. Solo se incluye firstName para permitir al cajero llamar al cliente al mostrador ("Orden para Ana"). No se incluyen apellido, teléfono ni correo. Solo presente en órdenes pickup; en delivery, customer = null.

Fields

firstNamestringrequired
Nombre de pila del cliente. Único campo en v1.0 — minimización de datos.

Payment

Información de pago. El cliente puede combinar múltiples métodos en una sola orden (ej: 30 en Bips + 200 con tarjeta + 277 en efectivo). Convención: cash se cobra en handover; card y bips son pre-pagos en la app.

Fields

methods[]PaymentMethod[]required
Métodos aplicados (mínimo 1). La suma de methods[].amount equivale a summary.grandTotal.
typeenumrequired
Instrumento de pago: cash (cobro en handover), card (pre-pagado en app), bips (créditos de lealtad pre-pagados).
amountdecimalrequired
Monto pagado con este método.
amountToCollectdecimalrequired
Monto a cobrar por el comercio en handover. Equivale a la suma de methods[].amount donde type=cash. 0.00 si está completamente pre-pagada.
changeFordecimal | nulloptional
Billete con el cual el cliente tiene previsto pagar. Solo se incluye si hay un método cash. null si está completamente pre-pagada.

Summary

Totales agregados para conciliación rápida. Fórmula: grandTotal = subtotal + taxes − discounts + additionalCharges.

Fields

subtotaldecimalrequired
Suma de unitPrice × quantity de los items antes de impuestos. Constituye la línea de ingreso del comercio.
taxesdecimalrequired
Suma de tax × quantity de los items. Constituye los impuestos a remitir.
discountsdecimalrequired
Suma de discounts[].amount (valor positivo).
additionalChargesdecimalrequired
Suma de charges[].amount.
grandTotaldecimalrequired
Total que pagó el cliente. Equivale a la suma de payment.methods[].amount.

Charge

Cargo agregado a la cuenta del cliente. code es enum cerrado; códigos nuevos requieren bump mayor de schema con anuncio anticipado.

Fields

codeenumrequired
Tipo de cargo. Enum cerrado, valores: delivery_fee, express_fee, service_fee, driver_tip, small_order_fee.
amountdecimalrequired
Monto del cargo (valor positivo).
billedByenumrequired
Destinatario del cobro: bipbip (factura BipBip; no es ingreso del comercio) | merchant (ingreso del comercio).

Discount

Descuento aplicado a la orden. En v1.0 (MVP) BipBip emite una sola entrada con code: "GENERIC" cuando hay descuento; iteraciones futuras desglosarán cupones, lealtad, etc.

Fields

codestringrequired
Identificador. En v1.0 BipBip emite code=GENERIC genérico. Iteraciones futuras desglosarán cupones, niveles de lealtad, etc.
namestringrequired
Etiqueta visible del descuento.
amountdecimalrequired
Monto del descuento (valor positivo).
fundedByenumrequired
Quién absorbe el costo: bipbip (financia BipBip, comercio recibe precio completo) | merchant (financia el comercio, impacta su ingreso).

Invoice

Datos para crédito fiscal. Solo presente cuando el cliente ha solicitado factura con su RTN y razón social. Cuando está poblado, ambos campos son obligatorios. null en el caso predominante (consumidor final).

Fields

taxIdstringrequired
RTN del cliente (Honduras). Obligatorio para la emisión del crédito fiscal.
businessNamestringrequired
Razón social del cliente. Obligatoria para la emisión del crédito fiscal.

Item

Línea de producto. Cada item lleva el código del catálogo BipBip (code) y el del POS del comercio (remoteCode) — este último cae al valor de code si no se configuró.

Fields

codestringrequired
Código del producto en el catálogo de BipBip. Identificador estable y opaco. Si el producto fue registrado sin código en BipBip, puede estar vacío — tratarlo como señal de calidad de datos.
remoteCodestringrequired
Código del producto en el catálogo del POS del comercio, según configurado por la marca. Si no se configuró un remoteCode propio, este campo cae al valor de code (catálogo BipBip).
namestringrequired
Nombre visible del producto.
quantityinteger ≥ 1required
Cantidad ordenada.
unitPricedecimalrequired
Precio unitario antes de impuestos.
taxdecimalrequired
Monto de impuesto por unidad del item.
lineTotaldecimalrequired
Total de línea: (unitPrice + tax) × quantity + modificadores. Se provee para conciliación rápida; el POS puede recalcularlo localmente.
notestring | nulloptional
Instrucción libre del cliente para el item (e.g. "sin cebolla, extra salsa"). null si no existe nota.
modifierGroups[]ItemModifierGroup[]required
Grupos de modificadores aplicados al item. Array vacío si no se seleccionaron modificadores.

ItemModifierGroup & ModifierOption

Modificadores aplicados a un item. Los modificadores se agrupan por tipo (ej: "Extras", "Tipo de masa", "Bebida"). Cada grupo lleva al menos una opción seleccionada.

ItemModifierGroup

codestringrequired
Código del grupo de modificadores en el catálogo de BipBip.
namestringrequired
Nombre visible del grupo (e.g. "Extras", "Tipo de masa").
options[]ModifierOption[]required
Opciones seleccionadas dentro del grupo. Mínimo 1.
codestringrequired
Código de la opción en el catálogo de BipBip.
remoteCodestringrequired
Código de la opción en el catálogo del POS. Cae al valor de code si no se configuró un remoteCode propio.
namestringrequired
Nombre visible de la opción.
quantityinteger ≥ 1required
Cantidad de unidades seleccionadas.
unitPricedecimalrequired
Precio unitario de la opción. 0.00 cuando está incluida en el item base (e.g. upgrade sin costo).

OrderAck

Response del POS al webhook de creación. remoteOrderId es obligatorio: BipBip lo persiste y compone con él la URL de los status updates futuros. Respuestas sin este campo se consideran fallidas y se reintentan.

Fields

remoteOrderIdstringrequired
Identificador interno de la orden en el POS. BipBip lo almacena en integration_order.remote_order_id y lo usa para componer la URL del webhook de novedades (PUT /v1/order/{remoteId}/{remoteOrderId}/events). Las respuestas sin este campo se reintentan.

OrderUpdateEvent

Envelope unificado para todas las novedades de una orden. event discrimina el evento: cancelled, driver_assigned, driver_released, delivered. Los campos específicos (reason, driver, releasedDriver, expectedNext) solo aparecen en el evento correspondiente.

event describe qué ocurrió, no el estado del recurso

Los eventos de repartidor (driver_assigned, driver_released) no modifican el estado de la orden. Solo cancelled y delivered tienen contraparte en él.

Forward compatibility — REQUERIDO

BipBip puede incorporar eventos nuevos sin bump de schema. Tu POS debe responder 200 OK e ignorar valores desconocidos de event, y tolerar campos top-level desconocidos.

Fields

orderKeystringrequired
Identificador opaco de la orden en BipBip (formato ord_ + 16 chars base62). Puede usarse al invocar la REST API.
remoteOrderIdstringrequired
Identificador interno del POS, mismo valor devuelto en el OrderAck original. Se incluye por conveniencia; el path parameter es autoritativo.
eventenumrequired
Discriminador. Valores actuales: cancelled (lleva reason; modifica el estado), driver_assigned (lleva driver; puede repetirse por reasignación; no modifica el estado), driver_released (lleva releasedDriver, reason, expectedNext; informativo, sin rollback, no modifica el estado), delivered (modifica el estado). Pueden agregarse valores nuevos sin bump; ante un valor desconocido, responder 200 OK e ignorar.
occurredAtISO-8601required
Timestamp UTC del momento en que ocurrió la novedad.
reasonstring | nulloptional
Etiqueta del origen de la novedad. Poblada cuando event=cancelled (valores: customer_requested, operator_action, acceptance_timeout, delivery_failed) o cuando event=driver_released (valor: manual_release). Pueden agregarse nuevos sin bump — tratar informativamente.
driverOrderEventDriveroptional
Identidad del conductor asignado. Poblado cuando event=driver_assigned; ausente en los demás. Importante: este evento puede llegar más de una vez por orden — cada llegada trae el conductor actualizado y tu POS debe mostrar siempre el más reciente.
fullNamestringrequired
Nombre completo del conductor según registrado en BipBip.
phonestring | nulloptional
Teléfono en formato internacional. null si el driver no registró número o lo marcó privado.
releasedDriverOrderEventDriveroptional
Identidad del conductor liberado. Poblado únicamente cuando event=driver_released; ausente en los demás. Mismo tipo que driver (fullName requerido, phone opcional).
fullNamestringrequired
Nombre completo del conductor que fue liberado.
phonestring | nulloptional
Teléfono del conductor liberado. null si está privado.
expectedNextstring | nulloptional
Sugerencia del próximo evento esperado. Poblado únicamente cuando event=driver_released. Valor actual: driver_reassignment (BipBip está rotando al conductor; el siguiente driver_assigned traerá el nuevo). Pueden agregarse valores nuevos sin bump — tratar informativamente.

OrderEventDriver

Identidad de un conductor dentro de un OrderUpdateEvent. Es el tipo de driver (cuando event = driver_assigned) y también de releasedDriver (cuando event = driver_released). Ausente en los demás eventos. Puede recibirse más de una vez por orden — cada vez con los datos del conductor actualmente asignado.

Fields

fullNamestringrequired
Nombre completo del conductor según registrado en BipBip.
phonestring | nulloptional
Teléfono en formato internacional. null si el conductor no registró número o lo tiene marcado privado.

MenuChangeCompletedWebhook

Payload v1.0 que BipBip envía al finalizar la aplicación de un cambio de menú (POST /v1/menu/change/{changeKey}, X-Bipbip-Event-Type: menu.change.completed.v1). La aplicación es best-effort por tienda: results reporta el resultado individual de cada tienda y status agrega el total. Los campos anulables (errorCode, errorMessage) se omiten del JSON cuando su valor es null.

Fields

changeKeystringrequired
Identificador opaco del change request. Formato: chg_ + 16 caracteres base62. Coincide con el valor del path y con el changeId devuelto en el 202 Accepted de la solicitud original.
statusenumrequired
Resultado agregado. applied (éxito en todas las tiendas del change request), partial (algunas aplicaron y otras fallaron — ver results), failed (falló en todas).
submittedAtISO-8601required
Timestamp UTC de cuándo el comercio solicitó el cambio.
completedAtISO-8601required
Timestamp UTC de cuándo BipBip terminó de aplicar el cambio.
results[]MenuChangeResult[]required
Resultado individual por cada par (tienda, entidad) intentado. Un item por combinación de tienda y cambio del change request.
storeRemoteIdstringrequired
Tienda del comercio donde se intentó aplicar el cambio.
targetEntitystringrequired
Entidad del menú afectada. Valores en uso: product, modifierOption, localProduct.
targetCodestringrequired
Código de la entidad afectada en el catálogo.
appliedbooleanrequired
true si el cambio se aplicó con éxito en esta tienda; false si falló.
errorCodestring | nulloptional
Código de error estable cuando applied=false (ej: STORE_OFFLINE, PRODUCT_NOT_FOUND). Se omite del JSON en caso de éxito.
errorMessagestring | nulloptional
Mensaje legible que describe la causa del fallo cuando applied=false. Se omite del JSON en caso de éxito.

MenuChangeResult

Resultado de aplicar un cambio de menú a una tienda específica. errorCode y errorMessage se encuentran presentes únicamente cuando applied = false; se omiten del JSON en caso de éxito.

Fields

storeRemoteIdstringrequired
Identificador de la tienda del comercio donde se intentó aplicar el cambio. Corresponde al valor configurado en el BackOffice de BipBip.
targetEntitystringrequired
Entidad del menú afectada por el cambio. Valores en uso: product, modifierOption, localProduct.
targetCodestringrequired
Código de la entidad afectada en el catálogo.
appliedbooleanrequired
true cuando el cambio se aplicó con éxito en esta tienda; false cuando falló (en cuyo caso errorCode y errorMessage se encuentran poblados).
errorCodestring | nulloptional
Código de error estable, procesable por máquina, cuando applied = false (ej: STORE_OFFLINE, PRODUCT_NOT_FOUND). Se omite del JSON en caso de éxito.
errorMessagestring | nulloptional
Mensaje de error legible que describe la causa del fallo cuando applied = false. Se omite del JSON en caso de éxito.

MerchantErrorResponse

Shape sugerida para el body de respuesta de error del POS. BipBip solo toma en cuenta el código HTTP para decidir reintentos — el body es informativo. Se acepta cualquier shape JSON o body vacío; este schema busca consistencia entre comercios.

Fields (todos opcionales)

errorstringoptional
Código corto procesable por máquina (ej: invalid_payload, duplicate_delivery).
messagestringoptional
Mensaje legible para debugging.
timestampISO-8601optional
Momento de generación del error en el servidor del POS.