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.

bash
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

  • q searches 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 422 that names the field.
  • Relations take public ids: a deal's person is a pr_… id. An id for something the key cannot see is a 422, 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.

json
{
  "error": {
    "code": "validation_failed",
    "message": "The request body is invalid.",
    "requestId": "req_5b1f…",
    "details": [{ "field": "email", "message": "Enter a valid email address." }]
  }
}
StatusCodeMeaning
401unauthorizedNo key, or a key that is wrong, revoked or expired.
403forbiddenThe key lacks the scope, or its role cannot do this.
404not_foundIt does not exist, or this key cannot see it.
409conflictThe state forbids it, such as a ticket move it cannot make.
422validation_failedSomething in the request is wrong; details say what.
422idempotency_key_reusedThe key was used with a different request.
429rate_limitedToo many requests. Wait for Retry-After.
500internalOur 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.