Consent & PII policy
Consent & PII policy API
Two org-scoped surfaces that back the legal record of your calling: consent (may we dial this number, and what proves it) and PII policy (what personal data we strip from transcripts and recordings, and what proves that).
Both authenticate with a user JWT + X-Org-Id — not an API key. Both are org-scoped under /api/orgs/{orgId}/…. Concepts and obligations are in Telephony compliance, US calling compliance and Data protection; this page is the endpoints.
Consent ledger
/api/orgs/{orgId}/consent
Proof-of-consent for outbound dialling (TCPA). Reads are open to any member — anyone in the workspace may ask whether a number is dialable. Writes need the manage tier: owner, admin or developer. That split matches DNC exactly, because the two are halves of one legal record.
| Method | Path | Purpose |
|---|---|---|
POST | / | Record consent for a number |
GET | /coverage | What enforcement would block right now — read-only |
PUT | /enforcement | Set the org's dial-time enforcement mode |
GET | /{phone} | Full consent history for one number |
POST | /{phone}/revoke | Revoke and suppress — writes through to DNC |
Recording consent
curl -X POST https://api.telenow.ai/api/orgs/$ORG/consent \
-H "Authorization: Bearer $JWT" -H "X-Org-Id: $ORG" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "+15551234567",
"consentType": "express_written",
"scope": "marketing",
"source": "web_form",
"capturedAt": "2026-03-12T09:14:00Z",
"evidence": { "formId": "signup-v3", "submissionId": "abc123" }
}'
| Field | Required | Values |
|---|---|---|
phoneNumber | Yes | E.164 |
consentType | Yes | express_written · express_oral · implied · existing_business_relationship |
source | Yes | web_form · import · api · ivr_dtmf · verbal_recorded · paper |
scope | No | marketing · transactional · service |
evidence | No | Free-form object — form id, submission payload, recording reference |
disclosureText, disclosureVersion | No | The exact wording the person agreed to, and its version |
capturedAt | No | Defaults to now |
expiresAt | No | When the consent lapses |
Set capturedAt when importing historical consent. It defaults to now, so a bulk import that omits it backdates every record to the import date — which destroys the one thing the record exists to prove.
Your evidence is enriched, not trusted wholesale. The server merges in its own provenance — recordedVia, the request User-Agent, and the first X-Forwarded-For address — alongside what you send. Your keys are preserved, so an integration can still attach its own form id. The reason: a consent record whose only evidence is client-supplied is exactly as strong as the client's word, and in a dispute the client's word is the thing being challenged.
Enforcement
PUT /enforcement takes {"mode": "off" | "required"}. Any other value is a 400. The default for an org is off.
Call GET /coverage before you flip it. Enforcement is a dial-time allow-list: with required, a number without a valid consent record does not get dialled. Coverage tells you how many of your contacts would be blocked the moment you switch, so you find out before a campaign does. Enforcement changes are logged at warn with the actor.
Revoking through POST /{phone}/revoke also writes to DNC — one call, both records, so a revocation cannot be honoured in one system and missed in the other.
PII policy
/api/orgs/{orgId}/pii
Which categories of personal data are stripped from transcripts and recordings, who changed that, and what the policy was on any given call.
Every endpoint here returns 404 when the feature is switched off for the deployment — deliberately, rather than answering with an empty policy. An endpoint that responds for a disabled feature invites an integration against something that is not running.
Reads are open to any member — "what do you strip from our transcripts" is a question anyone in the workspace may ask. Writes are owner or admin only: a floor is a contractual commitment, and lowering one should not be available to whoever happens to be logged in.
| Method | Path | Purpose | Role |
|---|---|---|---|
GET | / | Every rule: what the platform allows, what this org set | member |
GET | /changes | Who changed what, when, and why | member |
GET | /impact/{slug}?to= | What raising a floor would clamp, before you do it | member |
PUT | /rules/{slug} | Set this org's floor and its agents' default | owner/admin |
GET | /evidence?from=&to= | Per-call policy evidence over a date range | member |
GET | /calls/{sessionId}/policy | The policy that call actually ran under | member |
GET | /calls/{sessionId}/collected | Reveal the values a call captured under collect | owner/admin, see below |
Dispositions
Four, in increasing strictness:
| Value | Meaning |
|---|---|
off | The rule is not applied |
collect | The value is captured and stored, retrievable through the reveal endpoint |
redact | The value is masked before storage |
never_store | The value never reaches storage at all |
Setting a rule
curl -X PUT https://api.telenow.ai/api/orgs/$ORG/pii/rules/aadhaar \
-H "Authorization: Bearer $JWT" -H "X-Org-Id: $ORG" \
-H "Content-Type: application/json" \
-d '{ "floor": "redact", "defaultDisposition": "redact", "reason": "DPA with Acme" }'
floor is the strictest setting the org's agents may go below — it clamps them. defaultDisposition is what a new agent starts at. Sending null for either clears the override and returns to inheriting the platform value; omitting the key leaves it unchanged. reason is free text and lands in /changes.
The setting and its change-log entry are written in one transaction, so "who raised our floor, when, and why" can never be answered with a setting that has no log line.
Check GET /impact/{slug}?to=<disposition> first. It returns the agents that would be clamped by raising the floor, without changing anything. Omitting ?to= is a 400.
Revealing collected values
GET /calls/{sessionId}/collected is the tightest authorization on any call surface in the product, and deliberately so:
- It requires
owneroradmin. - It is refused outright during a support session, with
403. A support operator acting on a customer's behalf carries the owner's identity, so a plain role check would have passed — and the access log would then have recorded the customer's own owner as the reader of their caller's card number, pointing the audit trail away from whoever actually read it. The account owner must retrieve these values themselves.
GET /evidence requires both from and to; omitting either is a 400. It answers the question an enterprise buyer actually asks — "prove redaction was on for our org on 12 March" — from the per-call policy snapshot rather than by re-deriving today's policy.