SiteCall for developers
Calls and texts inside your application.
SiteCall is the phone system: numbers, routing, queues, recordings, transcripts and texting. Your application drives it through a REST API at https://sitecall.ai/api/v1, hears about every change through signed webhooks, and puts calls in your users' browsers and phones with the web and React Native SDKs.
How an application connects
- Your application is registered with SiteCall and manages workspaces (each business you serve). You name a workspace by SiteCall's id or by your own id for it.
- Your backend holds an application key (
sc_live_…) and calls the API for its workspaces. The key never reaches a browser or a phone. - Your users are application users: SiteCall knows them by your own user id. Your backend mints each a 15-minute end-user token (
POST /api/v1/sessions); their browser or phone uses that token, and SiteCall checks its workspace and scopes on every request. - Events come back to your webhook endpoints, signed and in order per call, number or agent.
Credentials
| Credential | What it is |
|---|---|
application_key | An application key (`sc_live_…`) of the application that manages the workspace. |
workspace_key | A workspace's own key (`sc_live_…`), which holds only `verify:send`. |
member_token | A SiteCall member's end-user token (`POST /api/v1/sessions` with the member's session). |
user_token | An application user's end-user token (`POST /api/v1/sessions` with the application key). |
user_session | A signed-in SiteCall user's access token (their SiteCall login, not an end-user token). |
application_secret | The application's legacy bearer secret with the `x-sitecall-application` header. |
public | No credential. |
Send it as Authorization: Bearer <credential>. Each operation needs one scope:
numbers:* · routing:* · calls:* · calls:supervise · devices:* · messages:* · media:read · webhooks:* · metrics:read
calls:* is call control and never implies calls:supervise. An end-user token carries at most the scopes the key that minted it holds.
Conventions
- Workspace. Every workspace request names it in
x-sitecall-workspace-id. With an application key you may use your own id instead:x-sitecall-external-workspace-id. A key reaches only the workspaces its application manages; a token only its own. - Idempotency. Every mutation takes an
idempotency-keyheader (1–255 visible ASCII; a UUID is a good choice). The first answer is kept for 24 hours: a retry with the same key and body gets it again withidempotent-replayed: true, the same key with another body is a 422idempotency_key_reused, and a retry while the first is still running is a 409idempotency_in_progress. Retry a 503 or a lost answer with the same key: it cannot act twice. - Pagination. Lists take
?limit=(1–200, default 50) and?cursor=, newest first, and answer{ data, nextCursor }.nextCursoris null on the last page. Cursors are opaque. - Additive changes only. Within
/v1new fields appear and enum-like values (a state, a role, a kind, an event type, an error code) may take values not listed today. Ignore fields you do not know and treat an unknown value as "other", never as an error. - Errors. Refusals are
{ error: { code, message } }with a stable code; routing plan errors addissues. Responses are never cached (cache-control: no-store). - Browsers. The API answers CORS for every origin (
Access-Control-Allow-Origin: *, preflights answer 204), so@sitecall/webcan call it from your page. It acceptsAuthorization,Content-Type,Idempotency-Key,x-sitecall-workspace-id,x-sitecall-external-workspace-id,x-sitecall-applicationand lets the page readRetry-After,idempotent-replayed,X-Request-Id,X-Vercel-Id. It never allows credentials: a request made without them (the SDK's default) carries no cookies, and a page on another origin can never read an answer to one made with the visitor's cookies. The page authenticates with its end-user token inAuthorization. An application key stays on your server.
A refusal
HTTP/1.1 409 Conflict
content-type: application/json
{ "error": { "code": "call_ended", "message": "The call has ended" } }| Code | Status |
|---|---|
unauthorized | 401 |
insufficient_scope | 403 |
workspace_forbidden | 403 |
forbidden | 403 |
invalid_request | 400 |
invalid_cursor | 400 |
idempotency_key_required | 400 |
idempotency_key_reused | 422 |
idempotency_in_progress | 409 |
not_found | 404 |
in_use | 409 |
not_published | 409 |
invalid_plan | 422 |
call_ended | 409 |
target_not_found | 404 |
supervisor_unreachable | 409 |
not_implemented | 501 |
unavailable | 503 |
invalid_destination | 400 |
emergency_unavailable | 422 |
destination_blocked | 403 |
number_unavailable | 404 |
caller_id_forbidden | 403 |
self_dial | 422 |
agent_unreachable | 409 |
plan_inactive | 402 |
call_conflict | 409 |
disabled | 503 |
application_key_required | 403 |
limit_exceeded | 409 |
device_busy | 409 |
emergency_location_required | 403 |
emergency_address_invalid | 422 |
recipient_opted_out | 409 |
sender_unavailable | 422 |
message_conflict | 409 |
sender_not_eligible | 403 |
invalid_media | 422 |
message_rejected | 422 |
The API reference lists all 81 operations, generated from SiteCall's endpoint table. SiteCall's tests run the typed client against every route it lists except the two session-bound provisioning operations: each operation's method and path, the scopes and credentials it accepts and refuses, when it needs an Idempotency-Key and a workspace header, and that its answer matches the published schema.