Skip to main content
Everything the panel does, it does through this API. There is no private interface behind it.

A session token

Returns a JWT valid for twelve hours. Send it as a bearer token:

An API key

For anything that isn’t a person: your CRM, a script, a data export. Create one under Settings → API keys. The secret is shown once, and it goes in the same header:
There are two kinds:
  • Integration key. Belongs to the organisation, not to whoever made it, so it keeps working when staff change. You choose what it may do from a preset: Read calls & CDRs, Click-to-call, Campaigns, Contacts & tickets sync, Webhooks admin or Full access. Even with full access it can’t create API keys or people.
  • Personal key. Acts as you, within your role.
A key can never exceed its owner. Its permissions are intersected with the role of the person who created it, at the time each request is made. You cannot grant a key something you do not have, and a key does not keep a permission its owner has since lost. Keys can’t create or change other keys; a person signed in to the panel does that.

Every key needs an IP allowlist

A key works only from the addresses you list: single addresses or ranges (203.0.113.0/24), up to 20 entries.
  • Refused when creating a key:
    • “everything” (0.0.0.0/0);
    • ranges wider than /16 (IPv4) or /32 (IPv6);
    • private or local addresses. Your integration calls from its public address.
  • A request from anywhere else gets 403 ip_not_allowed, naming the address it came from. The panel shows each key’s last refused address.
  • Keys made before allowlists were compulsory keep working for 14 days, with a warning in the panel. After that they get 403 ip_allowlist_required until you add their addresses. The panel offers the addresses each key has been used from.
You can change a key’s allowlist, name and rate at any time. You can’t change its permissions; make a new key for different access.

Rate limits

Each key may make 600 requests a minute unless you set a different rate, and at most 60 call placements a minute whatever its rate. Every response carries: Over the limit: 429 rate_limited with Retry-After in seconds. Panel sessions aren’t rate limited.

Retrying safely: Idempotency-Key

POST /calls, /contacts, /tickets and /campaigns/{id}/contacts accept an Idempotency-Key header. Use any string up to 255 characters, unique per action.
  • Retrying with the same key and body (after a timeout, say) returns the first answer again, with Idempotent-Replayed: true, instead of placing a second call.
  • The same key with a different body is 409 idempotency_mismatch.
  • While the first request is still running, a retry gets 409 idempotency_in_progress.
  • Keys are kept for 24 hours. A request that failed with a server error isn’t kept, so retrying it runs it again.

Who am I

Returns the identity and the resolved permission list. That list is what the panel gates its screens on; there is no second copy of the rules in the browser.

Errors

The message is written to be shown to a person. Where a request is refused for a reason somebody can act on, the reason is in the message rather than implied by the code.
Unknown JSON fields are rejected, not ignored. A typo’d field name is a bug, and silently discarding it means discovering months later that a setting never applied. If you get malformed JSON body on a valid document, look for a misspelt key.