Export Consent & Suppression Records
Recording consent and suppressing opt-outs is only half of the audit problem. When a regulator, an auditor, or opposing counsel asks you to prove who opted in or out, when, on which channel, and from what source, you need the whole trail back out as a structured file — not a per-contact lookup or a manual database pull. Two endpoints produce that proof. Both are limited to owners and admins, default to CSV (the file an auditor opens in a spreadsheet), also speak JSON, and are audited themselves: every export run is written to your audit log with the filters and row count, so the export is part of the evidence trail. All endpoints below are rooted athttps://api.orbit.devotel.io/api/v1/compliance.
Consent proof-of-record
GET /compliance/consent/export returns one row per consent event —
opt-in, opt-out, or unknown — joined to the contact’s email, phone, and
WhatsApp ID so a record maps back to a person.
Consent row schema
Every CSV export uses the same fixed column order, in this sequence (missing values are empty cells — start with the wide export, then narrow):
The JSON response carries the same fields and also returns the column
list in
columns, the row count in count, the applied filters in
filters, and the truncation flag in truncated.
Suppression ledger
GET /compliance/suppression-list/export is the export counterpart to
the bulk import — it returns the durable (channel, address) STOP
signals, including bulk-imported addresses that have no linked contact.
Suppression row schema
Every CSV export uses the same fixed column order, in this sequence:
The active set is the audit default because it is the set every send
gate enforces; switch to
revoked to prove an address
was re-permissioned, or all for the full ledger.
Worked example: prove a number is suppressed since a date
An auditor asks for evidence that+15555550100 has been suppressed
since May 1, 2026. Bound the export window to end at that date —
any row returned is proof the address was on the ledger on or before
the cut-off:
2026-05-01 via an
inbound STOP keyword (reason: stop_keyword, source: api), is still
active (status: active, empty revoked_at), and — because
status=all was passed — would also surface had someone since revoked
it. Quote the row and the audit entry for the export run together as
the evidence package.
The same window-bounding works on the consent export: filter to a
single contact_id, or set to to the audit cut-off so the file
contains only what was true at that point in time.
Truncation, and pulling past the 50k cap
Both exports are synchronous and hard-capped at 50,000 rows per request — the same ceiling as the bulk import. When your ledger exceeds the cap, the CSV response sets theX-Export-Truncated: true header and
JSON responses report truncated: true. Never assume a flagged file is
complete.
To page past the cap, pull consecutive date windows and keep each
window small enough to fit under 50,000 rows:
suppressed_at (consent: created_at)
ascending and to is inclusive of the day, adjacent windows tile with
no gaps and no duplicates. Concatenate the files (dropping the repeated
header lines) for the full ledger. If a single day still exceeds the
cap, narrow further by channel and pull one file per channel per
window.
Related references
- Consent Management — record and look up per-channel consent, the writes these exports read back.
- Opt-Out & Suppression Lists — bulk-import the suppression ledger these exports return.
- DSAR — honouring access requests over the consent record.
- API Reference → Compliance — full request/response schemas.