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.
| Jurisdiction | Code | Response SLA |
|---|---|---|
| EU / EEA GDPR | gdpr | 30 days |
| California CCPA | ccpa | 45 days |
| California CPRA | cpra | 45 days |
| Brazil LGPD | lgpd | 15 days |
| Singapore / Thailand PDPA | pdpa | 30 days |
| Canada PIPEDA | pipeda | 30 days |
| India DPDP | dpdp | 30 days |
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.
Operator request_type | Meaning | Public portal verb |
|---|---|---|
know | Access — disclose the data held (GDPR Art 15, CCPA §1798.110) | access |
delete | Erasure (GDPR Art 17, CCPA §1798.105) | delete |
correct | Rectification (GDPR Art 16, CPRA §1798.106) | — |
portability | Machine-readable export (GDPR Art 20) | portability |
opt_out_sale | Opt out of sale/share (CCPA §1798.120) | opt_out |
limit_sensitive_pi | Limit use of sensitive PI (CPRA §1798.121) | — |
non_discrimination | Non-discrimination right (CCPA §1798.125) | — |
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:
| Field | Type | Notes |
|---|---|---|
contact_id | string | Optional. Links the request to a known contact. |
subject_email | One of email / phone / contact_id is required. | |
subject_phone | string | E.164. |
requester_email | Required. Where status updates are sent. | |
applicable_jurisdiction | enum | Default gdpr. |
request_type | enum | Default know. |
consumer_categories | string[] | CCPA categories (access only). |
verification_method | enum | email_link, email_phone, document, manual_review. |
requester_statement | string | Free text, ≤ 4096 chars. |
authorized_agent | object | { agent_name, agent_email, permission_document_id? } when an agent files on the subject’s behalf. |
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:
escalation_due flips at
day 25.
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
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.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.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.Verify phone
POST /compliance/public/dsar/verify-phone with claim_id and the
6-digit code. Returns state phone_verified and next step
submit.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.Abuse defenses
| Control | Limit |
|---|---|
| Cloudflare Turnstile | Required on begin in production (fail-closed). |
Per-IP begin | 3 per hour. |
| Per-email cooldown | 1 per 60 s. |
| Per-phone SMS cooldown | 1 per 60 s. |
| Fastify per-IP gate | 30 requests/min across all public endpoints. |
| OTP TTL / attempts | 10 minutes, max 3 attempts per code. |
| Claim TTL | 30 minutes end-to-end. |
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).