Merchant Integration API

Changelog

Cada entrada indica si el cambio requiere una acción de su parte. El contrato se mantiene en la versión 1.0; los cambios incompatibles se anuncian con antelación y nunca se aplican de forma silenciosa.

Última publicación: 12 de agosto, 2026Contrato v1.0

Cómo leer este changelog

Incompatible
Requiere un cambio de código.
Comportamiento
La forma del contrato no cambió, pero el significado sí; conviene revisar los supuestos de su POS.
Aditivo
Se agregó algo; su integración actual sigue funcionando sin cambios.
Filtrar por nivel

Mostrando 15 de 15 cambios

Incompatible

El discriminador del webhook de actualización pasa a llamarse event

El envelope unificado de los webhooks de actualización llamaba status a su discriminador, pero solo dos de sus cuatro valores son estados de la orden: cancelled y delivered. driver_assigned y driver_released pertenecen al eje del repartidor y nunca mueven la orden, de modo que un comercio leyendo status: "driver_assigned" quedaba invitado a sobrescribir su propio estado con un evento de repartidor.

El campo ahora se llama event y la ruta pasa de /status a /events, para que el path deje de prometer un estado que el cuerpo no transporta.

Los valores admitidos no cambian: cancelled, driver_assigned, delivered y driver_released. El conjunto sigue siendo extensible — un valor de event no reconocido debe ignorarse, y agregar uno nuevo no constituye un cambio incompatible.

Antes
PUT {baseUrl}/v1/order/{remoteId}/{remoteOrderId}/status

{ "orderKey": "ord_oOR7xSbWz0QksS2I", "status": "driver_assigned", ... }
Después
PUT {baseUrl}/v1/order/{remoteId}/{remoteOrderId}/events

{ "orderKey": "ord_oOR7xSbWz0QksS2I", "event": "driver_assigned", ... }

Acción requerida.

Cambiar la ruta del receptor a /events y leer el campo event en lugar de status. No hay ventana de transición ni campo duplicado: la ruta anterior deja de emitirse de inmediato.
Comportamiento

handedOverAt queda null cuando el comercio nunca reportó el handover

Si el comercio no declara el handover y BipBip cierra la orden al confirmarse la entrega, handedOverAt guardaba el instante de la entrega al cliente. La columna afirmaba entonces un momento que nadie observó: releída, una orden en la que el comercio quedó en silencio parecía haber sido entregada al repartidor exactamente cuando el cliente la recibió.

Ese hecho ahora vive en deliveredAt, así que handedOverAt puede decir lo honesto y quedarse en null.

Una orden cerrada por esa vía se lee con handedOverAt: null y deliveredAt poblado. No es un hueco en los datos: es la diferencia entre «no lo sabemos» y «ocurrió a esta hora».

Revisar.

Si su POS asume que una orden en handed_over siempre trae handedOverAt, debe contemplar el null. Una orden puede estar en estado terminal sin que se conozca el momento del handover.
Aditivo

deliveredAt indica cuándo el cliente recibió la orden

handed_over responde «¿terminó el comercio?» y no puede responder «¿la tiene el cliente?». En una orden delivery esos dos momentos están separados por el trayecto del repartidor: el comercio entrega la comida al repartidor, y el repartidor la entrega al cliente más tarde.

deliveredAt responde lo segundo, tanto en el detalle como en el listado, junto a driverAssignedAt. En pickup el cliente retira en la tienda, de modo que el handover del comercio es la entrega y el valor se deriva del tipo de fulfillment. Ambos canales obtienen un valor, así que en una orden creada a partir del 12 de agosto de 2026 null significa «todavía no hay entrega confirmada» y nunca «este canal no puede tener una».

Las órdenes anteriores a esa fecha devuelven null de forma permanente, incluso si fueron entregadas. El campo se incorporó sin completar los registros previos, porque ese momento no había quedado registrado en ninguna parte: no existía dato que copiar.

Revisar.

Campo nuevo en GET /orders y en GET /orders/{orderKey}. Si concilia un período que incluya el 12 de agosto de 2026, no lea null como «no se entregó» en las órdenes anteriores a esa fecha: para ellas handed_over sigue siendo el único indicio de cierre.

Incompatible

El repartidor deja de ser un estado de la orden

El estado driver_assigned fue retirado de la máquina de estados. Una orden nunca reporta ese valor en status, y GET /orders dejó de aceptarlo como filtro. La asignación del repartidor corre en paralelo al avance del comercio y ahora se expone en el campo driverAssignedAt.

