Skip to content

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: Bearer header.

The machine readable description is the OpenAPI document at https://kabaido.ai/api/v1/openapi.json (version 1.0.0).

Resources

MethodPathScopeWhat it does
GET/api/v1/productsproducts:readList products
POST/api/v1/products/bulkproducts:writeBulk upsert products
GET/api/v1/quotesquotes:readList quotes
GET/api/v1/quotes/{id}quotes:readGet a quote with lines
GET/api/v1/ordersorders:readList orders
GET/api/v1/orders/{id}orders:readGet an order with lines
GET/api/v1/stock/linesstock:readList stock lines
GET/api/v1/stock/lines/{id}stock:readGet a stock line with its movements
GET/api/v1/stock/locationsstock:readList stock locations
GET/api/v1/stock/movementsstock:readList stock movements
POST/api/v1/stock/movementsstock:writeRecord a stock movement
GET/api/v1/deliveriesdeliveries:readList deliveries
GET/api/v1/deliveries/{id}deliveries:readGet a delivery with its lines and packages
GET/api/v1/supplierssuppliers:readList suppliers
GET/api/v1/suppliers/{id}suppliers:readGet a supplier with contacts
GET/api/v1/purchase-orderspurchase_orders:readList purchase orders
GET/api/v1/purchase-orders/{id}purchase_orders:readGet a purchase order with lines and receipts
GET/api/v1/customerscustomers:readList customers
POST/api/v1/customerscustomers:writeUpsert customers
GET/api/v1/customers/{id}customers:readGet a customer with contacts
GET/api/v1/requestsrequests:readList requests
POST/api/v1/requestsrequests:writeCreate a request
GET/api/v1/requests/{id}requests:readGet 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

bash
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).

bash
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.

bash
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.

StatusMeans
400The query, the body or the cursor is not valid
401The key is missing, unknown or revoked
402Your existing products plus the bulk batch would pass your plan's product cap
403The key lacks the scope
404Not in your organisation, or the product the route needs is off
409A stock movement would take a balance below zero
413Too many products in one bulk call
422A request cannot be attributed: the organisation has no owner
429The key's rate limit; wait and retry
500A 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.