# BipBip Merchant Integration API — Quickstart ## Overview The BipBip Merchant Integration API has two surfaces that work together. The **REST inbound API** (POS calls BipBip) lets the merchant's point-of-sale system accept or reject orders, advance order status, query order data, and keep the menu catalog in sync — availability, prices, per-entity edits, and full catalog publishing. The **webhook outbound API** (BipBip calls POS) delivers new orders and lifecycle events to the merchant's server. Neither surface is optional: webhooks are how orders arrive; the REST API is how the POS responds to them. The REST API is split into `/api/v1/Orders` (5 endpoints) and `/api/v1/menu` (13 endpoints). API spec version: 2.4.0. Payload schema version: 1.0 (carried in `X-Bipbip-Schema-Version`). ## Base URLs | Environment | URL | |-------------|-----| | Staging | `https://merchant-api.bipbip.dev` | | Production | `https://merchant-api.bipbip.hn` | Both environments require TLS on port 443. BipBip does not publish a fixed IP allowlist. If your security policy requires a static allowlist or private network path (e.g., AWS PrivateLink), contact `support@cit.hn`. ## REST API Authentication Headers All requests from the POS to BipBip must include: ``` X-Bipbip-Api-Key: ``` Mutation requests (POST, PUT, PATCH) additionally require: ``` Idempotency-Key: X-Bipbip-Schema-Version: 1.0 Content-Type: application/json ``` - `Idempotency-Key` must be a UUID v4, unique per logical attempt. Missing key returns 422. - `X-Bipbip-Schema-Version` must be `1.0`. Missing or unsupported value returns 400. - The contract publishes `/api/v1/Orders` with a capital `O` and `/api/v1/menu` in lowercase. Use the exact casing documented per endpoint. ## End-to-End Happy Path 1. **Onboarding**: BipBip team provisions an API key and configures your webhook base URL and per-store `remoteId` in the Merchant Portal. 2. **Order arrives** (BipBip calls your server): ``` POST {yourBaseUrl}/v1/order/{remoteId} ``` Your server validates the HMAC signature, deduplicates on `X-Bipbip-Delivery-Id`, persists the order, and responds: ```json { "remoteOrderId": "" } ``` BipBip stores `remoteOrderId` and uses it to route all subsequent updates to the right order. 3. **Accept the order** (your POS calls BipBip): ``` POST https://merchant-api.bipbip.hn/api/v1/Orders/{orderKey}/accept Body: {} ``` BipBip atomically transitions `pending → accepted → preparing`. Response returns `status: "Preparing"`. Do not call `PUT /status` with `preparing` after this — it will return 409. 4. **Advance status as food is prepared** (your POS calls BipBip): ``` PUT https://merchant-api.bipbip.hn/api/v1/Orders/{orderKey}/status Body: { "status": "ready" } ``` Then again with `"handed_over"` when the driver or customer picks up. 5. **Order updates arrive** (BipBip calls your server): ``` PUT {yourBaseUrl}/v1/order/{remoteId}/{remoteOrderId}/events ``` Body field `event` is one of `driver_assigned`, `driver_released`, `delivered`, or `cancelled`. Always respond `200 OK`. `event` is not the order status: only `cancelled` and `delivered` change it. Driver events run in parallel with steps 3–4, so `driver_assigned` can arrive while the order is still `preparing` — do not assume it comes after `ready`. If you would rather resolve delivery by asking instead of waiting for the event, `GET /api/v1/Orders/{orderKey}` and the order listing both report `deliveredAt`. `status` alone cannot answer it: an order in transit and a delivered one both read `HandedOver`. ## Menu Sync Independent of the order flow. Writes are asynchronous: they return `202 Accepted` with a `changeId`, and the outcome is checked with `GET /api/v1/menu/changes/{changeId}` or the `menu.change.completed.v1` webhook. - Day-to-day: `PUT /api/v1/menu/availability` and `PUT /api/v1/menu/prices` (store scope). - Targeted edits: `PATCH /api/v1/menu/products/{code}`, `/modifier-options/{code}`, `/categories/{code}`, `/modifiers/{code}`. - Full catalog: `POST /api/v1/menu/preview` (dry-run) then `PUT /api/v1/menu` (synchronous; **omitted items are deactivated**). - Reads: `GET /api/v1/menu/stores/{storeRemoteId}`, `GET /api/v1/menu/capabilities`. A `202` does not mean the change was applied — the real outcome is per store, in `results[].applied`. Query `GET /api/v1/menu/capabilities` before building on a field: only shipped `(entity, field, scope)` combinations are accepted; the rest return 422. ## Support Email: `support@cit.hn`