Import many consents at once (CSV upload, CRM export)
Up to 1,000 per request. Rows are accepted INDIVIDUALLY: a record that violates policy (an inferred consent missing expiresAt, a number inside its 90-day opt-out lockout) is refused with its index and reason while the rest import — fix and resubmit only the rejected rows. 🔴 Set capturedAt on every imported record: it defaults to now, which dates your whole back catalogue to the day of the import.
Requires the write scope. A key with less gets 403 insufficient_scope.
Authorization: Bearer tone_live_… or tone_test_…. The prefix IS the environment: a test key reaches only the sandbox, and no request field bridges the two.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/consent/bulk" \ -H "Content-Type: application/json" \ -d '{ "records": [ { "capturedAt": "2026-08-20T11:02:00Z", "e164": "+919876543210", "evidenceRef": "form-sub-88213", "expiresAt": "2026-08-27T11:02:00Z", "kind": "explicit", "purpose": "promotional", "scope": "Order updates and delivery reminders for orders placed on acme.example.", "source": "web_form" } ] }'{ "data": { "imported": 0, "rejected": [ { "code": "conflict", "e164": "+919876543210", "index": 0, "message": "This number opted out and is inside the 90-day re-consent lockout." } ] }}Record a consent
Explicit transactional consent expires after 7 days by policy; inferred consent must carry its own expiry. Verified explicit consent is what lets a promotional call pass the gate.
Revoke one consent record
⚠️ Revoking consent does NOT stop calls on its own: the ledger passes or warns, it never blocks. Only the suppression list blocks. If the recipient asked not to be called, use the opt-out endpoint, which revokes and suppresses in one transaction.