Acción requerida.

Si su POS filtraba por status=driver_assigned o comparaba contra ese valor, debe leer driverAssignedAt en su lugar. A cambio, ahora es posible marcar ready con un repartidor ya asignado, algo que antes se rechazaba con 409.
Comportamiento

Una orden entregada todavía puede cancelarse

Una orden en estado handed_over puede pasar a cancelled: un reembolso o una incidencia posterior a la entrega la cierran en ese estado y el comercio recibe el webhook correspondiente. Anteriormente esas cancelaciones no se notificaban.

Revisar.

Si su POS asumía que handed_over era un estado final absoluto, debe contemplar la recepción de un webhook event: "cancelled" con posterioridad.
Comportamiento

El motivo de cancelación del cliente viaja en texto

En las cancelaciones originadas por el cliente, history[].reason informa el motivo en texto. Anteriormente informaba únicamente su identificador numérico, que fuera de BipBip no significaba nada: el comercio recibía la cancelación sin poder decir por qué ocurrió.

Si el cliente escribe un comentario, viaja ese comentario; si no lo escribe, viaja el nombre del motivo que seleccionó. Las órdenes canceladas antes de este cambio conservan el identificador numérico.

Sin acción.

reason es texto descriptivo destinado a lectura humana y su contenido no es estable. No lo parsee ni derive lógica de él.
Comportamiento

GET /orders ordena por número de orden

El criterio anterior era el momento en que BipBip registró la orden, que puede diferir del orden real de creación y situar una orden antigua por encima de una más reciente. El cursor de paginación es ahora ese mismo número.

Sin acción.

La paginación por cursor sigue operando de forma idéntica.
Comportamiento

Una orden puede pasar a ready sin que el comercio lo solicite

El estado ready deja de depender exclusivamente de PUT /orders/{orderKey}/status. El repartidor marca la orden como lista desde su propia aplicación, y ese registro también la avanza.

En consecuencia, un PUT con status: "ready" puede responder 409 sobre una orden que el comercio todavía no había avanzado. Ese 409 no describe un conflicto: describe un estado ya alcanzado, y meta lo dice con todas las letras.

Respuesta 409
PUT {baseUrl}/api/v1/Orders/{orderKey}/status   →   409

{ "status": 409, "meta": { "currentStatus": "Ready", "allowedTransitions": ["HandedOver"] } }

Revisar.

Si su POS asume que solo él lleva la orden a ready, debe tratar un 409 con meta.currentStatus: "Ready" como estado ya alcanzado y continuar con handed_over, en lugar de considerarlo un error.
Aditivo

El listado indica si la orden tiene repartidor

Cada elemento de GET /orders incluye driverAssignedAt, con el momento en que se asignó un repartidor a la orden, o null si todavía no tiene uno. Con status por sí solo no era posible distinguir una orden lista en espera de repartidor de una lista con repartidor en camino.

Sin acción.

Campo nuevo en la respuesta.
Aditivo

El repartidor se identifica por su código

Los elementos de history[] relativos al repartidor incorporan el objeto driver con el campo code (por ejemplo BIP-01424), que es el identificador utilizable ante el soporte de BipBip. Los eventos driver_assigned, driver_reassigned y driver_released se distinguen mediante driver.event.

Cuando el repartidor no tiene un código cargado, code informa su identificador numérico. El campo es siempre una cadena de texto y su formato no es estable, de modo que no debe validarse contra el patrón BIP-#####.

Sin acción.

Campo nuevo dentro de history[]. Trátelo como opaco: es una etiqueta, no un número.

Comportamiento

Los productos locales reciben un código canónico

Al crear un producto local, BipBip deriva su propio código interno y preserva el código del comercio en remoteCode. Anteriormente el código enviado se utilizaba como código interno y el del comercio se perdía.

Las llamadas posteriores admiten cualquiera de los dos códigos, de modo que el comercio puede seguir direccionando el producto con el suyo.

Sin acción.

Los productos locales creados con anterioridad conservan su código original y se siguen resolviendo sin cambios.
Aditivo

El detalle de la orden devuelve su contenido completo

GET /orders/{orderKey} incorpora el objeto order con el contenido comercial de la orden: productos, modificadores, medios de pago, cargos, descuentos y datos de facturación. Su estructura es la misma del webhook order.created, de modo que puede interpretarse con el modelo ya implementado para ese webhook.

Opcional, recomendado.

Permite recuperar una orden cuyo webhook no pudo ser procesado, sin depender de un reenvío.