Skip to content

Recordings

Recording is off by default and is decided for each call, at the moment the session is minted. Most calls have none, and an empty list from get_recordings is a real answer rather than a missing one.

The client developer’s explicit record wins in both directions, because they are the only party who knows whether this caller consented. They can turn it off for an agent that records by default just as easily as on.

What the mint request saysWhat happens
record: trueRecorded
record: falseNot recorded, whatever the agent’s default says
omittedThe agent’s configured default, which itself defaults to off

Omitting the field is how “let the agent decide” is spelled. It is a different thing from false, and the distinction is the whole reason the field is nullable.

One asymmetry, and it is about which key you hold

Section titled “One asymmetry, and it is about which key you hold”

A publishable (pk_) key may turn recording off. It may not turn it on.

A pk_ key ships in page source, so “the client developer” on that path is whoever can read the page. Turning recording off needs no trust — opting out of being recorded never does. Turning it on would let a stranger write voice into your bucket, on your bill, for an agent whose owner chose not to record.

That refusal is an HTTP 400 with code recording_not_permitted, and it starts no call. It used to be a silent fallback to the agent default, which meant a page asking to record could “work” by coincidence whenever the owner had already turned recording on — and then quietly not work the day they turned it off. A request that can only ever be a no-op is a bug in the page, and it should be found on the page’s first run rather than by an auditor looking for a call nobody recorded.

A pk_ embed that wants recording sets the agent’s default, which its owner controls: update_agent(recording=true) over the MCP server, or the same switch in the console.

See keys and authentication.

get_recordings(tenant, session_id) returns one track per side: role is user (the caller’s microphone) or agent (what was spoken back).

Two tracks rather than one mix is the point. Listening to them separately distinguishes “the agent said nothing” from “the agent was never asked anything” — which a mixed track cannot tell you, and which is the first question worth asking about a call that went quiet.

Each track carries its state, duration, size, content type, and a failure_reason if it has one.

A track in state completed carries a download_url: a short-lived signed URL you fetch with a plain unauthenticated GET.

It carries its own credential, so treat it as a secret. Do not write it anywhere durable — not a ticket, not a log line, not a spreadsheet. ttl_seconds sets its lifetime between 60 and 900 seconds, defaulting to the maximum. Fifteen minutes is long enough to download and short enough that a leaked URL is dead by the time anyone finds it.

Ask for a fresh one rather than holding one.

The call’s session.created event carries recording_enabled and recording_sourceclient when the mint request said so, agent_default when it did not. That is how you answer “why was this call not recorded” without guessing. See reading a call back.

get_session also carries the same recordings without URLs, for when you only need to know whether any exist.