Skip to main content
Every call leaves a call record: who took part, what was said, how the agent decided each turn, and the recording if recording was on. Fonoster signs each record when the call ends, so you can prove later that nobody changed it. This guide shows how to find records, download them and their recordings, and check their signatures.

Before you begin

You need:
  • A workspace with at least one finished call. The quickstart makes one in a few minutes.
  • For the SDK or the CLI: an API key and Node.js 22 or later. The quickstart shows how to install both and sign in.

What’s in a record

A record is a vCon, an open JSON format for conversations. Fonoster writes version 0.4.0 of the format. fonoster.missing lists what the record lacks: hangup when the call’s end was never seen (the record was sealed shortly after its last entry), or recording when a recording was asked for and none was made. A record doesn’t include logs, the language model’s prompts and responses, or SIP traces. A call that never reached an application, because it was busy, wasn’t answered or was rejected, gets a shorter record with the failure reason.

Versions

A record is sealed when the call ends, as version 1. A sealed version is never edited. When something changes later, such as a part being deleted, Fonoster seals a new version that points to the one before it. Reads return the latest version unless you ask for another.

Two copies: redacted and original

Each version comes in two copies:
  • Redacted, the copy you get by default. Payment card numbers, as digits or as number words in English or Spanish, are replaced with [card number] in the transcript, the turn decisions and the notes. It has no messages.ndjson. When a card number was redacted, the recording in this copy has a beep over it. If Fonoster can’t find the redacted words in the audio, this copy leaves the recording out and sets fonoster.recordingWithheld.
  • Original, unredacted, with messages.ndjson and the recording without beeps. Only workspace owners and admins can read it.
Redaction only finds card numbers. Other personal data, such as names or addresses, isn’t masked.

How a record is signed

Inside the region, when a call ends the record is sealed as version 1 and split into an original copy (transcript, messages.ndjson and recording, for owners and admins) and a redacted copy (card numbers replaced, recording beeped, the default). Both are signed as ES256 JWS with the region's key. Outside the region, a call_record.sealed webhook reaches your endpoint, the SDK, CLI or HTTP API fetches the record with GET /api/records/<callRef>, and you verify either copy against the keys the region publishes at /.well-known/call-record-keys.json. Inside the region, when a call ends the record is sealed as version 1 and split into an original copy (transcript, messages.ndjson and recording, for owners and admins) and a redacted copy (card numbers replaced, recording beeped, the default). Both are signed as ES256 JWS with the region's key. Outside the region, a call_record.sealed webhook reaches your endpoint, the SDK, CLI or HTTP API fetches the record with GET /api/records/<callRef>, and you verify either copy against the keys the region publishes at /.well-known/call-record-keys.json. Fonoster signs both copies of every version with the key of the region where the call ran. Each signature is a JWS with the ES256 algorithm. Each file the record points to, such as the recording, is listed with its SHA-512 hash, so the signature covers the files too. The region publishes its public keys at /.well-known/call-record-keys.json, including old keys, so records signed before a key change still verify. Records stay in the region where the call ran.

Know when a record is ready

Subscribe a webhook to call_record.sealed. Fonoster sends it for every new version of a record:
recordUrl is the record’s path on the API. When it’s a path, add your API’s address in front, such as https://api.fonoster.ai. The event never carries the transcript or the recording.

Find records

Go to Calls. Each row is a call, newest first. Open one to read its turns and its turn decisions. The dashboard shows the redacted copy.
These filters work on every surface:

Get a record

In Calls, open the call. The page header shows who called, the application, the length, why the call ended, and the record’s version.
--original and { original: true } need the owner or admin role. Without it, the request is refused with 403.

Download the recording

The recording is a stereo WAV file at 16 kHz: the caller on the left channel, your application on the right. There’s a recording only when the call’s recording policy was on. See Record calls and ask for consent.
Open the call in Calls and choose Download recording, then Save recording. When there’s none, the page shows No recording.
By default you get the redacted copy’s recording, with a beep over any card number. Add --original (CLI) or { original: true } (SDK) for the recording without beeps. If the redacted copy withheld the recording, only the original has it.

Use the HTTP API

The SDK and the CLI call these HTTP endpoints, which you can also call directly. Send your access token and your workspace with every request:
With the SDK, client.getAccessToken() returns the token after you sign in. This request fetches a record:

Verify a record

Verification proves that a record and its recording are exactly what the region signed. You check two things: the signature over the vCon, and the hash of each file it points to.
1

Download the signed record and its recording

Download the same copy of both. For the redacted copy:
For the original, add --original to both commands.
2

Check the signature and the recording

The signed record is a JWS in JSON form. Its protected header holds alg (ES256), typ (vcon+jws), kid, the ID of the signing key, and jku, the URL of the region’s key set.This script fetches the key set from jku, picks the key whose kid matches, checks the signature, then compares the recording’s SHA-512 hash with the one in the vCon:
verify-record.js
Run it next to the two files:
The record and its recording are exactly what the region signed.
A content hash is sha512- followed by the base64url SHA-512 of the file. The original copy also points to messages.ndjson in attachments, with its own content_hash, which you can check the same way. File urls in the vCon are relative, such as parts/recording.wav; download the files through the API.
A record proves it matches the key set its region publishes. The key isn’t backed by a certificate chain or an outside timestamp, so you trust the region’s published keys.
For every command and method, see Call records in the CLI reference and CallRecords in the Node SDK reference.

Next steps

Retention and erasure

Delete recordings after a number of days, or erase one call.

Record calls and ask for consent

Turn recording on, off, or on with consent.

Webhooks

Get call_record.sealed when a record is ready.

Node SDK

Every CallRecords method.