Outbound · You implement it
Webhook Spec
This document describes the outbound contract BipBip uses to deliver new orders to your POS. It is the endpoint that your system must implement and expose so BipBip can call it.
This is the counterpart to the REST API
Transport contract
Fixed transport contract — these parameters are non-negotiable and are not customized per merchant.
| Parameter | Value |
|---|---|
| Creation path | POST {yourBaseUrl}/v1/order/{remoteId} |
| Events path (multiplexed) | POST {yourBaseUrl}/v1/order/{remoteId}/{remoteOrderId} |
| Events on this path | order.cancelled, order.driver_assigned, order.delivered — distinguish by X-Bipbip-Event-Type |
| Versioning | In the path (/v1/) — future versions can run in parallel |
| Body | JSON — Order, OrderCancellation, OrderDriverAssigned, OrderDelivered schemas |
| Timeout | 30 seconds per attempt |
| ACK (creation) | HTTP 200 with { remoteOrderId } — required |
| ACK (events) | HTTP 200 — body ignored |
Signed headers
BipBip signs each request with HMAC-SHA256 over {timestamp}.{rawBody}
using the shared secret provided during onboarding. See the HMAC verification guide for the full algorithm and code samples.
| Header | Description |
|---|---|
| X-Bipbip-Signature-256 | HMAC-SHA256 in sha256=<hex> format (lowercase) |
| X-Bipbip-Timestamp | Unix epoch in seconds. Reject if skew exceeds 300s. |
| X-Bipbip-Event-Type | order.created, order.cancelled, order.driver_assigned, or order.delivered — use it to route to the correct handler |
| X-Bipbip-Delivery-Id | Unique UUID per dispatch. Use for deduplication. |
Retry policy
BipBip implements at-least-once delivery with exponential backoff.
- 5xx or network error → BipBip retries (up to
maxRetries, default 5) - 4xx → terminal, BipBip does not retry
- Timeout > 30s → treats the attempt as a failure and retries
- HTTP 200 without remoteOrderId → treats as failure and retries
- All retries carry the same
X-Bipbip-Delivery-Id— deduplicate using that UUID
If retries are exhausted
order.cancelled webhook is sent (if the creation webhook ever reached your POS).
Endpoints
Your POS must expose these two endpoints. The second path multiplexes three event types — use the
X-Bipbip-Event-Type
header to route to the correct handler.
/v1/order/{remoteId} Delivery of a new order (order.created). Verify the HMAC signature, deduplicate with X-Bipbip-Delivery-Id, persist the order in your POS, and respond HTTP 200 with { remoteOrderId } in the body. The remoteOrderId value is required — BipBip uses it to compose the URLs of subsequent events.
Example Response
{
"remoteOrderId": "POS-2026-04-11-00142"
} /v1/order/{remoteId}/{remoteOrderId} Subsequent order events — multiplexes three types based on X-Bipbip-Event-Type: order.cancelled (cancel the order in your POS), order.driver_assigned (driver assigned, informational: optionally update your operational view), order.delivered (delivered to customer, terminal: mark as delivered). Verify HMAC, process the event, and respond HTTP 200 (body ignored). Only sent if the creation webhook was delivered successfully.
Subsequent events depend on creation success
order.created) never reached your POS with HTTP 200,
BipBip will not send any of the subsequent events (cancelled,
driver_assigned,
delivered) for that order.
Schemas
The JSON bodies BipBip sends and the ACK it expects in return.
Order
Payload sent by BipBip on POST /v1/order/{remoteId}
(eventType order.created).
| Field | Type | Description |
|---|---|---|
| orderKey | string | Opaque BipBip identifier (ord_ + 16 base62) |
| eventType | enum | Always order.created |
| occurredAt | ISO-8601 | UTC timestamp of the event |
| correlationId | uuid | Trace ID for support and logging |
| customer | object | fullName, phone |
| delivery | object | address, latitude?, longitude? |
| totals | object | total, subTotal, taxes, deliveryCharge |
| items[] | array | productCode, name, quantity, price, tax, modifiers[] |
| comment | string? | Customer note (may be null) |
| dateDelivery | ISO-8601 | Target delivery time |
Full example
{
"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 sent by BipBip on POST /v1/order/{remoteId}/{remoteOrderId}
when a customer cancels an order.
| Field | Type | Description |
|---|---|---|
| orderKey | string | BipBip order identifier |
| remoteOrderId | string? | The value you returned in the original ACK (also present in the path) |
| cancelReasonId | integer? | Cancellation reason (informational, may be null) |
| previousStatus | enum | Pending / Accepted / Preparing / Ready / DriverAssigned / Unknown |
| origin | enum | Who cancelled: Customer (end customer), Operator (BackOffice operator), Timeout (your POS did not accept in time), or WebhookDlq (BipBip exhausted creation retries) |
| operatorUserName | string? | BackOffice operator username — only present when origin = Operator |
| occurredAt | ISO-8601 | UTC timestamp of the cancellation |
Example
{
"orderKey": "ord_7h3nXpQa2KvLmN9F",
"remoteOrderId": "POS-2026-04-11-00142",
"cancelReasonId": 3,
"previousStatus": "Pending",
"origin": "Customer",
"occurredAt": "2026-04-11T15:52:00Z"
} OrderDriverAssigned
Payload sent by BipBip on POST /v1/order/{remoteId}/{remoteOrderId}
with X-Bipbip-Event-Type: order.driver_assigned
when a driver has been assigned to pick up the order. Informational — the order remains in its active state; no action required beyond optionally updating your operational view.
| Field | Type | Description |
|---|---|---|
| orderKey | string | BipBip order identifier |
| remoteOrderId | string | The value you returned in the original ACK (also present in the path) |
| driver.id | integer | Numeric BipBip driver identifier |
| driver.fullName | string | Driver's full name |
| driver.phone | string? | International phone number — may be null if unregistered or marked private |
| assignedAt | ISO-8601 | UTC timestamp when the driver was assigned |
Example
{
"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 sent by BipBip on POST /v1/order/{remoteId}/{remoteOrderId}
with X-Bipbip-Event-Type: order.delivered
when the order has been delivered to the customer. Terminal state — mark the order as delivered in your POS.
| Field | Type | Description |
|---|---|---|
| orderKey | string | BipBip order identifier |
| remoteOrderId | string | The value you returned in the original ACK (also present in the path) |
| deliveredAt | ISO-8601 | UTC timestamp when the order was delivered to the customer |
Example
{
"orderKey": "ord_7h3nXpQa2KvLmN9F",
"remoteOrderId": "POS-2026-04-11-00142",
"deliveredAt": "2026-04-11T16:18:30Z"
} OrderAck
Your response to the creation webhook. Required field: remoteOrderId.
{
"remoteOrderId": "POS-2026-04-11-00142"
} Without remoteOrderId, BipBip retries
remoteOrderId null, empty, or absent
are treated as a failed delivery. BipBip will retry until maxRetries is exhausted.