AI Voice Agent Call Recording: TCPA, CCPA, and GDPR Compliance
Call recording compliance for AI voice agents — TCPA two-party consent states, CCPA disclosure, GDPR, and audit trails.
Recording is the easy part, compliance is not
Hitting "record" on a voice agent call takes one line of code. Staying legal across all US states, the EU, and the UK takes policy, disclosure logic, retention schedules, and audit trails. This post walks through the technical implementation of call recording compliance for AI voice agents, focused on TCPA two-party consent states, CCPA disclosure requirements, and GDPR lawful basis.
Disclaimer: this is engineering guidance, not legal advice. Work with counsel for your specific jurisdiction.
incoming call
│
▼
detect jurisdiction from caller ID / IP
│
▼
two-party state? ── yes ──► play consent prompt, wait for "yes"
│
no
│
▼
play one-party disclosure ("this call may be recorded")
│
▼
start recording + log consent event
Architecture overview
┌───────────────────────┐
│ Voice agent runtime │
│ • consent state │
│ • recording on/off │
└──────────┬────────────┘
│
▼
┌───────────────────────┐
│ Consent log (Postgres)│
└──────────┬────────────┘
│
▼
┌───────────────────────┐
│ Recording storage │
│ (S3 + KMS encryption) │
└───────────────────────┘
Prerequisites
- A jurisdiction mapping (NANPA area code → state, IP → country for WebRTC).
- A consent log table in Postgres.
- Encrypted storage for recordings (S3 + SSE-KMS or equivalent).
- Legal-reviewed disclosure scripts per jurisdiction.
Step-by-step walkthrough
1. Identify jurisdiction on ring
def jurisdiction_for_caller(caller_number: str) -> str:
# Lookup NPA → state
npa = caller_number[2:5] if caller_number.startswith("+1") else None
return NPA_STATE.get(npa, "unknown")
TWO_PARTY_STATES = {"CA", "CT", "DE", "FL", "IL", "MD", "MA", "MI", "MT", "NV", "NH", "OR", "PA", "VT", "WA"}
def needs_two_party_consent(state: str) -> bool:
return state in TWO_PARTY_STATES
2. Play the appropriate disclosure
async def run_disclosure(oai_ws, state: str):
if needs_two_party_consent(state):
script = "This call will be recorded for quality and training. Is that okay with you?"
else:
script = "Just so you know, this call may be recorded for quality purposes."
await oai_ws.send(json.dumps({
"type": "response.create",
"response": {"instructions": f"Speak this exactly: {script}"},
}))
3. Wait for explicit consent in two-party states
Set a flag on the session: awaiting_consent = true. Only start recording when the caller says yes.
CONSENT_YES = {"yes", "sure", "okay", "ok", "yeah", "fine", "that's fine"}
CONSENT_NO = {"no", "nope", "don't", "do not"}
async def handle_consent_turn(transcript: str, session):
t = transcript.lower().strip()
if any(w in t for w in CONSENT_YES):
session.consent = True
await log_consent(session.call_id, "granted")
await start_recording(session)
elif any(w in t for w in CONSENT_NO):
await log_consent(session.call_id, "refused")
await end_call_politely(session)
4. Log the consent event with immutable timestamp
CREATE TABLE consent_events (
id BIGSERIAL PRIMARY KEY,
call_id TEXT NOT NULL,
caller_number TEXT,
jurisdiction TEXT,
consent_status TEXT NOT NULL,
disclosure_script TEXT NOT NULL,
recorded_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
5. Store recordings encrypted with per-tenant keys
import boto3
s3 = boto3.client("s3")
async def upload_recording(tenant_id: str, call_id: str, wav_bytes: bytes):
key = f"tenants/{tenant_id}/calls/{call_id}.wav"
s3.put_object(
Bucket="cs-recordings",
Key=key,
Body=wav_bytes,
ServerSideEncryption="aws:kms",
SSEKMSKeyId=tenant_kms_key(tenant_id),
)
6. Honor deletion requests (CCPA, GDPR)
async def delete_caller_data(caller_number: str):
call_ids = await db.fetch("SELECT call_id FROM calls WHERE caller_number = $1", caller_number)
for cid in call_ids:
await s3.delete_object(Bucket="cs-recordings", Key=f"calls/{cid}.wav")
await db.execute("UPDATE calls SET transcript = NULL, deleted_at = now() WHERE call_id = $1", cid)
Production considerations
- Retention schedules: MiFID II = 5 years, HIPAA = 6 years, GDPR = "no longer than necessary". Store per-tenant policy.
- Access control: recordings are sensitive; gate playback behind signed URLs with short TTLs.
- Audit logs: who accessed a recording, when, and why.
- Breach notification: GDPR requires 72h breach notice.
- Cross-border transfer: EU recordings must stay in EU-region storage unless SCCs are in place.
CallSphere's real implementation
CallSphere builds consent detection, per-state disclosure scripts, and encrypted recording storage into every production deployment. The voice plane runs on the OpenAI Realtime API (gpt-4o-realtime-preview-2025-06-03) at 24kHz PCM16 with server VAD, and the consent gate fires before the first tool call. Recordings land in per-tenant S3 buckets with SSE-KMS, and access is gated through signed URLs from the admin UI.
The pattern applies uniformly across healthcare (14 tools, HIPAA-aware retention), real estate (10 agents), salon (4 agents), after-hours escalation (7 tools), IT helpdesk (10 tools + RAG), and the ElevenLabs sales pod (5 GPT-4 specialists). A GPT-4o-mini post-call pipeline redacts PII from transcripts before they flow into the analytics store. CallSphere supports 57+ languages with locale-specific consent scripts and maintains sub-second latency through the disclosure flow.
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
Common pitfalls
- Blanket "this call is recorded" in two-party states: not sufficient for consent.
- Forgetting consent logs: regulators will ask for proof.
- Global S3 bucket: violates GDPR data residency.
- No deletion API: CCPA and GDPR both require it.
- Unencrypted storage: this is a breach waiting to happen.
FAQ
Does TCPA apply to inbound calls?
Yes — recording rules apply regardless of direction.
Is IP-based jurisdiction detection reliable?
Good enough for WebRTC, but combine it with explicit disclosure everywhere.
What if a caller refuses consent in a two-party state?
End the call politely without recording and log the refusal.
How long can I keep recordings?
It depends on the jurisdiction and vertical; store a policy column per tenant.
Can I train on customer recordings?
Only with explicit opt-in consent spelled out in the disclosure.
Next steps
Need a compliance-ready voice agent? Book a demo, read the technology page, or see pricing.
#CallSphere #Compliance #TCPA #GDPR #CCPA #CallRecording #AIVoiceAgents
Written by
CallSphere Team
Expert insights on AI voice agents and customer communication automation.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.