Skip to main content

API pagination, rate limits, errors, and conventions

Cursor-based pagination, rate limits and retry headers, HTTP error meanings, structured error responses, and the request conventions shared across all Sybill API endpoints.

Written by Sybill Inc

This is the reference for behavior shared by every Sybill API endpoint - consult it when a call doesn't behave the way you expect.
​

Pagination

The conversations, deals, accounts, messages, rows, and documents list endpoints use cursor-based pagination. Every list response includes the same pagination object alongside the results:

{   "conversations": [ ... ],   "pagination": {     "nextCursor": "eyJzZWFyY2hBZnRlciI6...",     "hasMore": true   } }


To fetch the next page, pass nextCursor back as the cursor query parameter. Check hasMore - not nextCursor - to decide whether more pages exist.
​

curl -H "Authorization: Bearer sk_live_YOUR_KEY" \   "https://api.sybill.ai/v1/conversations?limit=50&cursor=eyJzZWFyY2hBZnRlciI6..."


Rules that keep iteration correct:

  • Repeat your filters on every page. Cursors mark a position; they do not remember the filters from the first request.

  • Cursors are opaque. Don't parse, construct, or store them as long-term bookmarks - use each one promptly, within the same iteration.

  • Records added or deleted while you paginate can affect later pages. On document lists specifically, records sharing a creation timestamp at a page boundary may be repeated or skipped.

Page sizes: the maximum limit is 50 everywhere. Defaults differ - conversations, deals, and accounts default to 20; messages, rows, and documents default to 50. The sources and object-types lists are not paginated.
​

Rate limits

Data endpoints enforce per-key limits using a moving window. All rate-limited requests made with the same key share one set of counters, regardless of scope or endpoint. Health checks (GET /v1/health) don't count.

Window

Limit

Per minute

60 requests

Per hour

1,000 requests

Per day

10,000 requests

When you exceed a limit, the API returns 429 Too Many Requests with the body {"detail": "Rate limit exceeded"} and these headers:

Header

Meaning

X-RateLimit-Limit

Maximum requests allowed in the current window

X-RateLimit-Remaining

Requests remaining in the current window

X-RateLimit-Reset

Unix timestamp when the window resets

Retry-After

Seconds to wait before retrying

Handle 429s by waiting the Retry-After period and backing off exponentially on repeats. To stay under the limits: cache responses where you can, use the most specific endpoint for your need instead of re-polling list endpoints, and use limit=50 when iterating so you make fewer requests.
​

HTTP status codes

Status

Meaning

400 Bad Request

Malformed request, validation failure, or invalid query parameter

401 Unauthorized

API key is invalid or revoked

403 Forbidden

Authorization header missing, key lacks the required scope, or the resource belongs to another organization

404 Not Found

Resource doesn't exist or isn't accessible to your organization

409 Conflict

Duplicate or concurrent write

411 Length Required

A POST or PATCH request omitted the Content-Length header

413 Payload Too Large

A POST or PATCH body exceeded 10 MB

422 Unprocessable Entity

Request validation failed

429 Too Many Requests

Rate limit exceeded

500 Internal Server Error

Unexpected server error

Error response formats

GET endpoints generally return a simple message:

{ "detail": "Conversation not found" }


​POST, PATCH, and DELETE endpoints return structured details for 400, 403, 404, 409, 411, and 413:
​

{   "detail": {     "error": "validation_error",     "message": "exactly one of url or content must be provided",     "field": null,     "request_id": "01HV..."   } }
  • error is a machine-readable code: validation_error, forbidden, conflict, not_found, length_required, or payload_too_large.

  • field names the offending field when one applies.

  • request_id is a correlation ID - include it when you contact support about a failed request.

422 responses use a list format instead, with each entry naming the location (loc), message (msg), and type of the validation failure.
​

Request conventions

  • Field naming is camelCase - sourceId, remoteId, createdAfter - in query parameters and resource fields alike. Two documented exceptions stay snake_case: org_id in the health response and request_id in structured error details.

  • Timestamps in responses are ISO 8601 strings in UTC unless an endpoint's schema says otherwise.

  • Timestamps in import request bodies (createdAt, updatedAt, startedAt, endedAt, timestamp) also accept Unix seconds and Unix milliseconds; the format is auto-detected.

  • POST and PATCH bodies require a Content-Length header and may not exceed 10 MB.

Did this answer your question?