Data Subject Access Requests (DSAR)
A Data Subject Access Request (also called a privacy request or consumer rights request) is the formal mechanism a person uses to exercise their rights over the personal data you hold about them — the right to access, delete, correct, port, or opt out of the sale of that data. Most privacy laws give you a hard deadline to respond (30 days under GDPR, 45 under CCPA/CPRA). Orbit gives you two intake paths and one fulfilment pipeline:- Operator-filed DSAR — your support or compliance team files a request on a customer’s behalf through the authenticated API or dashboard.
- Public self-service portal — the data subject files their own request through a public, unauthenticated flow that proves their identity with a two-factor email + SMS OTP before anything is queued.
https://api.orbit.devotel.io/api/v1/compliance.
Supported jurisdictions and deadlines
Theapplicable_jurisdiction on a request controls which statutory
clock Orbit’s SLA tracker applies. Operators can reclassify a request
after intake.
Request types
request_type describes what the subject is asking for. The full
CCPA/CPRA verb set is available to operators; the public portal
exposes a friendlier subset that maps onto it.
For CCPA access requests you may also attach
consumer_categories — the CCPA §1798.100(b) categories the subject
is asking about: identifiers, customer_records,
protected_classifications, commercial, biometric,
internet_activity, geolocation, sensory, professional,
education, inferences, sensitive_pi.
Operator-filed requests
Create a request
POST /compliance/dsar — requires an admin or owner API key.
Provide at least one subject identifier (contact_id,
subject_email, or subject_phone) plus the requester_email that
should receive correspondence.
202 Accepted:
Note —applicable_jurisdictiononly defaults togdprfor rights that exist under GDPR. Theopt_out_saleandlimit_sensitive_pirequest types are CCPA/CPRA-only and have no GDPR equivalent, so you must setapplicable_jurisdictiontoccpaorcpraexplicitly for them. Omitting it (or leaving thegdprdefault) is rejected with422 VALIDATION_ERROR.
Status lifecycle
A request moves through:received → processing → completed
with terminal branches failed, expired, and cancelled. The
verification sub-state is tracked independently:
pending → verified (worker proceeds) or rejected (worker
halts). GDPR/admin-filed rows default to not_required.
Verify or reject identity
Higher-assurance requests (delete, opt-out, limit-sensitive) require an operator decision before fulfilment proceeds:decision is verified or rejected; notes is optional
(≤ 2048 chars). Returns the new verification_status and
verified_at.
Cancel a request
POST /compliance/dsar/{id}/cancel withdraws an in-flight request
(GDPR Art 7(3)). Only works while the request is received or
processing; a terminal request returns 409 Conflict.
List and read requests
GET /compliance/dsar— paginated list. Query:page(≥ 1),page_size(≤ 100, default 25), and an optionalstatusfilter.GET /compliance/dsar/{id}— fetch one request. The response includes the signedexport_url(and itsexport_expires_at) once an access/portability export has been produced, plustables_exporteddescribing the per-table row counts.
Erasure requests
GDPR Art 17 erasures are tracked as their own resource so you can audit and intervene before data is destroyed:GET /compliance/dsar/erasure-requests— list. Query:status(pending,cancelled,executing,executed,failed) andlimit(≤ 500).POST /compliance/dsar/erasure-requests/{id}/cancel— cancel a pending erasure before it executes. Optionalreason(≤ 500 chars). Returns409if it is already executing or done.
SLA dashboard
GET /compliance/dsar/sla returns a combined export + erasure SLA
snapshot so you never miss a statutory deadline:
slaDays / 30 ratio, so a request always turns amber
and red at the same fraction of its own deadline. escalation_due flips
5 days before the statutory deadline (slaDays − 5).
For GDPR (sla_days: 30): green (< 20 days elapsed),
amber (20–25), red (26–30), red + breach (> 30);
escalation_due at day 25.
For CCPA/CPRA (sla_days: 45) the same ratios give green
(< 30), amber (30–38), red (39–45), red + breach (> 45);
escalation_due at day 40. Always read the tier boundaries against the
sla_days returned for that request, not the fixed 20/25/30 numbers.
Public self-service portal
The public flow lets a data subject file a request without an account. Identity is proven with a two-factor OTP — an email code and an SMS code — before any request is queued. The endpoints live under/compliance/public/dsar and are unauthenticated, but are
defended by Cloudflare Turnstile, per-IP and per-identifier
rate limits, and a privacy-preserving response shape that never
reveals whether an email/phone pair matches a real contact.
SMS verification codes are delivered through the Devotel softswitch
(the platform’s sole outbound SMS path). They are platform OTPs, not
tenant-billable traffic, and carry no delivery-receipt persistence.
Flow overview
1
Begin
POST /compliance/public/dsar/begin with email, phone (E.164),
request_type (access | delete | portability | opt_out),
and a Cloudflare turnstile_token (required in production).
Returns an opaque claim_id, email_sent: true, and
expires_in: 600. An email OTP is sent immediately.2
Verify email
POST /compliance/public/dsar/verify-email with claim_id and the
6-digit code. Returns state email_verified and next step
phone_send. Codes expire after 10 minutes; max 3
attempts. POST …/resend-email (with claim_id + email) issues
a new code, subject to a 60-second cooldown.3
Send phone code
POST /compliance/public/dsar/send-phone with claim_id and the
phone that matches the one given at begin. Sends an SMS OTP
(expires_in: 600). A 60-second cooldown applies between sends; a
too-soon retry returns 429 with Retry-After.4
Verify phone
POST /compliance/public/dsar/verify-phone with claim_id and the
6-digit code. Returns state phone_verified and next step
submit.5
Submit
POST /compliance/public/dsar/submit with claim_id. Persists an
audit row and — only if the verified email + phone match a contact
in your tenant — queues a real DSAR (pre-marked
verification_status: verified, since the OTP already proved
identity). Returns a reference_id (e.g. dsar_pub_…) and a
queued boolean.Configure the identity-proof senders
The two OTPs are sent from platform-level senders you configure once in your API environment. Set them before publishing the portal — an unset SMS sender with no fallback makes the phone step fail closed.
If
DEVOTEL_DSAR_PROOF_SMS_FROM and DEVOTEL_PLATFORM_DEFAULT_FROM
are both unset, the send-phone step fails closed with a 503 — the
portal returns a “temporarily unavailable” message and the failure is
emitted under the dsar.proof.sms_send_failed metric so it surfaces in
your dashboards rather than silently skipping the second factor.
Likewise, the email step returns 503 when DEVOTEL_RESEND_API_KEY is
unset. Configure both senders before you link the portal publicly.
Abuse defenses
The response shape is identical whether or not the identifiers match a
real contact — the portal never confirms or denies that someone is in
your database. When Redis is unavailable the rate-limit gates
fail open to preserve availability.
Enabling Turnstile protection
The Turnstile gate is configured with two environment variables.Hosting the portal link
Publish the public portal under your privacy policy as the “Submit a privacy request” link. Because the flow self-verifies via OTP, requests that arrive through it are already identity-proven — they land in your operator queue ready to fulfil, and appear inGET /compliance/dsar alongside operator-filed requests.
Related references
- Consent Management — record and look up the consent state a DSAR may ask you to honour.
- Opt-Out & Suppression Lists —
how
delete/opt_outoutcomes flow into suppression. - Call Recording Consent — handling recordings referenced by an access request.
- API Reference → Compliance — full request/response schemas (regenerated from the live API).