Developers

REST API

Read and write any record over a predictable REST interface — list, filter, create, update and act on resources.

The REST API exposes the same records and operations as the interface. If you understand the data model, the endpoints follow naturally: each resource has a collection and a member URL with the usual verbs.

Resource conventions#

| Verb | Path | Does | | --- | --- | --- | | GET | /v1/{resource} | List, with filtering and pagination | | GET | /v1/{resource}/{id} | Fetch one record | | POST | /v1/{resource} | Create a record | | PATCH | /v1/{resource}/{id} | Update fields on a record | | POST | /v1/{resource}/{id}/{action} | Run an action (e.g. confirm, post) |

List and filter#

Collections support filtering, field selection, sorting and cursor pagination:

curl "https://acme.quelixa.com/api/v1/invoices?\
state=posted&\
fields=number,partner,amount_total,state&\
sort=-date&\
limit=50" \
  -H "Authorization: Bearer qx_live_8f2c…"
{
  "data": [
    {
      "id": "inv_01HX…",
      "number": "INV/2026/0042",
      "partner": { "id": "res_01H…", "name": "Globex" },
      "amount_total": 1260.00,
      "state": "posted"
    }
  ],
  "next_cursor": "eyJpZCI6…"
}
Ask for the fields you need

Use fields to keep responses small and stable. Relations are returned as nested objects with an id and a label so you rarely need a second round-trip.

Create a record#

Posting to a collection creates a draft. Most documents then need an explicit action to take effect — mirroring "save" then "confirm" in the app.

# 1. Create a draft invoice
curl -X POST https://acme.quelixa.com/api/v1/invoices \
  -H "Authorization: Bearer qx_live_8f2c…" \
  -H "Content-Type: application/json" \
  -d '{
    "partner": "res_01H…",
    "lines": [
      { "product": "prd_204", "quantity": 10, "price_unit": 100 }
    ]
  }'
 
# 2. Confirm it — assigns the number and posts the journal entry
curl -X POST https://acme.quelixa.com/api/v1/invoices/inv_01HX…/confirm \
  -H "Authorization: Bearer qx_live_8f2c…"
Actions are where the side effects live

Creating a record rarely touches the ledger. The confirm/post/pay actions are what validate, number and post — exactly as in the interface. Design integrations around create-then-act.

Errors#

Errors use standard HTTP status codes with a JSON body describing the problem.

| Status | Meaning | | --- | --- | | 400 | Malformed request or invalid field | | 401 | Missing or invalid token | | 403 | Token lacks the required scope | | 404 | No such record in this workspace | | 422 | Business rule rejected the operation | | 429 | Rate limited — back off and retry |

{
  "error": {
    "type": "validation_error",
    "message": "Partner is required to confirm an invoice.",
    "field": "partner"
  }
}

Rate limits#

Calls are rate limited per token. When you exceed the limit you get 429 with a Retry-After header; honour it with exponential backoff.

Prefer webhooks over polling

Don't poll for changes on a tight loop — it burns your rate budget. Subscribe to webhooks and react to events as they happen.