Errors & Pagination
Error envelope
All errors return JSON:
{
"error": {
"type": "permission_error",
"code": "plan_required",
"message": "The API is available on the Pro plan. Upgrade in your dashboard to continue.",
"param": null
}
}
code is stable and machine-readable — branch on it, not on message.
| HTTP | type |
code |
What to do |
|---|---|---|---|
| 400 | invalid_request_error |
invalid_request |
Fix the field named in param. |
| 400 | invalid_request_error |
invalid_cursor |
Restart pagination from the first page. |
| 401 | authentication_error |
invalid_api_key |
Check the header format and that the key isn't revoked. |
| 403 | permission_error |
plan_required |
Upgrade the account to Pro. |
| 403 | permission_error |
insufficient_scope |
Use a read_write key. |
| 404 | not_found_error |
resource_not_found |
The ID doesn't exist on this account. |
| 409 | idempotency_error |
idempotency_conflict |
Same Idempotency-Key reused with a different body — use a fresh key. |
| 429 | rate_limit_error |
rate_limit_exceeded |
Wait Retry-After seconds, then retry. |
| 5xx | api_error |
internal_error |
Retry with exponential backoff. |
Pagination
List endpoints take limit (default 25, max 100) and an opaque cursor:
{
"object": "list",
"data": [ ... ],
"has_more": true,
"next_cursor": "eyJzIjoiMjAyNi0wNy0xN1QxNDowMzoyMloifQ"
}
Loop until has_more is false:
import os
import requests
BASE = "https://voice-public-api.essere.ai/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ESSERE_API_KEY']}"}
def iter_all(path, **params):
cursor = None
while True:
r = requests.get(f"{BASE}{path}", headers=HEADERS,
params={**params, "limit": 100, "cursor": cursor})
r.raise_for_status()
page = r.json()
yield from page["data"]
if not page["has_more"]:
return
cursor = page["next_cursor"]
for call in iter_all("/calls", status="completed"):
print(call["id"], call["outcome"])
Never parse or construct cursors yourself — treat them as opaque tokens.
Idempotency
POST and PATCH accept an Idempotency-Key header (any unique string,
e.g. a UUID). Within 24 hours, retrying with the same key returns the
original response with the header Idempotent-Replayed: true instead of
performing the operation twice. Always send one on writes you might retry.