Skip to main content
Unpod records a call as one WAV file, with each person on their own channel. Once the call has ended, ask the API for the recording, then download the audio with the same credentials.
Whether a call is recorded follows the recording policy (set by the Unpod team). To change it, ask them. record=True on a call doesn’t override the policy today, and the record setting in a number’s inbound config is stored but not applied yet.

Get a recording

Export your credentials (UNPOD_BASE_URL, UNPOD_PLATFORM_TOKEN, UNPOD_ORG_HANDLE). After the call ends, get_recording returns the recording’s details. Until the recording is saved it raises 409 (the call is still going) or 404 (it has just ended), so wait a few seconds and ask again. A wrong call_id also returns 404, so it only fails once the retries run out:
The response:
An unknown call_id, or one from another org, returns 404 not_found. After hangup, GET /sbc/v1/calls/{id} returns the same details, but its url is a path inside Unpod: download from the url that get_recording returns.

Download the audio

Request the same URL with the header Accept: audio/wav, plus the same Authorization and Org-Handle headers as every other API call. Without Accept: audio/wav you get the JSON above. The file is about 1 MB per minute of call.
A 200 means call.wav holds the audio. A call with no recording returns 404, and call.wav then holds the error instead. The URL only works with your credentials, so download the file and serve it from your own storage rather than handing the URL to a browser.

Format

The first leg (A) is on the left channel and the second leg (B) on the right. To get each person in their own file, split the channels with sox or ffmpeg:
Both keep the μ-law encoding; for an A-law file, use -c:a pcm_alaw with ffmpeg (sox keeps the input encoding by itself). Python’s wave module can’t open G.711 WAV files (it fails with unknown format: 7 for μ-law, 6 for A-law), and audioop is gone from Python 3.13. If a tool needs 16-bit PCM, convert the file first with sox or ffmpeg: sox call.wav -b 16 -e signed-integer call-pcm.wav.

Recording events

When a recorded call ends, Unpod sends MPCRecordingCompleted to the call’s recording_callback_url only, never to status_callback_url. Set it on create, or in a number’s inbound config. The event carries ev.call_id, ev.recording_url and ev.recording_duration. Treat it as a hint that the recording is ready:
  • It isn’t signed yet, so parse_call_event with your secret rejects it. Parse it with verify=False and trust only what get_recording returns for ev.call_id.
  • It carries no metadata, so match it to your own records by ev.call_id.
  • ev.recording_url is a path inside Unpod, not a download link. Call get_recording(ev.call_id) for the url.
  • It may never arrive for a call started with create. The reliable way is to call get_recording after the call’s Hangup, as above.
The /recording route in Number Masking handles the event this way. With record_participant_track=True (which needs record=True), the same URL also gets ParticipantRecordingInitiated and ParticipantRecordingCompleted for each leg. Both arrive together after the call ends, and both carry the leg’s channel in ev.metadata["channel"]: 1 for the first leg (left), 2 for the second (right). Only ParticipantRecordingCompleted carries the recording, in ev.metadata["recording_url"]: the same 2-channel file, at the same path inside Unpod. Answer URL <Record>. When a <Record> in your answer-URL reply reaches its maxLength (300 s by default), Unpod sends RecordStop to your answer URL with ev.recording_url. That’s the same path inside Unpod: once the call ends, get the audio with get_recording(ev.call_id).

Record part of a call

calls.record asks Unpod to start recording a call that’s still going:
It returns as soon as the request reaches the call, before recording starts, so it doesn’t report whether recording started. A call that has ended returns 404 not_found. A call the recording policy already records keeps that one recording. Whether get_recording returns a recording started this way isn’t confirmed yet. transcribe=True is accepted, but no transcript is made yet.

Tell callers

Many places require you to tell people, and sometimes to get their consent, before you record a call. Check the rules where you and the people you call are.
Say it at the start of the call. On an inbound call, put a <Speak> first in your answer-URL reply:
On a call you start with create, speak the same line when the leg sends Answered. If the recording policy records the call, you don’t need <Record/>. Never put <Record/> before <Dial>: Unpod waits for the recording to reach its maxLength (300 s by default) before dialing, and the caller hears silence.