Docs menu

Errors, limits & pagination

How the API reports problems, how much you can call it, and how to page through results.

Error format #

Errors use standard HTTP status codes and a JSON body. Validation errors also list the fields that failed.

HTTP/1.1 400 Bad Request
{
  "error": "Invalid request",
  "issues": [{ "path": "datasetId", "message": "Required" }]
}
StatusMeaningWhat to do
400Invalid input, or the connected system rejected the requestFix the request. Don't retry unchanged
401Missing, invalid, expired or revoked keyCheck the key and header format
402Plan limit reached (reports, call minutes, API access)Upgrade, or wait for the next month
403Key lacks the scope, IP not allowlisted, or origin not allowedAdjust the key in the dashboard
404Not found in this workspaceCheck the ID. Keys only see their own workspace
409Duplicate (e.g. same call externalId) or wrong stateTreat as already done
413 / 415Body too large / wrong content typeSend smaller batches, as JSON or multipart
429Rate limit exceededBack off and retry after the time in the error message
5xxOur sideRetry with exponential backoff; contact support if it persists

Rate limits #

PlanSecret key requests / minuteAI reports / monthCall minutes / month
FreeNo API access560
Starter3050600
Professional1203003 000
Business6002 00015 000

Limits are counted per key, over a sliding one-minute window. Public keys are also limited to 30 requests per minute per client IP. Push URLs accept 60 requests per minute.

Asynchronous work #

Reports and call processing take seconds to minutes, so their create endpoints return 202 Accepted with an ID and a status of QUEUED/PENDING. You can poll the resource every 5–10 seconds, or, better, subscribe to webhooks.

Pagination #

/v1/calls is cursor-paginated. Pass limit (1–100), then send the returned nextCursor as cursor until it is null./v1/reports and /v1/datasets return the most recent 100 and 200 items.

let cursor = null;
do {
  const url = new URL("https://api.summarix.co.za/v1/calls");
  url.searchParams.set("limit", "100");
  if (cursor) url.searchParams.set("cursor", cursor);
  const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` } }).then((r) => r.json());
  handle(res.data);
  cursor = res.nextCursor;
} while (cursor);

Versioning #

The API is versioned in the path (/v1). Within a version we only make additive changes: new endpoints, new optional fields and new response fields. Your client should ignore fields it doesn't know. Breaking changes will ship as /v2, with at least 12 months' notice.