Requests and responses
Pages, filters, syncing, error codes, retries with idempotency keys, and rate limits.
Every endpoint behaves the same way for pages, filters, errors, retries and limits. Learn these once.
#Responses
A success returns { "data": … }: one object, or a list. Objects carry an object field naming what they are, a public id such as pr_1a2b3c4d5e6f7a8b, and timestamps in ISO 8601 with a zone. Every response has an X-Request-Id header; quote it if you contact support.
#Lists, pages and sync
Lists return { "data": [...], "pagination": { "nextCursor", "hasMore" } }. Ask for up to 100 with limit, and pass nextCursor back as cursor for the next page. A cursor belongs to the filters it was made with; using it with others answers 422.
To keep another system in step, ask for sort=-updated_at with updated_since set to the newest updated_at you last saw. Some lists cannot be paged and say so in the reference; they return the newest items and hasMore.
curl "https://synconone.com/api/v1/people?sort=-updated_at&updated_since=2026-11-05T00:00:00Z&limit=100" \
-H "Authorization: Bearer sk_live_YOUR_KEY"#Filters, search and custom fields
qsearches a record's main text. Other query parameters filter by equality; each endpoint lists its own in the reference.- Custom fields are written and read by their key beside the built-in ones. A value that does not fit the field's type is a
422that names the field. - Relations take public ids: a deal's
personis apr_…id. An id for something the key cannot see is a422, never a silent skip.
#Errors
Every failure has the same shape. Branch on code, never on the wording of message, which is written for people and may change.
{
"error": {
"code": "validation_failed",
"message": "The request body is invalid.",
"requestId": "req_5b1f…",
"details": [{ "field": "email", "message": "Enter a valid email address." }]
}
}| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | No key, or a key that is wrong, revoked or expired. |
| 403 | forbidden | The key lacks the scope, or its role cannot do this. |
| 404 | not_found | It does not exist, or this key cannot see it. |
| 409 | conflict | The state forbids it, such as a ticket move it cannot make. |
| 422 | validation_failed | Something in the request is wrong; details say what. |
| 422 | idempotency_key_reused | The key was used with a different request. |
| 429 | rate_limited | Too many requests. Wait for Retry-After. |
| 500 | internal | Our side. Retry; quote the request id if it persists. |
#Retries and idempotency
Send an Idempotency-Key (any unique string up to 255 characters) on creates a retry could repeat. Retrying with the same key and body replays the first answer and sets Idempotent-Replayed: true; the same key with a different body is refused. Keys are remembered for 24 hours. GET, PATCH and DELETE are safe to retry as they are.
#Rate limits
Each key has a requests-per-minute limit, set when it is made. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Past the limit the API answers 429 with Retry-After in seconds; wait that long, then continue. Back off rather than retrying in a tight loop. Sending to people has its own, lower limits, noted where they apply: replies in the live chat inbox, and invitations sent by meetings.