voepy

Recordings

A recording is the stored audio of a call or conference. voepy captures it for you, stores it, and hands back a downloadable file plus metadata (duration, format, channel layout, size). You list, fetch, download, and delete recordings through the /v1/recordings resource.

All paths under /v1/. Authorization: Bearer <api-key> required. Bodies are JSON, field names snake_case, timestamps ISO-8601, IDs opaque prefixed strings. A recording id looks like voepy_rec_….

How recordings get created

You never POST to /v1/recordings. A recording row appears as a side effect of a record action on a live call or conference. The flow is:

  1. You start recording on an in-progress call or conference (or ask for recording at dial/answer time).
  2. The audio is captured for as long as recording is active.
  3. When recording stops — on hangup, on an explicit stop, or at a configured limit — the audio is finalized and stored.
  4. voepy fires a recording.completed webhook and the recording becomes retrievable at GET /v1/recordings/{id}.

Recording a call

Two ways to record a call:

  • At dial or answer time. Pass record (and optionally record_channels, record_format) when you place an outbound call or answer an inbound one. See Calls.
  • Mid-call. Toggle recording on an answered call with the record actions:
POST /v1/calls/{id}/actions/start_recording
{ "channels": "dual", "format": "mp3", "play_beep": true }
POST /v1/calls/{id}/actions/stop_recording
{}

Full action reference (including max_length) lives in Calls.

Recording a conference

Conferences record at the bridge level — one file for the whole room — and support pause/resume on top of start/stop:

POST /v1/conferences/{id}/actions/record_start
POST /v1/conferences/{id}/actions/record_pause
POST /v1/conferences/{id}/actions/record_resume
POST /v1/conferences/{id}/actions/record_stop

A conference recording is stored against the conference's host call, so it shows up in that call's recordings array and is filterable by that call_id. See Conferences for the action bodies.

The Recording resource

{
  "id": "voepy_rec_01HXYZ123abc456def789012abcdef10",
  "call_id": "voepy_call_01HXYZ123abc456def789012abcdef01",
  "channels": "dual",
  "format": "mp3",
  "duration_seconds": 132,
  "size_bytes": 671088,
  "download_url": "https://media.voepy.com/recordings/voepy_rec_…mp3?sig=…",
  "status": "available",
  "created_at": "2026-05-12T14:33:01.880Z"
}
FieldTypeNotes
idvoepy_rec_…Opaque recording id.
call_idvoepy_call_…The call this recording belongs to. For a conference recording, this is the host call.
channelsenumsingle (mono, both parties mixed) or dual (stereo, each leg on its own channel).
formatenummp3 or wav.
duration_secondsintegerRecorded length in whole seconds.
size_bytesintegerFile size of the stored audio.
download_urlstring (URL)Time-limited URL to the audio file. May be empty until the recording is finalized. See Downloading.
statusenumavailable, archived, expired, or failed. See below.
created_attimestampWhen the recording row was stored (recording finalized).

Status values

StatusMeaning
availableStored and downloadable.
archivedSoft-deleted by you (via DELETE). The row remains for your history; the audio is no longer served.
expiredPast its retention window; audio no longer available.
failedCapture or storage errored — no usable audio. You'll have gotten a recording.failed webhook.

A recording is downloadable only while status == available. Fetching audio for any other status returns 409 recording_not_ready.

List recordings

GET /v1/recordings
  ?call_id=voepy_call_01HXYZ123abc456def789012abcdef01
  &page=1
  &page_size=50
Query paramDefaultNotes
call_idFilter to one call's recordings (includes any conference recording hosted on that call).
page11-indexed page number.
page_size20Rows per page, max 200.

Results are scoped to your tenant and ordered newest-first. The response is the standard page envelope:

{
  "count": 3,
  "next": "https://api.voepy.com/v1/recordings/?page=2",
  "previous": null,
  "results": [ /* Recording objects */ ]
}

next/previous are null at the ends. Recordings also appear inline on the parent Call resource (recordings: [...]) when you fetch a call directly — see Calls.

Retrieve one recording

GET /v1/recordings/{id}

Returns a single Recording. Unknown or non-owned ids return 404.

Downloading the audio

download_url points at the stored audio file. It is time-limited and signed — fetch it fresh from the API rather than caching it long-term, because a stale URL will stop resolving once its signature window passes.

# 1. Get the recording (fresh signed URL)
curl https://api.voepy.com/v1/recordings/voepy_rec_… \
  -H "Authorization: Bearer $VOEPY_KEY"

# 2. Download the audio from the returned download_url
curl -L -o recording.mp3 "https://media.voepy.com/recordings/voepy_rec_…mp3?sig=…"

Notes:

  • The audio host is separate from the API host — you do not send your API key to download_url; the signature in the URL authorizes the fetch. Treat the signed URL as a short-lived secret.
  • download_url can be empty for a brief moment between the record action and finalization. Wait for the recording.completed webhook (or re-fetch) before downloading.
  • If status != available, there's nothing to download — see status values.

Storage, retention, and deletion

Recordings stay available until their retention window elapses, at which point status flips to expired and the audio stops being served. The metadata row persists either way so your call history stays intact.

To remove a recording yourself:

DELETE /v1/recordings/{id}

This is a soft delete. voepy flips the recording's status to archived and stops serving the audio. The metadata row is kept on purpose so your historical and billing records line up. There is no endpoint that restores archived audio, so treat the delete as permanent for the file.

DELETE returns the updated Recording (with status: "archived") and HTTP 200 — not an empty 204. Deleting a recording already in a failed state returns 409 recording_not_ready (there's no audio to remove).

Transcription

Recordings and transcription are independent features. voepy does not auto-transcribe stored recordings. If you want text, use real-time transcription on the live call (POST /v1/calls/{id}/actions/transcription_start), which streams call.transcript_chunk webhooks and exposes the full session at GET /v1/calls/{id}/transcription. See Calls.

Webhooks

Two recording events fire to your subscribed endpoint:

EventWhen
recording.completedA call or conference recording is stored and ready to download.
recording.failedA recording errors before completion.

recording.completed payload:

{
  "event_type": "recording.completed",
  "data": {
    "call_id": "voepy_call_01HXYZ123abc456def789012abcdef01",
    "recording_id": "voepy_rec_01HXYZ123abc456def789012abcdef10",
    "channels": "dual",
    "format": "mp3",
    "duration_seconds": 132,
    "download_url": "https://media.voepy.com/recordings/voepy_rec_…mp3?sig=…"
  }
}

For a conference recording with no single host call, call_id is an empty string. recording.failed carries call_id, recording_id, and a short reason:

{
  "event_type": "recording.failed",
  "data": {
    "call_id": "voepy_call_…",
    "recording_id": "voepy_rec_…",
    "reason": "storage_unavailable: Recording could not be persisted within retention window."
  }
}

recording_id may be empty if no row was ever persisted. Listen for recording.completed before you try to download, rather than polling. See Webhooks for signature verification and retries.

Errors

Every error uses the standard envelope:

{
  "error": {
    "code": "recording_not_ready",
    "message": "Recording is not in a downloadable state."
  }
}
HTTPCodeWhen
400invalid_requestMalformed call_id filter or other bad input.
404not_foundRecording id is unknown or not owned by your tenant.
409recording_not_readyAction on a recording whose status isn't usable (e.g. deleting a failed recording).

Full list: Error reference.

Next

  • Calls — start and stop call recording, real-time transcription, and AMD.
  • Conferences — record a whole room with pause/resume.
  • Webhooks — subscribe to recording.completed and verify the signature.