Consent Management & Receipts
Before you message a contact on a regulated channel you generally need a lawful basis — most often consent. Orbit’s consent API is the system of record for who opted in or out, on which channel, when, and under what legal basis. Every write fans out to the surfaces your sends are gated against, so recording consent here is what actually unblocks (or blocks) a message. All endpoints below are rooted athttps://api.orbit.devotel.io/api/v1/compliance.
Channels and states
Consent is tracked per channel. The supported channel set is:email, fax, instagram, line, messenger, push, rcs,
sms, viber, voice, whatsapp.
A (contact, channel) pair resolves to one of three states:
| State | Meaning |
|---|---|
opted_in | Consent granted and not revoked. |
opted_out | Consent revoked, or an explicit opt-out recorded. |
unknown | No consent record exists for the pair — your send gate decides the default. |
Recording consent
POST /compliance/consent records an opt-in or opt-out across one or
more channels in a single call. Identify the contact by contact_id
or by identifier (an email, E.164 phone, or WhatsApp ID — Orbit
resolves the type automatically).
201 Created:
| Field | Type | Notes |
|---|---|---|
contact_id / identifier | string | Provide one of the two. |
channels | string[] | One or more of the channel set; deduplicated and sorted. |
opt_in | boolean | Required. true = opt-in, false = opt-out. |
source | string | How consent was captured (e.g. web_form, import, double_opt_in). Default consent_api. |
consent_type | string | Purpose category, e.g. marketing, transactional. Default messaging. |
lawful_basis | enum | GDPR Art 6 basis: consent, contract, legal_obligation, vital_interests, public_task, legitimate_interests. |
purpose | string | Free text describing the use (≤ 500). |
consent_text_version | string | Version of the notice the subject agreed to. |
consent_proof_url | string (url) | Link to a screenshot or signed document. |
metadata | object | Arbitrary custom key/values. |
consent_records audit table, the
contact’s channel_preferences mirror (the read-side fast path your
sends check), the suppression_list (on opt-out), and a short-lived
Redis STOP-fence so in-flight campaign batches honour the change
within ~10 minutes.
Writes are partial-safe: if one channel fails, the others still
apply. Compare
consent_record_ids.length against the number of
channels you requested to detect a partial write. Re-recording an
opt-in for a channel that is already opted-in refreshes the
metadata/proof but keeps the original granted_at.Looking up consent
GET /compliance/consent/lookup returns the current state for one
(contact, channel) pair — use it as a pre-send gate.
state of unknown means no record exists for the pair — your
application decides whether that implies consent (some transactional
flows) or blocks the send (most marketing flows).
Consent history
GET /compliance/consent/history returns the full, paginated audit
trail for a contact — every grant and revocation, most recent first.
Query parameters: contact_id or identifier (one required), an
optional channel filter, limit (≤ 100, default 50), and an opaque
cursor.
Consent receipts (India DPDP) & Consent Managers
India’s Digital Personal Data Protection Act (DPDP) introduces the concept of a Consent Manager — an accountable, registered intermediary that mints cryptographically signed consent receipts on behalf of a data principal. Orbit can register the managers your users go through and verify the receipts they issue.Register a Consent Manager
POST /compliance/consent/managers (admin/owner) registers a manager
and stores its public key (an ECDSA P-256 SPKI PEM) used to verify
every receipt it signs.
GET /compliance/consent/managerslists registered managers (active first).PUT /compliance/consent/managers/{id}updates or deactivates one (partial update; all fields optional).
Store a signed receipt
POST /compliance/consent/receipts verifies a manager-signed receipt
and persists it as consent. The signature (ECDSA P-256 / SHA-256,
IEEE-P1363, base64url) is checked against the registered manager’s
public key over the RFC 8785 (JCS) canonicalized payload before
anything is stored.
201 with { "id": …, "receipt_id": …, "verified": true }.
A bad signature, or an unregistered/inactive manager, returns 422 CONSENT_RECEIPT_INVALID — the detail notes the payload may have been
tampered with or the manager may have rotated keys.
Re-verify a stored receipt
POST /compliance/consent/receipts/{id}/verify re-checks a
previously stored receipt against the manager’s current key — use
it during an audit to confirm a receipt still validates and whether
its manager remains active. {id} accepts either the consent-record
id or the receipt_id.
Consent receipts require the tenant
consent_managers migration.
On tenants that predate it, the manager/receipt endpoints degrade
gracefully (empty list / 404) rather than erroring.Related references
- Opt-Out & Suppression Lists — bulk-import opt-outs and how the suppression list gates sends.
- DSAR — honouring access/delete requests over the consent record.
- DLT-India Onboarding — the registration layer that pairs with DPDP consent on Indian SMS.
- API Reference → Compliance — full request/response schemas (regenerated from the live API).