AI Consent Ledger: Stop Voice Agents From Ignoring Revoked Permission A developer proposes an AI consent ledger to solve the state-management problem when voice agents ignore revoked permissions across channels. The append-only record tracks permission events and provides a fast read model to check consent before any agent action, preventing trust incidents from fragmented consent state. A voice agent can sound polished, respond instantly, and still create a trust incident in one sentence: “Stop calling me.” If that request only updates the SMS path, your agent may keep dialing tomorrow. If it only updates a call transcript, your follow-up workflow may keep texting. For builders shipping AI callers, inbox agents, scheduling bots, or multi-step outreach workflows, consent is no longer a static checkbox. It is runtime state. That is where an AI consent ledger helps. It gives every agent action a simple rule: before contacting, enriching, recording, or escalating a person, check the latest consent state from one durable place. This guide shows how to design that ledger without turning your product into a compliance maze. This is technical architecture guidance, not legal advice. If your workflow touches regulated outreach, health, finance, employment, or sensitive personal data, involve a qualified legal reviewer. Traditional apps usually ask for permission at predictable moments: signup, newsletter opt-in, cookie banner, phone number capture, or billing consent. AI agents blur that boundary. A production agent may: Each step may be valid by itself. The risk appears when consent changes in one channel and the rest of the workflow does not notice. The common failure shape is simple: That is not an LLM problem. It is a state-management problem. An AI consent ledger is an append-only record of permission events plus a fast read model that answers one question: Is this specific agent allowed to perform this specific action for this person right now? The ledger should track consent and revocation across channels, identities, agents, workflows, tools, and time. It is not just a subscribed: true column. A useful ledger stores: For AI workflows, the most important part is not the log. It is the policy check before action. Start by mapping every place an agent can create, use, or change permission state. A user may say: Do not bury these phrases inside transcripts. Extract them as candidate consent events. Voice revocation is tricky because the agent may hear it during a long conversation. You need a separate classifier or deterministic phrase layer that watches for permission changes, not only a final summary. Most teams handle STOP , UNSUBSCRIBE , and START first. That is necessary, but users do not always speak in exact keywords. You also need to catch natural language: Exact keywords can be deterministic. Natural language can be classified, then routed to confirmation or human review when uncertain. An agent may draft or send email from a workflow that was originally voice-based. If email has a separate consent purpose, the ledger must know that. Consent should not silently expand just because the agent has another tool available. Many AI workflows begin with imported contacts. That import may include old consent flags, partial channel history, or no evidence at all. Treat imported permission as lower-trust until verified. Store the source and timestamp so the agent can choose a safer mode. Humans need override paths, but overrides should be explicit events with reasons, not invisible admin edits. A good override record answers: Keep the write model append-only. Build a separate current-state view from it. Here is a compact TypeScript-style model: type ConsentChannel = "voice" | "sms" | "email" | "push" | "in app"; type ConsentPurpose = | "support followup" | "appointment reminder" | "marketing outreach" | "transactional update" | "recording" | "data enrichment"; type ConsentEventType = | "granted" | "revoked" | "limited" | "confirmed" | "expired" | "human override"; type ConsentEvent = { id: string; tenantId: string; subjectId: string; // person/customer/contact normalizedContact: string; // phone/email/device id hash channel: ConsentChannel; purpose: ConsentPurpose; eventType: ConsentEventType; scope: "single channel" | "all channels" | "all outreach"; source: "voice agent" | "sms keyword" | "web form" | "crm import" | "human"; evidenceRef: string; // transcript span, form id, message id, admin note confidence: number; // 0..1 for AI-extracted events workflowRunId?: string; agentId?: string; createdAt: string; expiresAt?: string; }; A few details matter: scope prevents “stop calling” from accidentally becoming “stop everything” unless policy says so. purpose stops consent for appointment reminders from becoming consent for promotions. evidenceRef lets you explain why the system made the decision. confidence lets uncertain AI-extracted events pause instead of acting blindly.Before any state-changing or contact action, ask the ledger for a decision. type ConsentDecision = { allowed: boolean; reason: string; matchedEventIds: string ; requiresHumanReview?: boolean; safeAlternative?: "do not contact" | "in app only" | "ask for confirmation"; }; async function canAgentAct input: { tenantId: string; subjectId: string; channel: ConsentChannel; purpose: ConsentPurpose; action: "call" | "text" | "email" | "record" | "enrich"; workflowRunId: string; } : Promise