Skip to content
BookifyCall
Developer docs: Pagination, errors and limits

Pagination, errors and limits

The rules every endpoint follows, so one client handles all of them.

Formats

  • JSON in and out, UTF-8, over HTTPS only.
  • Times are ISO 8601 in UTC (2026-10-16T12:00:00.000Z). Date filters accept a date (2026-10-16) or a full timestamp; a date-only end covers that whole day.
  • IDs are UUIDs. A malformed id answers 400; an unknown one, or one outside your key's scope, 404.
  • Phone numbers are E.164 (+15551230001).
  • Fields are camelCase. Responses may gain new fields at any time; ignore the ones you do not know.

Pagination

List endpoints take page (from 1) and limit (default 20, at most 100; a larger value is clamped). The response carries the totals:

List response (example values)
{
  "success": true,
  "data": [
    "…"
  ],
  "pagination": {
    "page": 2,
    "limit": 50,
    "total": 137,
    "pages": 3
  }
}

Every list has a unique tiebreaker (the record id), so pages never repeat or skip a record that did not change.

Filtering and sorting

Each list documents its filters in the reference (status, agent, direction, date ranges and more). sort picks the field and order is asc or desc (default desc, newest first).

Incremental sync and caching

Calls, leads, appointments and scheduled calls accept updatedSince. Request ?updatedSince=<cursor>&sort=updatedAt&order=asc, page through, and save the last updatedAt as the next cursor (full example). Cancelled appointments are hidden unless you pass includeCancelled=true.

GET responses carry an ETag. Send it back as If-None-Match and an unchanged response answers 304 Not Modified with no body.

Errors

A failed request answers with an HTTP status and a stable code from our error registry. Switch on error.code; message is for people and may be reworded.

Example error · 400
{
  "success": false,
  "message": "limit must not be less than 1",
  "error": {
    "code": "VALID_001",
    "message": "limit must not be less than 1",
    "details": {
      "validation": [
        "limit must not be less than 1"
      ]
    }
  },
  "meta": {
    "timestamp": "2026-10-16T12:00:00.000Z",
    "path": "/api/v1/external/calls-history?limit=0"
  }
}

Server errors answer 500 with code INTERNAL. They are safe to retry with backoff; writes should carry an Idempotency-Key.

StatusCodeMessageWhen
400CALL_004No phone number assignedThe agent has no phone number to call from
400PHONE_004Number already assignedThe agent already has a number
400SCHED_002Invalid schedule timescheduledAt must be in the future
400SCHED_010Choose a lead or enter a phone number, not bothSend leadId or phoneNumber, not both
400VALID_001Validation failedA query or body field is invalid or not supported (see error.details.validation)
400WEBHOOK_003Webhook URL must use httpsURL must use https
400WEBHOOK_004Webhook URL must resolve to a public addressURL must resolve to a public address
400WEBHOOK_005Unknown webhook eventUnknown webhook event name
401APIKEY_002Invalid or revoked API keyX-API-Key missing, unknown, expired or revoked
403APIKEY_003API key is missing a required scopeThe key lacks a scope this endpoint requires (details.required / details.granted)
403AUTH_006You do not have permission to perform this actionAgent-bound key used on an organization-wide resource or another agent
403EXT_010This feed is not available to this API keyDemo-line feed, enabled partner accounts only
403PLAN_001This feature is not included in your current planYour plan does not include API access (Enterprise)
403PLAN_002Plan limit reachedA plan limit was reached (agents, transfer contacts, ...)
404AGENT_001Agent not foundAgent not found, inactive or outside the key scope
404APPT_001Appointment not foundAppointment not found or outside the key scope
404CALL_002Call not foundCall not found or outside the key scope
404LEAD_001Lead not foundLead not found or outside the key scope
404PHONE_001Number not foundNumber not found
404REC_001Recording not foundThe call has no recording
404SCHED_001Scheduled call not foundScheduled call not found or outside the key scope
404WEBHOOK_001Webhook endpoint not foundWebhook subscription not found
409IDEM_001Duplicate requestSame Idempotency-Key still in flight, or used on another endpoint
409REC_010This recording is still held by the phone provider and is not available to play here yetThe recording is still at the phone provider and cannot be served yet
409SCHED_004Scheduled call can no longer be changedThe scheduled call is no longer pending
422IDEM_002Idempotency key was already used with a different request bodyIdempotency-Key reused with a different request body
429RATE_001Rate limit exceededRate limit exceeded; wait for Retry-After seconds

Rate limits

Each API key may make 60 requests per minute by default, across all endpoints and IP addresses. Every response reports your budget for the current window:

Response headers (example values)
X-RateLimit-Limit-external: 60
X-RateLimit-Remaining-external: 57
X-RateLimit-Reset-external: 42

Reset is in seconds. Over the limit you get 429 RATE_001 with a Retry-After header (seconds): wait that long, then retry. Need more? Tell us your expected volume through sales.

Idempotency

Network failures happen after the server has acted. To retry a write safely, send an Idempotency-Key header (1 to 200 characters; a UUID is ideal). For 24 hours, a retry with the same key and the same body replays the first response instead of running again.

  • A retry while the first request is still running answers 409 IDEM_001; wait and retry.
  • The same key with a different body answers 422 IDEM_002, never someone else's result.
  • A request that failed does not keep its key, so you can retry it with the same key.
  • Keys are private to your API key; they never collide with another customer's.

Endpoints that accept it:

  • POST /calls/outbound
  • POST /scheduled-calls
  • POST /agents
  • POST /numbers/{id}/assign
  • POST /webhooks