---
title: "Get a short-lived playback link for one session's saved audio"
method: GET
path: "/voice/bridge/{id}/recording"
tags: ["voice"]
---

# Get a short-lived playback link for one session's saved audio

`GET /voice/bridge/{id}/recording`

## Request

- Base URL: `https://corebee.ai/api/v1`
- URL: `https://corebee.ai/api/v1/voice/bridge/{id}/recording`
- Auth: HTTP bearer

Returns metadata about the saved audio for one bridge session plus a `playback_url` you can put straight into an `<audio src>`. Requires the voice:bridge scope.

⛔ THE AUDIO IS THE AGENT-TO-BUSINESS LEG ONLY, AND THAT IS NOT A FOOTNOTE. Recording stops before the consumer is dialed, so the consumer's voice was NEVER CAPTURED and is not in the file. Every response says so twice, in `audio_scope`, which is always the literal string `agent_to_business_only`, and in `note`. DO NOT LABEL THIS "call recording" OR "the call" IN YOUR OWN UI. The consumer on that call never agreed to anything with you or with us, several U.S. states require all-party consent, and an implied-but-false scope is the part that creates liability. If you need a phrase, use "agent-to-business audio".

⛔ `playback_url` IS NOT AN OBJECT-STORE LINK AND MUST NOT BE TREATED AS A PERMANENT ADDRESS. It points at our host and carries an opaque token bound to your organization, this session and this one recording, valid for `playback_ttl_seconds` (900, fifteen minutes) from the moment of this call. It is revocable by us and it is not a credential you can store: DO NOT persist it, email it, or write it into a ticket. Re-request this endpoint whenever you need to play the audio again; that is one authenticated call and it is the intended flow. There is no sliding window, a token does not renew itself because you kept listening.

A SESSION WITH NO AUDIO IS A 200, NOT A 404. `audio_available: false` with `playback_url: null` means nothing was recorded for that call, which is the ORDINARY case: recording is a per-deployment opt-in and most sessions have none. A 404 means the session id is not one of yours (or does not exist), the two are deliberately not distinguishable, so a 404 never tells you whether some other organization owns that id.

`recording_duration_sec` IS THE LENGTH OF THE SAVED AUDIO, NOT THE LENGTH OF THE CALL AND NOT THE BILLED INTERVAL. It measures one leg. It is the SAME FIELD, BY THE SAME NAME AND THE SAME TYPE, that GET /voice/bridge and GET /voice/bridge/{id} already publish, so one duration column in your code works across all three. For billing use `joined_seconds` on /voice/bridge/usage; for wall-clock timings use the `timings` block on /voice/bridge/{id}. A call can be recorded for 41 seconds and never join anybody.

THIS ENDPOINT IS OFF UNLESS ASKOTTO_BRIDGE_RECORDING_PLAYBACK IS SET ON THE DEPLOYMENT, AND WHILE IT IS OFF IT ANSWERS 404, the same 404 as a session you do not own. That is deliberate: an off feature must not be distinguishable from a call you have no audio for, or the endpoint reports the existence of other people's recordings.

## Path parameters

- `id` integer, required

## Response `200`

OK. Audio metadata, and a playback link when audio exists.

- object
  - `data` object, required
    - `session_id` integer, required: The bridge session this audio belongs to.
    - `audio_available` boolean, required: False means nothing was recorded for this call. It does NOT mean the call did not happen, and it is not an error.
    - `audio_scope` 'agent_to_business_only', required: ALWAYS this one value. The recording covers the AI agent talking to the business; recording stops before the consumer is dialed, so the consumer is never on it. A one-value enum on purpose: there is no second scope, and a client that branches on it will never have to.
    - `format` string, nullable: Container of the saved audio. `mp3` on every recording made so far.
    - `channels` string, nullable: Telnyx channel mode of the saved file, e.g. `dual`. Both channels are still the SAME leg (agent and business); neither is the consumer.
    - `recording_duration_sec` integer, nullable: Seconds of SAVED AUDIO for this call, the length of the mp3, as reported by the carrier (whole seconds). This is NOT the billed duration and it is NOT the whole call: see `joined_seconds` for what you are invoiced for. ⛔ SCOPE: the audio covers the AI-TO-BUSINESS leg ONLY. Recording stops before the consumer is dialed, so the consumer is never in it and was never recorded. Do not label this "call recording" in a UI shown to anyone who might reasonably read that as including the consumer. null when no recording exists for the session, which is the ORDINARY case, not an error: recording is a per-account feature and most sessions have no recording row at all. null ALSO when a recording exists but its length was never stored. It is never 0 for "unknown": a 0 would be a claim about the call, a null is a claim about our knowledge. This field never fails the request and never carries a link to audio.
    - `recorded_at` string, date-time, nullable: When the recording row was written.
    - `playback_url` string, nullable, required: Absolute URL on OUR host, carrying an opaque single-recording token. Feed it to an audio element or fetch it directly; it needs no Authorization header, which is exactly why it is short-lived. Null when `audio_available` is false.
    - `playback_expires_at` string, date-time, nullable: The instant the token stops working. After it, re-request this endpoint.
    - `playback_ttl_seconds` integer, required: Lifetime of a freshly minted token, in seconds. 900.
    - `note` string, required: The scope sentence, in words, for surfacing next to a play button.

## Other responses

- `401`: Invalid or missing credential
- `404`: No audio for this session. Returned identically for a session id you do not own, a session id that does not exist, and a deployment where the feature is switched off. It never reveals which.
- `503`: The playback subsystem could not answer (its tables are not present, or a write failed). Retryable. It is NOT returned for "this call has no audio", that is a 200.

---

[API](https://skmtc.dev/corebee/apis/corebee-api.md) · [All operations](https://skmtc.dev/corebee/apis/corebee-api/llms.txt) · [OpenAPI document](https://skmtc.dev/corebee/apis/corebee-api/revisions/a48ea543b4dc?raw)
