Developers and API
Testing the API with Postman, curl and the built-in console
Three ways to make a real call before you write any code — and what to do when one fails.
Open this in the appThe fastest check: the built-in console
Settings → API & webhooks → Guide & testing has a request console. Paste a key, pick an endpoint from the quick list, press Send, and the real response appears with its status code and timing. Nothing is stored — the key lives in the page and is gone when you leave it.
Use this first. If a call works here and fails in your code, the problem is in your code rather than in the key or its permissions, which narrows the hunt considerably.
Postman, in four steps
The same screen has a Download Postman collection button. The file is generated from the live route table, so it contains every endpoint this API serves, grouped by module, with the required permission written into each request's description.
- 1. Download the collection and import it in Postman.
- 2. Open the collection's Variables tab.
- 3. Paste your key into apiKey, and check that baseUrl matches your server. Save.
- 4. Open Employees → GET /employees and press Send.
A 200 with a list of employees means you are connected, and every other request in the collection now works the same way. The same file imports cleanly into Insomnia, Bruno and Hoppscotch.
curl, for a one-off check
KEY="ct_live_xxxxxx_your_key_here"
BASE="https://your-api-host/api/v1"
# read
curl "$BASE/departments" -H "x-api-key: $KEY"
# write
curl -X POST "$BASE/departments" \
-H "x-api-key: $KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Kitchen Operations","code":"KIT"}'
# show status and headers when something is wrong
curl -i "$BASE/employees" -H "x-api-key: $KEY"When it does not work
- 401 on everything — the header is x-api-key, not Authorization. Check for a truncated paste; keys are long and terminals wrap them.
- 403 with a valid key — the key lacks that permission. Keys cannot be edited: create a new one with the right scopes and revoke the old.
- 403 on /integrations — keys may not manage keys or webhooks. Use the web app for that.
- 422 you cannot explain — read error.details, it names the field. Dates must be YYYY-MM-DD.
- The first call after a quiet period times out — on smaller hosting plans the server sleeps when idle and takes up to a minute to wake. Allow a 60 second client timeout.
- Webhook signature never matches — you are hashing a re-serialised body instead of the raw bytes.
Going to production
- Use a separate key per integration, so one can be revoked without breaking the others.
- Retry 429 and 5xx with exponential backoff; do not retry 4xx, which will fail identically.
- Log the requestId from failed responses — it is the fastest way for us to find what happened.
- Page with limit=100 rather than pulling everything in one call.
- Prefer webhooks over polling for anything that needs to be timely.