Skip to main content

Two ways to place a call

Both originate from your number and, in sandbox, are locked to your signup number. A production key removes that lock.

Read the call log

GET /v1/calls returns your calls newest-first with cursor pagination. Needs the calls:read scope.
Pass next_cursor back as ?cursor= to page. Destination numbers are masked.

Fetch a recording

GET /v1/calls/{call_id}/recording returns a time-limited download URL (valid ~60 minutes). Needs the recordings:read scope and a production key.
A recording exists only if the call was recorded (via a <Dial record> or a background <Record>) and storage is provisioned for your account. Until then this returns 404 RECORDING_NOT_FOUND or 503 RECORDING_SERVICE_UNAVAILABLE. Sandbox keys get 400 SANDBOX_KEY_NOT_ALLOWED.

Control a live call

Change a call while it is live: POST /v1/calls/{call_id}/{action}, where action is hangup, hold, unhold, mute, unmute, dtmf ({"digits"}), play ({"url"}, a public https URL), recording/start or recording/stop. Needs the calls:write scope. A 200 means the voice engine accepted the command.
  • Works on calls Wave placed (callbacks and outbound calls) and on inbound calls to your numbers. Web-calling calls return 409 CALL_NOT_CONTROLLABLE (the SDK controls the browser’s own leg).
  • hangup works from initiated; every other action needs an answered call.
  • The optional body field leg picks the leg: "customer" (default) or "agent", the agent connected now by a <Dial> or a queue. With no connected agent you get 409 AGENT_LEG_NOT_CONNECTED. The response tells you the leg.
In-call control is turned on per environment, and the agent leg and the recording routes each have their own switch. While a switch is off, the route returns 503 CALL_CONTROL_DISABLED.

Transfer a live call

Send the caller somewhere else: POST /v1/calls/{call_id}/transfer with a target. This is a blind transfer: the caller’s leg goes straight to the target, with no announcement to the target first. Do not depend on the current agent leg staying connected after the transfer. Needs the calls:write scope. A target that has a bad format or is not your organization’s returns 422 TRANSFER_TARGET_INVALID. The call must be answered, and only one transfer can be in progress on a call (409 TRANSFER_IN_PROGRESS).
Wave answers 202 at once. When the transfer has a result, Wave sends one call.transferred webhook with an outcome: answered, no_answer, busy, failed, cancelled, enqueued (queue target) or expired (the voice engine did not act on it). If the target does not answer, the call ends. Read a call’s transfers and their outcomes with GET /v1/calls/{call_id}/transfers (calls:read scope). On a simulated sandbox call, the transfer completes at once with outcome answered, and the webhook is marked simulated.
Call transfer has its own switch per environment, and it is not available in production yet. While it is off, the route returns 503 CALL_CONTROL_DISABLED.

Next steps

Web Calling

Place calls from the browser with the SDK.

Webhooks

Get call events pushed to you instead of polling.