Docs · Setup
Security & DSR.
How we isolate tenants, encrypt secrets, redact PII, log audits, and handle data-subject requests under DPDP, TCPA, and GDPR.
Tenant isolation
Hard isolation, not row-level. Every store is partitioned per tenant:
- Postgres — schema per tenant (
cf_t_{id}) inside shared databases - MongoDB — database per tenant (
cf_t_{id}) - Qdrant — collections per tenant (
cf_t_{id}_company_kb,cf_t_{id}_customer_data) - HashiCorp Vault — path per tenant (
secret/cf/tenants/{id}/) - Redis — key namespace per tenant (
cf:t:{id}:*) - Object storage — prefix per tenant (
t_{id}/) - Keycloak — group per tenant (
t_{id}),tenant_idclaim in every JWT
Why: one missing WHERE tenant_id=… can leak across customers in a row-level
design. Schema/database/collection per tenant means there's no shared row to leak.
Auth & secrets
Passwords — Argon2id (OWASP 2024). Bcrypt legacy hashes rejected.
JWT — HS256, claims include sub, tid (tenant), role, exp, 7-day TTL. HttpOnly Secure cookie + bearer header fallback.
BYOK provider secrets — AES-256-GCM envelope-encrypted in Postgres. Master key in env or Vault, never logged. Decryption per-call, in memory.
Webhook signatures — Every inbound webhook (payment processor, Twilio) is signature-verified with replay-window protection.
PII redaction (pre-LLM)
Before every Claude call, customer data passes through the redactor. Patterns covered:
- Phone (E.164, Indian regional, US 10-digit)
- PAN (India)
- Aadhaar (India)
- SSN (US)
- IFSC, bank account number (India)
- Money amount
- Address (multi-line postal)
Tokens like {{phone:1}} survive the LLM round-trip and are reinjected
before customer-facing output. Logs keep the redacted form; full-fidelity originals live
only in the per-tenant tables.
Recording & consent
Voice — Recording disclosure played on the first turn of every call. Cannot be disabled. Consent record written per contact, per scope.
Consent scopes per contact: marketing_call, marketing_wa,
recording, data_sharing_with_creator, transactional_only.
Opt-out — Spoken opt-out parsed in-call ("don't call me again," "remove me from your list"), added to internal DNC immediately. Customer also receives a confirmation message on the channel they opted out from.
DNC + (post-launch) NCPR scrub
Internal DNC list per tenant: numbers added on opt-out, support escalation, or manual import. Outbound dialer filters against it before queueing.
India NCPR daily scrub is on the post-launch roadmap (Phase 8): we pull the TRAI registry once a day, fold into the exclusion set. Until that ships, NCPR enforcement is via your manual DNC additions + Exotel's own pre-call check.
DSR — export
POST /dsr/export with the contact identifier (phone or email) returns the
full bundle: every Contact record, every Conversation, every Turn, every Approval, every
consent record, every audit log entry — across all your collections.
Bundle is JSON + optional ZIP of call recordings. Returned in under 30 seconds because hard isolation means it's a single-schema query, not a cross-tenant search.
DSR — erase
POST /dsr/erase with the contact identifier:
- Drops the contact's Mongo documents (turns, conversations, decisions)
- Deletes Postgres rows per retention policy (configurable: default delete-immediately)
- Pseudonymises audit-keep rows (those we must retain for legal/regulatory reasons) — replaces PII with stable hashes
- Removes Qdrant chunks tagged to the contact
- Purges S3 prefixes (call recordings) for that contact
Audit trail of the erasure itself is retained (you have to be able to prove you erased them).
Audit logs
Per-tenant — every workflow change, every approval decision, every concession, every DSR action, every user login. Queryable from Dashboard → Audit or via API. Regulator format on request.
Global — tenant lifecycle events on the control plane: provisioning, suspension, archival, erasure. Internal; available to DPOs on request.
Data residency
India tenants → Mumbai. US tenants → us-east. EU tenants → eu-west (post-launch). Pick at tenant creation; we don't move silently. Cross-region DSR transit is logged.
Sub-processors
See the integrations page for the full list. DPA available on request to dpo@callfunnel.ai.
Disclosure
Security issues: security@callfunnel.ai (PGP on request).
DPDP / GDPR data-subject requests: dpo@callfunnel.ai.