Inbound · You call it

REST API Reference

Your POS calls BipBip to accept, reject, advance the status, and query orders. This is the counterpart of the Webhook Spec: once BipBip delivers an order to you, use this API to manage its lifecycle.

Base URL

All endpoints are relative to https://api.bipbip.com. Paths carry the prefix /api/v1/ with versioning in the path.

Authentication

Every request must include the X-Bipbip-Api-Key header with the value provided by the BipBip team during onboarding. We do not use Bearer tokens or OAuth for this API. To obtain your API Keys, reach out to the BipBip team at [email protected].

# Every call must include this header
curl -H "X-Bipbip-Api-Key: <your-api-key>" \
     https://api.bipbip.com/api/v1/Orders/<orderKey>

Protect your API Key

Do not expose it in the frontend, in public repositories, or in client-side bundles. Store it in server-side environment variables and never commit it.

Case-sensitive paths

The server does not normalize casing. The segment /Orders/ must use a capital O literally — /orders/ returns 404. Use the exact casing of each path documented here.

Idempotency-Key

All mutations (/accept, /reject, /status) require the Idempotency-Key header. The value must be a unique UUID v4 per logical attempt.

  • Same key + same body within 24h → BipBip returns the cached response without re-executing.
  • Same key + different body → HTTP 409 Conflict.
  • New key → request processed normally.
  • Missing header on mutations → HTTP 422 Unprocessable Entity.
{
  "type": "https://errors.bipbip.com/idempotency-conflict",
  "title": "Idempotency conflict",
  "detail": "Idempotency-Key reused with a different request body.",
  "status": 409,
  "traceId": "00-abc...",
  "meta": null
}

Rate limits

Limits are applied per API Key and are active on all endpoints. If exceeded, you receive HTTP 429 — implement exponential backoff with jitter in your client.

Window Limit Strategy
Fixed window 100 requests / min Resets every 60s
Sliding window 1,000 requests / hour Evaluated continuously

Errors

The API follows the RFC 7807 Problem Details format. All errors return a JSON body with the fields type, title, detail, status, traceId and meta. For validation errors (422), meta includes a field → message list map.

Code Meaning
401 Unauthorized Missing or invalid API Key
404 Not Found orderKey does not exist or does not belong to the authenticated client
409 Conflict Idempotency-Key reused with a different body, order in wrong state for the transition, or invalid transition
422 Unprocessable Entity Invalid data in the body or missing Idempotency-Key header. The meta.errors field details the problematic fields.
429 Too Many Requests Rate limit exceeded — implement exponential backoff with jitter
5xx Server error — retry with backoff

Generic error (401, 404, 409, 429)

{
  "type": "https://errors.bipbip.com/not-found",
  "title": "Order not found",
  "detail": "The order ord_xxx does not exist or does not belong to the authenticated client.",
  "status": 404,
  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
  "meta": null
}

Validation error (422)

{
  "type": "https://errors.bipbip.com/validation",
  "title": "Validation failed",
  "detail": "One or more validation errors occurred.",
  "status": 422,
  "traceId": "00-abc...",
  "meta": {
    "errors": {
      "reasonCode": ["The ReasonCode field is required."]
    }
  }
}

Orders

Manage the lifecycle of orders delivered to you by BipBip via webhook. Mutation endpoints require X-Bipbip-Api-Key and Idempotency-Key.

POST /api/v1/Orders/{orderKey}/accept

Accept an order after responding HTTP 200 to the creation webhook. Transitions the order from pending to accepted, cancels the acceptance timeout job, and publishes the order.accepted_by_external_merchant.v1 event. Body: { remoteOrderId?, estimatedPrepTimeMinutes? }. Idempotent: same Idempotency-Key + same body → cached response. Returns 202.

Example Response
{
  "message": "Order accepted",
  "data": {
    "orderKey": "ord_7h3nXpQa2KvLmN9F",
    "status": "accepted",
    "acceptedAt": "2026-04-11T15:44:12Z",
    "remoteOrderId": "POS-2026-04-11-00142"
  }
}
POST /api/v1/Orders/{orderKey}/reject

