Developer Overview
Mulabbe gives developers two ways to build on top of the platform:
- The REST API (v1) — read and write conversations, contacts, products, orders and usage from your own backend.
- Webhooks — receive signed HTTP notifications when something happens in your workspace, such as a new message or a new order.
There is also an embeddable website chat widget that adds the assistant to any web page with one script tag. See the widget guide for that.
Base URL
All REST API requests go to:
https://api.<your-domain>/api/v1
Every path in this documentation is relative to this base URL. For example, "List conversations" is:
GET https://api.<your-domain>/api/v1/conversations
Authentication
Every request must carry an API key in the Authorization header:
curl https://api.<your-domain>/api/v1/conversations \
-H "Authorization: Bearer wk_live_..."
Keys are created in the dashboard under Settings → Developers. There are two kinds:
wk_live_...— a live key. It acts on your real channels and data.wk_test_...— a test key. It can read everything, but it may only write to conversations on sandbox channels. Writing to a live channel with a test key returns403with the codetest_key_live_channel.
Each key carries a list of scopes, and each route requires exactly one scope. See API keys for details.
Versioning
- The API version is part of the path:
/api/v1. Breaking changes will only ever appear under a new version prefix. - Webhook payloads carry their own shape version in the
apiVersionfield (currently2026-10-01).
Requests and responses
- Requests and responses are JSON (
application/json), encoded as UTF-8. - Request bodies are validated strictly: unknown fields are rejected with a
400validation error. - Errors are returned as
application/problem+jsondocuments. See Errors. - List endpoints use cursor pagination and return
{ "items": [...], "nextCursor": "..." }. See Pagination. - Money is always an integer amount in minor units (for example
12550for 125.50 SAR) together with an ISO currency code. The API never uses floating-point money.
Rate limits
Each API key has its own token bucket (by default 10 requests per second with a burst of 50; both are configurable per key). Every response — including refusals — carries these headers:
| Header | Meaning |
|---|---|
RateLimit-Limit | The bucket size (burst capacity). |
RateLimit-Remaining | Tokens left right now. |
RateLimit-Reset | Seconds until the bucket is full again. |
RateLimit-Policy | The policy as <burst>;w=<window seconds>. |
When the bucket is empty the API answers 429 with the code rate_limited, a retry_after field (in seconds) and a Retry-After header. Back off and retry after that delay.
Idempotent writes
POST and PATCH endpoints accept an optional Idempotency-Key header (1–255 visible ASCII characters). When you retry a request with the same key:
- The first successful response is stored for 24 hours.
- A retry with the same key and the same request returns the stored response again, with the header
Idempotent-Replayed: true, without running the operation twice. - The same key with a different request is rejected with
422and the codeidempotency_key_reused. - Failed requests are not stored, so a retry after an error runs normally.
Use a fresh random value (for example a UUID) per logical operation, and reuse it only for retries of that operation.
OpenAPI document
A machine-readable OpenAPI 3.1 description of the whole API is public at:
GET https://api.<your-domain>/api/v1/openapi.json
The same reference is rendered inside the dashboard under Settings → Developers. You can import the document into tools such as Postman or use it to generate a client.
Where to go next
- API keys — create a key, pick scopes, rotate safely.
- API reference — every endpoint with its method, path and required scope.
- Webhooks — subscribe to events and verify signatures.
- Errors — the error format and common error codes.
- Pagination — how cursors work.
- Website chat widget — embed the assistant on your site.