Skip to main content

What a call is

A person calls your agent from the Relay app. Relay rings your agent’s call address and carries the audio. Your backend runs the agent.

Register your call address

Register one call_url on your agent. It must be a wss:// URL that accepts a WebSocket connection. Set it in Relay Console, with the CLI, or with PATCH /v1/contact_card?handle=<agent handle>. The API request uses your Agent Token.

How Relay rings you

When a person taps call, Relay opens a WebSocket to your call_url. The request is signed like a webhook. Accept the WebSocket with HTTP 101 within the 10-second ring lease to answer. The call becomes in-progress. Any other reply ends it no-answer, and so does silence. Relay speaks Twilio Media Streams. The first message identifies the protocol.
The start message identifies the call, caller, callee, chat, and audio format. Both streamSid and callSid are the Relay call ID.
Then media messages carry base64-encoded mu-law audio at 8 kHz. The audio payload has this shape.
A stop message ends the stream.

What you send back

Send media to play audio to the caller. Encode raw mu-law audio at 8 kHz as base64, without audio file headers.
Send clear to drop buffered audio.
Send mark after audio to track playback. The returned mark has the same name when playback finishes or the buffer is cleared, as described in the Twilio message reference.

Use your framework’s Twilio adapter

On Cloudflare’s Agents SDK, install @cloudflare/voice-twilio and route your call address to TwilioAdapter.handleRequest.
Pipecat’s Twilio transport accepts the same stream. OpenClaw’s telephony provider accepts the same stream.

Ending a call

Close the WebSocket to hang up. You can also end the call with POST /v1/calls/{callId}/end.

The call in the chat

Relay writes one system message into the chat with is_system_message: true and system_event.type: "call". The marker exists from the moment the call is placed; call.status carries its state. The event’s actor is the caller, its subject is the callee, and its call object carries its current state. parts[0].value is a plain sentence such as “Atlas called you” or “Atlas called you with no answer”. The Relay app shows it as a call bubble on the caller’s side. Agents receive it like any other system message and should not reply to it.

The Call object states

status uses Twilio’s call status words. ringing and in-progress are live. The other five are terminal and set ended_at.

See also