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”| Resource | Method · Path | Scope | Notes |
|---|---|---|---|
| Identity | GET /v1/whoami | any | Who the credential is. |
| Account | GET /v1/account | any | Name, status, timezone, language, CAC ceilings. |
| Calls / CDR | GET /v1/calls | cdr | Call records; ?since=&until=&limit=&cursor=&format=csv (paginated). |
| Agents | GET /v1/agents | agents | Live agent state (?userId=). |
| Agents | POST /v1/agents/state | agents | Drive an agent: { userId, event, queues? }. |
| Queues | GET /v1/queues | queues | Queues + KPIs (?since=). |
| Numbers | GET /v1/numbers | numbers | Your DIDs. |
| DNC | GET·POST·DELETE /v1/dnc | dnc | Do-not-call list: { e164, reason?, source? }. |
| Webhooks | GET·POST·DELETE /v1/webhooks | webhooks | Subscriptions. |
| Webhooks | POST /v1/webhooks/test | webhooks | Fire a test event to your endpoints. |
| Campaigns | /v1/campaigns… | campaign | Dialer campaigns: create, contacts, start, pause, disposition, KPIs. |
# 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" }'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.jsonPagination
Section titled “Pagination”GET /v1/calls is 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 & roadmap
Section titled “Status & roadmap”The /v1 surface above is live. On the roadmap: write CRUD for the full resource model (numbers, queues, flows, trunks), Idempotency-Key on writes, cursor pagination, and published SDKs / an MCP server generated from the OpenAPI spec.