Call center
Queues, agents and live calls.
Agents are SiteCall members or your application users. Queues hand callers to the longest-idle agent with the right skills; your application, a supervisor or the agent controls each live call.
Queues
POST /api/v1/queues creates one (scope routing:*). Members carry skills and a priority (lower wins a tie between equally idle agents); a queue's requiredSkills filter who is offered its calls. maxWaitSecs bounds the wait (a plan's queue step overflows after it), wrapUpSecs gives an agent time after each call, and awayOnMiss sets an agent away after a missed offer. The service-level target (answerTargetSecs, default 20 s, and serviceLevelGoalPct, default 80) feeds team metrics. Route callers into a queue with a plan's queue step.
Agents and their states
| State | Set by |
|---|---|
offline | The agent, a supervisor or your application |
available | The agent, a supervisor or your application |
offered | SiteCall (an offer, a call, wrap-up) |
on_call | SiteCall (an offer, a call, wrap-up) |
wrap_up | SiteCall (an offer, a call, wrap-up) |
away | The agent, a supervisor or your application |
GET /api/v1/agents lists members and active application users (kind, externalUserId) with their live state. PUT /api/v1/agents/{memberId}/state { "state": "available" } asks for a state: a member sets their own with calls:*; setting anyone else's, including with your application key, needs calls:supervise. System states (on_call, wrap_up) stay until the call or wrap-up ends. Every change is an agent.state_changed event.
The answer is { memberId, changed, state, previous }, plus one of two flags. deferred: true: you asked an agent who is ringing or on a call to go away or offline; it applies when the call (and any wrap-up) ends, so state is still the busy one, and a later available cancels it. stuck: true: the agent read as ringing or on a call with no live call or offer behind it, so the state you asked for applied at once.
Placing calls
POST /api/v1/calls/dial rings the agent's device first, then the destination. A token's own user or member is the agent; with your key, name it in agent. An application user dials only from the numbers you gave it (numberIds on POST /api/v1/users). Answering-machine detection is off unless machineDetection: "premium".
const placed = await sitecall.calls.dial({
to: "+15125550123",
from: { phoneNumberId },
agent: { externalUserId: "user-7" },
});
// placed.callId; progress arrives as call.* eventsThe call id is callId if you send one, else derived from the Idempotency-Key, and every refusal after it is fixed carries callId beside the error: a retry after a 503 with the same key is the same call. Refusals include caller_id_forbidden, invalid_destination, destination_blocked, agent_unreachable and emergency_location_required (see E911).
Controlling a live call
Hang up, transfer, hold, resume and swap take your key, a member's token, or an application user's token (acting with the role you gave it). Each answers 202 once the engine has the command (200 for a repeat of the same command); the outcome arrives as events.
| Operation | Body | Notes |
|---|---|---|
POST /calls/{id}/hangup | none | Ends the call. |
POST /calls/{id}/transfer | { target, warm? } | target is { e164 }, { queueId } or { memberId }; blind unless warm. |
POST /calls/{id}/hold | none | The remote party hears hold audio; so does the agent's leg, so hold that leg locally too. |
POST /calls/{id}/resume | none | Holds the device's other call first: one active leg per device. |
POST /calls/{id}/swap | none | Swaps the device's live and server-held calls. |
Only server holds count for resume and swap: a hold the phone does on its own leg is not server state. A 409 device_busy means a call on the device cannot be held right now (mid transfer, still being set up); nothing changed.
Supervision
POST /api/v1/calls/{id}/supervise (scope calls:supervise, your key or a member's token) dials a supervisor in with role monitor (listen), whisper (the agent hears them) or barge (everyone does). A member's token dials in that member; your key names supervisorMemberId and optionally a deviceId. With supervisorLegId an existing supervisor leg changes role in place.
Web devices take calls
A browser gets no push. While it is registered, it reads the calls ringing it from GET /api/v1/devices/{deviceId}/offers and answers with POST /api/v1/calls/{id}/answer { deviceId }: SiteCall hands the call to that device's WebRTC credential (POST /api/v1/credentials). @sitecall/web does all of this for you (Quickstart).
After the call
- Recordings (
media:read):GET /api/v1/recordings?callId=, and/recordings/{id}/linkfor a download URL that lasts about 15 minutes.recording.readysays when one is stored. - Transcripts:
GET /api/v1/transcripts?callId=lists each recording's transcript with its status (pending,processing,completed,empty,failed);GET /api/v1/transcripts/{id}has the text, per-party segments and channels (channel 0 is the outside party).transcript.readycarries the text and the first segments. - Voicemail:
GET /api/v1/voicemails, their links, andvoicemail.ready. - Texts (your key,
messages:*):POST /api/v1/messagessends an SMS or MMS from a workspace number or your application's system sender; the Idempotency-Key makes a retry the same message. Replies arrive asmessage.received, progress asmessage.status. A customer who texted STOP is refused (recipient_opted_out) until they text START.