Public API (v1)
The public REST API is served at https://api.sip.io/v1. It’s JSON in and out, authenticated with an API key or session token, and authorized by scope. The account is always taken from your credential, never a path or query parameter.
curl https://api.sip.io/v1/whoami -H 'x-api-key: sk_…'# → { "accountId": "acc_acme", "scopes": ["*"], "via": "key" }Endpoints
Section titled “Endpoints”The surface is large, grouped below by resource area. Every path takes the credential’s account implicitly; scopes are shown per row (* on a key or token grants all of them).
Identity & account
| Method · Path | Scope | Notes |
|---|---|---|
GET /v1/whoami | any | Who the credential is. |
GET /v1/scopes | open | The catalog of grantable scopes, no key needed. |
GET /v1/account | any | Name, status, timezone, language, voice gender, ringback country, recording retention, CAC ceilings. |
PATCH /v1/account | account | Self-service update: { name?, timezone?, language?, voice_gender?, tone_country?, recording_retention_days?, allow_free_caller_id? }. Never settable here: id, status, parent_id, billing (admin-only). |
GET|POST|DELETE /v1/keys | keys | Self-service API keys: list (no secrets shown), mint { label?, scopes? } (secret shown once), revoke. |
GET /v1/usage | usage | Spend/minutes/call-count from the CDR, ?since=&until=&daily=1 for a daily series. |
GET /v1/balance | usage | Account financial statement: status, rate plan, month-to-date spend. |
Calls
| Method · Path | Scope | Notes |
|---|---|---|
GET /v1/calls | cdr | Call records; ?since=&until=&limit=&cursor=&format=csv, keyset-paginated. |
POST /v1/calls | calls | Click to call: { to, from?, callerId?|cidPoolId?, agentCallerId?, screenPop? }. 409 if the agent’s already on a call. |
GET /v1/calls/mine | calls | The caller’s own current call id (for a softphone app). |
GET /v1/calls/{id}/trace | cdr | The full flow-node execution trace for a call, the debugger view. |
GET/POST /v1/calls/{id}/ivr , /ivr/select | calls | Visual IVR: read the live menu a call is waiting on, or submit a selection that advances the same flow. |
POST /v1/calls/{id}/control | calls | Live-call control: { action: hold|unhold|mute|unmute|hangup|dtmf|park, digits? }. id: "mine" for your own call. |
POST /v1/calls/{id}/transfer | calls | Blind, attended, or 3-way transfer: { action, target, mode? }. |
POST /v1/calls/{id}/supervise | calls | Supervisor listen / whisper / barge into a live agent call. |
POST /v1/calls/{id}/recording | recordings | Mid-call recording control: { action: pause|resume|stop|start } (the PCI-sensitive-segment control). |
POST /v1/cac/reset | cdr | Clear this account’s leaked concurrency counters. |
Agents & queues
| Method · Path | Scope | Notes |
|---|---|---|
GET /v1/agents | agents | Live agent presence, ?userId=. |
POST /v1/agents/state | agents | Drive an agent: { userId, event, queues? }. |
GET|POST /v1/queues, /{id} | queues | List + rolling KPIs (?since=) / one queue, create, update, delete. |
GET|POST /v1/queues/{id}/members, DELETE .../{userId} | queues | Queue membership. |
POST /v1/queues/{id}/options, DELETE .../{digit} | queues | In-queue DTMF options. |
GET /v1/live | cdr | Live account snapshot (agents, in-progress calls, CAC counters, queue configs), a real-time debugging view. |
Numbers, extensions & routing config
| Method · Path | Scope | Notes |
|---|---|---|
GET|POST /v1/numbers, /{id} | numbers | Your DIDs: route target, fax mode, business hours. |
GET|POST /v1/extensions, /{id} | extensions | Internal short codes. |
GET|POST /v1/ring-groups, /{id} | ringgroups | Ring groups, members replace as a set on each write. |
GET|POST /v1/schedules, /{id} | schedules | Business-hours schedules, rules replace as a set on each write. |
GET|POST /v1/users, /{id}, /{id}/devices | users | Users/agents/extensions and their SIP devices. |
GET|POST /v1/devices, PATCH|DELETE /{id} | users | SIP devices (password → ha1, never stored plaintext). |
Flows
| Method · Path | Scope | Notes |
|---|---|---|
GET|POST /v1/flows, GET /{id} | flows | Call flows: publish: true is lint-gated, a failing lint returns 422. |
POST /v1/flows/validate | flows | Lint a flow graph without saving, the editor’s live check. |
POST /v1/flows/{id}/test | flows | Run a simulated call through a flow, { from?, to?, digits?, vars? } → the routing trace. |
Recordings, voicemail & media
| Method · Path | Scope | Notes |
|---|---|---|
GET /v1/recordings, /{id}, /play, /download, DELETE | recordings | Call recordings; every access is logged. |
GET|POST /v1/voicemails, /{id} | voicemail | Mailboxes, PIN stored as a secret reference. |
GET /v1/voicemails/mwi | voicemail | Message-waiting summary. |
GET /v1/voicemails/{id}/messages, .../{msgId}/audio, PATCH|DELETE .../{msgId} | voicemail | The message inbox: list, stream/download, mark read, delete. |
GET|POST /v1/media, GET|DELETE /{id} | media | Prompts/MOH/greetings: upload (raw audio body), play/download, delete. |
GET|POST /v1/faxes, GET|DELETE /{id} | fax | Fax over IP: send, list, download/render, delete. |
Transcription & summarization
| Method · Path | Scope | Notes |
|---|---|---|
POST /v1/recordings/{id}/transcribe | recordings | Transcribe a recording: { language?, summarize? }. |
POST /v1/recordings/{id}/summarize | recordings | Summarize an already-transcribed recording on its own. |
GET /v1/recordings/{id}/transcript | recordings | Text, language, and summary (?words=1 for word/speaker-level detail). |
GET /v1/transcripts | recordings | List transcripts, filterable, cursor-paginated. |
POST /v1/transcripts/batch | recordings | Batch-transcribe by recording ids or a date range, processed in the background. |
GET|PUT|DELETE /v1/transcription/config | recordings | Bring your own AI provider (any OpenAI-standard transcription or LLM endpoint); your key is encrypted at rest. |
Messaging
| Method · Path | Scope | Notes |
|---|---|---|
GET|POST /v1/channels, /{id} | channels | Messaging channels (SMS/WhatsApp/RCS senders); secrets shown once. |
GET /v1/conversations, /{id}, POST .../reply | messaging | The omnichannel inbox. |
POST /v1/messages | messaging | Send a message, starts or continues a conversation. |
GET|POST /v1/templates, /{id}, POST .../submit | messaging | WhatsApp/RCS templates, including Meta submission. |
Contacts, scripts & custom fields
| Method · Path | Scope | Notes |
|---|---|---|
GET|POST /v1/contacts, /{id} | contacts | Phonebook: CNAM, reverse lookup, screen-pop source. |
GET /v1/directory | contacts | Internal directory, ?digits= for dial-by-name. |
GET|POST /v1/scripts, /{id}, GET .../render | scripts | The call-script store (SIP.IO stores the blob, your app renders it). |
GET|POST /v1/fields, /{id}, GET /v1/calls/{id}/fields | fields | Custom fields captured by a flow’s collect node, for screen-pop/CDR enrichment. |
Conferences & softphone
| Method · Path | Scope | Notes |
|---|---|---|
GET|POST /v1/conferences, /{id}, POST .../control | conferences | Conference bridges: create, moderate (mute/kick/lock), delete. |
POST /v1/softphone/token | softphone | Mint an ephemeral WebRTC SIP credential for an embedded softphone. |
Compliance & outbound
| Method · Path | Scope | Notes |
|---|---|---|
GET|POST|DELETE /v1/dnc | dnc | Do-not-call list. |
/v1/campaigns… | campaign | Dialer campaigns: create, contacts, start, pause, disposition, KPIs. |
Webhooks & events
| Method · Path | Scope | Notes |
|---|---|---|
GET|POST|DELETE /v1/webhooks, POST .../test | webhooks | Subscriptions. |
GET /v1/webhooks/events | webhooks | The catalog of subscribable event types with sample payloads. |
GET /v1/webhooks/deliveries | webhooks | The delivery log: status, attempts, last error. |
POST /v1/events/ticket | events | Mint a single-use ticket for the realtime event-stream WebSocket. |
Microsoft Teams Direct Routing
| Method · Path | Scope | Notes |
|---|---|---|
GET|POST /v1/teams, GET|PATCH|DELETE /{id} | teams | Tenant management: create returns the DNS records to add. |
GET /v1/teams/{id}/dns, /cert, /health, /cdrs | teams | DNS verification, certificate status, live SBC health, call records. |
POST /v1/teams/{id}/provision | teams | Run or resume provisioning. |
POST /v1/teams/{id}/status-token | teams | Rotate the tenant’s shareable public-status link. |
Reporting & analytics
| Method · Path | Scope | Notes |
|---|---|---|
GET /v1/reports/queues, GET /v1/metrics/queues | reports | Queue rollup reports, 15-minute and daily grain. |
GET /v1/reports/agents | reports | Agent rollup reports: occupancy, utilization, time-in-state. |
GET /v1/reports/teams, GET|POST /v1/agent-teams, /{id} | reports | Group agents into teams for team × queue rollups. |
GET /v1/reports/pauses | reports | Agent pause time broken down by reason. |
GET /v1/live/queues, /v1/live/agents, /v1/live/interactions | reports | REST snapshots of live queue health, agent state, and in-progress interactions, an alternative to the WebSocket wallboard for consumers that want a poll instead of a live socket. |
Reseller / operator
| Method · Path | Scope | Notes |
|---|---|---|
GET /v1/accounts | accounts | The subaccounts under your management (reseller/operator only). |
GET /v1/logs | cdr | Recent flow-node events across your calls, ?limit=&level=. |
# create a webhook subscriptioncurl -X POST https://api.sip.io/v1/webhooks \ -H 'x-api-key: sk_…' -H 'content-type: application/json' \ -d '{ "url": "https://acme.com/hooks/sipio", "events": "call.started,call.ended" }'# update account settings (only the fields you send are changed)curl -X PATCH https://api.sip.io/v1/account \ -H 'x-api-key: sk_…' -H 'content-type: application/json' \ -d '{ "tone_country": "GB", "recording_retention_days": 90 }'OpenAPI
Section titled “OpenAPI”The spec is published at GET /v1/openapi.json (OpenAPI 3.0, no auth). Point your generator at it for a typed client in any language. Security schemes: apiKey (x-api-key) and bearer (JWT).
curl https://api.sip.io/v1/openapi.json -o sipio-openapi.jsonIdempotency
Section titled “Idempotency”Mutating requests (POST/PATCH/DELETE) accept an Idempotency-Key header. Send the same key on a retry (e.g. after a timeout) and you get back the original stored response instead of creating a duplicate:
curl -X POST https://api.sip.io/v1/queues \ -H 'x-api-key: sk_…' -H 'content-type: application/json' \ -H 'Idempotency-Key: 3f29a1e0-…' \ -d '{ "name": "Support" }'A replayed response carries an idempotency-replayed: true header so you can tell it apart from a fresh one. Keys are held for 24 hours.
Pagination
Section titled “Pagination”List endpoints that return large result sets (like GET /v1/calls) are keyset-paginated (stable and cursor-based, with no offset drift). When a page is full, the response includes a next_cursor; pass it back as ?cursor= (with the same limit) to get the next page. A response without a next_cursor is the last page.
curl 'https://api.sip.io/v1/calls?limit=500&cursor=…' -H 'x-api-key: sk_…'Rate limits
Section titled “Rate limits”The authed /v1 surface is limited to 100 requests / 60s per API key (per-IP for unkeyed requests), enforced by a layered edge gate plus a precise quota. Over the limit returns 429 with a Retry-After header:
{ "ok": false, "error": "rate_limited", "hint": "100 requests / 60s", "retry_after_sec": 42 }The open /v1 index and /v1/openapi.json are not rate-limited.
Responses & errors
Section titled “Responses & errors”Responses are JSON. Errors are uniform:
| Status | Body |
|---|---|
401 | { "ok": false, "error": "unauthorized" }: missing/invalid credential. |
403 | { "ok": false, "error": "forbidden", "need": "<scope>" }: credential lacks the scope. |
404 | { "ok": false, "error": "not_found" }. |
429 | { "ok": false, "error": "rate_limited", "retry_after_sec": … }: see Rate limits. |
Status
Section titled “Status”The /v1 surface above is live, including write CRUD across the resource model (numbers, extensions, ring groups, schedules, users, devices, queues, flows, voicemail, media, conferences), Idempotency-Key support on mutating requests, and keyset pagination. A few narrower resources (SIP domains, call forwards, trunks, outbound routes, number transforms, policies) are still config-managed rather than /v1-exposed. Published SDKs and an MCP server generated from the OpenAPI spec are on the roadmap.