AI disclosure & consent
Two obligations get confused with each other, and CallAgent handles them differently — one partially, one not at all. Read this before you assume either is covered.
| Obligation | Roughly | What CallAgent does |
|---|---|---|
| Telling the caller they are talking to a machine | EU AI Act Article 50 | nothing No feature does this. |
| Telling the caller the call is recorded | GDPR, ePrivacy, two-party-consent regimes | an announcement It can be played. A refusal cannot be honoured. |
This page is not legal advice. It is an accurate description of what the software does, so that your legal advice is given about the right thing.
AI disclosure
Nothing in CallAgent makes an assistant disclose that it is an AI.
compliance_planon an assistant — includingidentity_disclosure_required— is validated, stored, versioned, published, and included in the snapshot the voice gateway receives. The gateway never reads it.- The first message is validated for length and template syntax. No content rule requires a disclosure, and nothing checks for one.
- The only Article 50 disclosure anywhere in the codebase is hardcoded into CallAgent's own outbound sales demo, which refuses to place a call if the disclosure string is empty. That mechanism is not exposed to customer assistants.
There is also no jurisdiction logic. Nothing branches on the caller's country to decide what must be said.
Do it yourself, like this
Put the sentence in first_message, make it the first thing said, and stop it being talked over:
{
"first_message_mode": "assistant_speaks_first",
"first_message": "Hello, this is an automated assistant from Example Ltd. How can I help?",
"first_message_interruptions_enabled": false
}Three details that matter:
first_message_modemust beassistant_speaks_first. Withassistant_waits_for_usernothing is said until the caller speaks, and withassistant_speaks_first_with_model_generated_messagethe model writes the greeting — which means the disclosure is a suggestion, not a guarantee.first_message_interruptions_enabled: false— the default, and leave it there. Callers routinely talk over the first second of a connected call. If barge-in is enabled on the greeting, the disclosure is abandoned mid-word.- Put it in
first_message, not insystem_prompt. A system prompt is an instruction the model may or may not follow.first_messageis spoken verbatim.
For an outbound campaign the same applies to the campaign's assistant. There is no campaign-level disclosure field.
A variable that does not resolve renders as an empty string
{{company_name}} with nothing bound produces Hello, this is an automated assistant from . How can I help? — the disclosure survives, the company name does not. If you template the greeting, set template_strictness: "strict" so an unbound variable is an error at publish rather than a gap on a call. Then check POST /assistants/{id}/render-prompt, which returns a missing list.
Recording consent
What can happen
{
"recording_consent_plan": {
"required": true,
"mode": "announcement",
"prompt": "This call is recorded for quality and training purposes.",
"regions": ["RO", "DE"]
}
}mode is one of:
mode | Effect |
|---|---|
none | Default. Nothing is said. |
announcement | The prompt text is spoken before the greeting. |
assistant_spoken | The assistant speaks the prompt in its own voice. |
custom_audio | An audio file at audio_url is played. |
The organization-level policy has its own defaults, which the assistant's plan merges over: recording enabled, dual_channel, consent policy none, and on refusal continue.
What cannot happen
Three things you must design around
1. Recording starts before the announcement is spoken. The recorder is constructed and started, and playout begins, and then the consent announcement is played. The first seconds of audio — including the announcement itself — are already being written.
2. A refusal cannot be honoured. The gateway reports exactly one consent state to the control plane: announced. It never reports granted or denied, because there is no acknowledgement mechanism — no DTMF prompt, no phrase matcher. on_refusal is carried in the call config, is not read, and cannot fire. The control plane has a method that pauses recording on a denial; nothing on a real call calls it.
3. regions is documentation. Nothing branches on it. The service that computes the plan says in its own comment that it does not determine whether a recording is lawful.
So the honest reading of consent_state on a call:
| Value | What it means |
|---|---|
not_required | The policy asked for nothing. |
announced | A notice was played. Not that anybody agreed. |
pending | The plan wanted a notice and it has not been played yet. |
granted / denied | Reachable through the control plane's own API. Never produced by a live call. |
If your obligation is "inform", an announcement satisfies it. If your obligation is "obtain and honour consent", CallAgent does not do that today — handle it before the call reaches the assistant, or do not record.
Turning recording off entirely
The reliable control is not to record:
{ "artifact_plan": { "recording_enabled": false } }or per number:
{ "recordingMode": "disabled" }or per queue, with recording_policy: "disabled".
Redaction is not audio redaction
PII redaction runs once, at finalisation, over text: message contents, the transcript, the summary and event payloads. Categories are card (Luhn-validated), national_id (US SSN, Romanian CNP, UK NINo), email, phone, iban and custom patterns you supply. It is off by default; enabling it defaults to card and national_id.
artifact_plan.pii_redaction.redact_recording exists as a field. The recording audio is never modified. If a caller reads a card number aloud, it is in the WAV.
To keep it out of storage at all, use zero data retention or do not record.
Zero data retention
The strongest switch available. With zero_data_retention on the organization's retention policy:
- message contents, tool arguments and results, and word timings are nulled;
- event payloads are nulled, the event rows survive;
- the call's transcript, summary, analysis, structured output and topics are nulled;
- recording artifacts are deleted; the artifact row survives, marked
purged, as evidence that something existed.
What is deliberately kept: the call id, status, duration, the two E.164 numbers, costs, metrics, legs and the audit log. Billing and dispute resolution need those, and none of them is conversation content.
With zdr_delay_minutes: 0 this runs inline at call finalisation, not on the nightly job.
Audit
Every supervisor action — listen, whisper, barge, force-state, force-logout, end — writes an audit row on success, on denial and on exception. An attempt is never invisible.
The audit log is insert-only and has an exclusion list, so credentials are never written into it.
What to do
- Put your AI disclosure in
first_message, with interruptions off. - Decide whether an announcement satisfies your recording obligation. If it does not, do not record.
- Enable PII redaction if transcripts will be retained, and remember it does not touch audio.
- Set retention per category, or zero data retention, rather than relying on manual deletion.
- Read What is not built before you write any of this into a DPA.
Next
- Recording & storage — where the audio goes and who owns it.
- Security — keys, tenancy, audit.