Skip to content

For developers

Bottle’s web and driver apps use the same API available to integrations.

An API key belongs to a business and has a fixed set of permissions. It remains valid if its creator leaves. Use it for server-to-server integrations such as accounting syncs.

An OAuth connection belongs to a person and is limited to their approved permissions. Access ends when their business membership ends. Use it for an assistant acting on their behalf. See Connecting over MCP.

Both authentication methods use the same permissions.

The API speaks JSON over HTTPS. Every tenant-scoped request needs a business: an API key names its own, and a session sends X-Tenant-Id.

Terminal window
curl https://api.bottle.example/customers \
-H "Authorization: Bearer btl_7f3a9c21_..."

Errors include a stable error code and a display message:

{ "error": "missing_scope", "message": "This needs the customers:write permission, ..." }

Handle errors by code. Display messages may change or be translated.

The API reference is generated from the server’s /openapi.json document.

A write may succeed even if its response is lost. Send an Idempotency-Key header so a retry does not repeat the change.

Terminal window
curl -X POST https://api.bottle.example/customers \
-H "Authorization: Bearer btl_7f3a9c21_..." \
-H "Idempotency-Key: 0192c7d4-5e1f-7a3b-9c2d-8e4f6a1b3c5d" \
-H "Content-Type: application/json" \
-d '{"tradingName": "The Anchor"}'
  • The first request with a key does the work. The same request with the same key gets the first answer back, with Idempotent-Replayed: true, and changes nothing.
  • A key is 8 to 100 letters, digits, dots, colons, dashes or underscores. A UUID made fresh for each write is ideal.
  • Keys belong to whoever sent them, in one business, and are kept for a week.
  • The same key on a different request is refused with idempotency_key_reused. One that arrives while the first is still being worked on gets idempotency_in_progress: wait a moment and send it again.
  • An answer that went wrong on our side (a 5xx) is not kept, so sending it again really does try again.

Delivery and cash records accept an optional occurredAt: an ISO timestamp including its time-zone offset. This preserves the event time when a phone syncs after working offline.

Bottle accepts timestamps up to three days in the past or two minutes in the future. Missing or out-of-range timestamps use the server’s receipt time.