Reject an order you can't fulfill. Transitions the order from pending to rejected (terminal). Requires a reasonCode (int). Body: { reasonCode*, reason?, notes? }. Use standard codes like OUT_OF_STOCK, STORE_CLOSED, or TOO_BUSY. Publishes order.rejected_by_external_merchant.v1. Idempotent. Returns 202.

Example Response
{
  "message": "Order rejected",
  "data": {
    "orderKey": "ord_7h3nXpQa2KvLmN9F",
    "status": "rejected",
    "rejectedAt": "2026-04-11T15:44:30Z",
    "reason": "Producto agotado"
  }
}
POST /api/v1/Orders/{orderKey}/status

Advance the state of an accepted order. Valid transitions: accepted → preparing → ready → handedOver. Also allows cancellation (→ cancelled). Body: { newStatus* (MerchantStatus: pending/accepted/rejected/preparing/ready/handedOver/cancelled/driverAssigned), estimatedReadyAt? }. Once Ready, BipBip dispatches to the driver automatically. Publishes order.status_changed_by_external_merchant.v1. Returns 202.

Example Response
{
  "message": "Status updated",
  "data": {
    "orderKey": "ord_7h3nXpQa2KvLmN9F",
    "status": "preparing",
    "changedAt": "2026-04-11T15:47:00Z"
  }
}
GET /api/v1/Orders/{orderKey}

Query the current state of an order by its orderKey. Returns the full order snapshot: current status, timestamps for each transition (receivedAt, acceptedAt?, rejectedAt?, preparingAt?, readyAt?, driverAssignedAt?, handedOverAt?, cancelledAt?) and complete change history. Only returns orders belonging to the authenticated client. Does not require Idempotency-Key (read-only). Returns 200.

Example Response
{
  "message": "Ok",
  "data": {
    "orderKey": "ord_7h3nXpQa2KvLmN9F",
    "storeId": 42,
    "brandId": 7,
    "status": "preparing",
    "merchantStatusReason": null,
    "remoteOrderId": "POS-2026-04-11-00142",
    "receivedAt": "2026-04-11T15:42:00Z",
    "acceptedAt": "2026-04-11T15:44:12Z",
    "rejectedAt": null,
    "preparingAt": "2026-04-11T15:47:00Z",
    "readyAt": null,
    "driverAssignedAt": null,
    "handedOverAt": null,
    "cancelledAt": null,
    "history": [
      {
        "fromStatus": null,
        "toStatus": "pending",
        "changedAt": "2026-04-11T15:42:00Z",
        "actorType": "system",
        "actorId": null,
        "reason": null
      }
    ]
  }
}
GET /api/v1/Orders

List orders for the authenticated client with opaque cursor pagination. Query params: Cursor?, PageSize? (max 100), Status?, FromDate?, ToDate?. Ordered by creation date descending. Pass nextCursor from the previous response to fetch the next page. Returns 200.

Example Response
{
  "message": "Ok",
  "data": {
    "items": [
      {
        "orderKey": "ord_7h3nXpQa2KvLmN9F",
        "storeId": 42,
        "status": "preparing",
        "receivedAt": "2026-04-11T15:42:00Z",
        "acceptedAt": "2026-04-11T15:44:12Z",
        "remoteOrderId": "POS-2026-04-11-00142"
      }
    ],
    "nextCursor": "eyJsYXN0SWQiOjE3fQ",
    "hasMore": true
  }
}

State machine

Valid transitions from the REST API are: pendingaccepted / rejected, acceptedpreparing, preparingreadyhandedOver. The driverAssigned state is set automatically by BipBip between ready and handedOver (the merchant does not transition to this state, only reads it). See the glossary for details. Note: status values in the REST API are camelCase lowercase (e.g. handedOver, driverAssigned), unlike webhooks which use PascalCase.