Skip to content

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.

ObligationRoughlyWhat CallAgent does
Telling the caller they are talking to a machineEU AI Act Article 50nothing No feature does this.
Telling the caller the call is recordedGDPR, ePrivacy, two-party-consent regimesan 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_plan on an assistant — including identity_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:

json
{
  "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:

  1. first_message_mode must be assistant_speaks_first. With assistant_waits_for_user nothing is said until the caller speaks, and with assistant_speaks_first_with_model_generated_message the model writes the greeting — which means the disclosure is a suggestion, not a guarantee.
  2. 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.
  3. Put it in first_message, not in system_prompt. A system prompt is an instruction the model may or may not follow. first_message is 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.

What can happen ​

json
{
  "recording_consent_plan": {
    "required": true,
    "mode": "announcement",
    "prompt": "This call is recorded for quality and training purposes.",
    "regions": ["RO", "DE"]
  }
}

mode is one of:

modeEffect
noneDefault. Nothing is said.
announcementThe prompt text is spoken before the greeting.
assistant_spokenThe assistant speaks the prompt in its own voice.
custom_audioAn 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:

ValueWhat it means
not_requiredThe policy asked for nothing.
announcedA notice was played. Not that anybody agreed.
pendingThe plan wanted a notice and it has not been played yet.
granted / deniedReachable 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:

json
{ "artifact_plan": { "recording_enabled": false } }

or per number:

json
{ "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 ​

  1. Put your AI disclosure in first_message, with interruptions off.
  2. Decide whether an announcement satisfies your recording obligation. If it does not, do not record.
  3. Enable PII redaction if transcripts will be retained, and remember it does not touch audio.
  4. Set retention per category, or zero data retention, rather than relying on manual deletion.
  5. Read What is not built before you write any of this into a DPA.

Next ​

Documented against the code. Anything not yet implemented is labelled, never described as working.