The REST API
Call every v1 resource with the right scope, page through lists and handle every error it returns.
Updated 23 September 2026
On this page
- Why
- Your own systems should read what your team works on and write what they are allowed to, without anyone copying data.
- What
- REST over HTTPS at
https://kabaido.ai/api/v1, scoped to your organisation by the key, with money in integer minor units. - How
- Create a scoped key, then call the routes below with an
Authorization: Bearerheader.
The machine readable description is the OpenAPI document at https://kabaido.ai/api/v1/openapi.json (version 1.0.0).
Resources
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /api/v1/products | products:read | List products |
| POST | /api/v1/products/bulk | products:write | Bulk upsert products |
| GET | /api/v1/quotes | quotes:read | List quotes |
| GET | /api/v1/quotes/{id} | quotes:read | Get a quote with lines |
| GET | /api/v1/orders | orders:read | List orders |
| GET | /api/v1/orders/{id} | orders:read | Get an order with lines |
| GET | /api/v1/stock/lines | stock:read | List stock lines |
| GET | /api/v1/stock/lines/{id} | stock:read | Get a stock line with its movements |
| GET | /api/v1/stock/locations | stock:read | List stock locations |
| GET | /api/v1/stock/movements | stock:read | List stock movements |
| POST | /api/v1/stock/movements | stock:write | Record a stock movement |
| GET | /api/v1/deliveries | deliveries:read | List deliveries |
| GET | /api/v1/deliveries/{id} | deliveries:read | Get a delivery with its lines and packages |
| GET | /api/v1/suppliers | suppliers:read | List suppliers |
| GET | /api/v1/suppliers/{id} | suppliers:read | Get a supplier with contacts |
| GET | /api/v1/purchase-orders | purchase_orders:read | List purchase orders |
| GET | /api/v1/purchase-orders/{id} | purchase_orders:read | Get a purchase order with lines and receipts |
| GET | /api/v1/customers | customers:read | List customers |
| POST | /api/v1/customers | customers:write | Upsert customers |
| GET | /api/v1/customers/{id} | customers:read | Get a customer with contacts |
| GET | /api/v1/requests | requests:read | List requests |
| POST | /api/v1/requests | requests:write | Create a request |
| GET | /api/v1/requests/{id} | requests:read | Get a request with messages |
The stock routes also need Stock, the deliveries routes Route and the suppliers and purchase orders routes Source. Without the product a route answers 404. Reads keep working after a product is switched off while it still holds rows; a stock movement needs Stock on.
Pages
A list returns its rows and next_cursor. Pass that back as cursor for the next page; null means you have everything. Products are ordered by SKU, stock locations come back whole with the default first, and every other list is newest first. limit sets the page size, up to the caps on rate limits.
Examples
curl https://kabaido.ai/api/v1/quotes/7f0c0000-0000-0000-0000-000000000000 \
-H "Authorization: Bearer kbd_your_key_here"The quote comes with its lines in position order. Each line carries amount_minor, its net value: use it rather than recomputing from qty and unit_price_minor, because a seller can pin a line total (amount_override_minor).
curl -X POST https://kabaido.ai/api/v1/requests \
-H "Authorization: Bearer kbd_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "text": "Please quote 20 off 250 mm saw blades, 60 teeth" }'Returns 201 with the request's id, title and url. The text may run to 100,000 characters. The request is attributed to the organisation's owner and opens at that url in the AI area. Opening it through a key draws no usage.
curl -X POST https://kabaido.ai/api/v1/stock/movements \
-H "Authorization: Bearer kbd_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "kind": "receipt", "product_id": "<product id>", "qty": 20, "unit_cost_minor": 1250, "idempotency_key": "grn-4411-1" }'A key may write the kinds a person writes by hand: adjustment, transfer, scrap, return and receipt. Name the line_id, or the product_id with a location_id when it is not the default location; a transfer also names to_location_id. A repeated idempotency_key is not written twice. See the ledger.
Writes
POST /api/v1/products/bulk upserts up to 10,000 products by SKU. POST /api/v1/customers upserts up to 500 customers, matched by external id then email domain. A retry after a timeout updates rather than duplicates, except for a customer sent with neither an external_id nor an email: that one is created again.
Errors
An error is JSON with one error message.
| Status | Means |
|---|---|
| 400 | The query, the body or the cursor is not valid |
| 401 | The key is missing, unknown or revoked |
| 402 | Your existing products plus the bulk batch would pass your plan's product cap |
| 403 | The key lacks the scope |
| 404 | Not in your organisation, or the product the route needs is off |
| 409 | A stock movement would take a balance below zero |
| 413 | Too many products in one bulk call |
| 422 | A request cannot be attributed: the organisation has no owner |
| 429 | The key's rate limit; wait and retry |
| 500 | A fault on our side; retry with a backoff |
Every money field is an integer in minor units beside a currency: total_minor 58200 with currency GBP is 582.00 pounds. Divide at display, not before.
Related
- API keys and scopesCreate a key that can do exactly what one integration needs, and retire it safely.
- Rate limitsKnow every limit the API, the inbound endpoints and the webhooks apply, and what happens at each.
- The products APIPush products into your catalogue from your own systems and read them back, with an API key.
- API changelogSee what the API, the webhooks and the MCP server offer today and when each part arrived.