> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy the public self-service DSAR intake portal

> Publish Devotel Orbit's unauthenticated DSAR intake portal under your privacy policy — the two-factor email + SMS OTP identity proof, jurisdiction-aware SLA clocks, and where portal filings land in your operator queue.

# Deploy the public self-service DSAR intake portal

Devotel Orbit ships a public, unauthenticated intake page where a data
subject files a privacy request themselves — access, erasure,
portability, or opt-out — and proves their identity with a two-factor
email + SMS OTP before anything enters your queue. This guide walks
through deciding on, publishing, and operating that portal. For the
endpoint surface and jurisdiction tables, read the
[DSAR reference](/compliance/dsar); for the operator-side walkthrough
of the queue portal filings land in, read the
[DSAR operator guide](/guides/compliance-dsar-breach-register).

<Note>
  The portal is **your** intake surface. Orbit hosts it and tracks the
  statutory clocks, but the legal duty to respond within the deadline
  stays with you, the controller. Confirm your obligations with
  counsel.
</Note>

***

## When the public portal beats operator-filed DSAR

The operator flow ([file a request in the console](/guides/compliance-dsar-breach-register))
works perfectly well — until it does not:

* **Volume.** Every intake routed through your support or compliance
  team costs an operator round-trip per request. High-volume consumer
  businesses get subject requests daily; self-service takes them to zero
  ops touches.
* **Unauthenticated subjects.** An operator-filed request via your
  authenticated API can only be filed by someone with a session. The
  public portal gives strangers on the internet a lawful front door.
* **Statutory clocks.** GDPR Article 12 gives you 30 days, CCPA/CPRA 45,
  LGPD 15. An intake channel that forces every request through a human
  queue burns those days on triage. Portal filings arrive
  pre-verified, so the clock is spent on fulfilment, not identity
  paperwork.

If you publish a privacy policy that promises a self-serve channel —
and most GDPR-obligated controllers do — the portal is how that promise
actually works.

***

## Deploy the portal

### Route and hosting model

The portal is a hosted public page on Orbit's web surface — no account,
no API key, no session. Publish it as the "Submit a privacy request"
link in your privacy policy, website footer, and in-product settings:

```
https://orbit.devotel.io/<locale>/dsar
```

`<locale>` follows the same locale prefix as every other Orbit web
page (for example `en`, `fr`, `de`). The page renders a two-step
identifier form behind a Cloudflare Turnstile bot check: the subject
enters their email and phone (E.164), chooses a request type, and the
identity proof begins.

### The two-factor identity proof

Nothing is queued until the subject proves they control **both** an
email address and a phone number:

1. **Begin** — the subject submits email + phone + request type. An
   email OTP is sent immediately.
2. **Verify email** — the 6-digit email code (10-minute TTL, 3
   attempts; a 60-second resend cooldown).
3. **Send phone code** — an SMS OTP to the same phone (60-second
   cooldown between sends).
4. **Verify phone** — the 6-digit SMS code.
5. **Submit** — only with both proofs on file does a request enter
   your queue. The whole claim has a 30-minute end-to-end TTL.

The identity proof runs against **platform-level senders** you
configure in your API environment — an unset SMS sender (with the
platform fallback unset too) fails the phone step closed with a `503`,
and the email step fails closed when the email delivery key is missing.
Configure both before you link the portal publicly:

| Variable                        | Used for                       | Fallback                                            |
| ------------------------------- | ------------------------------ | --------------------------------------------------- |
| `DEVOTEL_DSAR_PROOF_FROM_EMAIL` | From-address on the email OTP. | none — delivery also needs `DEVOTEL_RESEND_API_KEY` |
| `DEVOTEL_DSAR_PROOF_SMS_FROM`   | E.164 sender on the SMS OTP.   | `DEVOTEL_PLATFORM_DEFAULT_FROM`                     |

In production, the first step also requires a Turnstile token:
`DEVOTEL_TURNSTILE_SECRET_KEY` on the API and
`NEXT_PUBLIC_DEVOTEL_TURNSTILE_SITE_KEY` on the web deployment. Both
keys come from the Cloudflare dashboard (Turnstile → Add site). Without
the secret the gate is open — set it in production.

SMS verification codes go out through the Devotel softswitch as
platform OTPs — they are not tenant-billable traffic.

### Request types a subject can pick

The public form exposes a friendlier subset that maps onto the operator
enum:

| Subject picks | Operator `request_type` |
| ------------- | ----------------------- |
| `access`      | `know`                  |
| `delete`      | `delete`                |
| `portability` | `portability`           |
| `opt_out`     | `opt_out_sale`          |

Operator-only rights (correct, limit-sensitive-PI, non-discrimination)
are intentionally not exposed publicly — a subject who needs those can
still file through your operators.

### Jurisdiction and the SLA clock

The subject picks the jurisdiction their request falls under; that
choice sets the statutory clock your queue displays:

| 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      |

Operators can reclassify the jurisdiction after intake — so a subject's
mis-selection is fixable inside your queue, not a wrong clock you must
live with. When a portal filing targets `opt_out`, jurisdiction
defaults to CCPA/CPRA rather than GDPR, matching the operator-side
validation that rejects a GDPR-scoped opt-out request.

***

## Lifecycle visibility for ops

Portal filings that match a contact in your tenant land in
**Settings → Compliance → DSAR**, in the same list and the same
`GET /compliance/dsar` response as operator-filed requests. Because the
OTP already proved identity, they arrive pre-marked
`verification_status: verified` — the export or erasure worker starts
immediately and no operator approve/reject gate sits in the way.

* **Erasure-class portal filings** (the subject picked "delete") are
  pulled into the **Erasure requests (Art. 17)** tab's portal section —
  the same place the console groups erasures from the admin dialog —
  with their SLA badge beside them.
* **Wrong jurisdiction picked?** Reclassify the row from the queue;
  the SLA badge re-anchors to the corrected window.
* **Need the paper trail?** The document-verification and manual-review
  methods exist for operator-filed rows; a portal row's proof is its
  two-factor OTP, recorded in the audit chain (below).

***

## Evidence a portal filing leaves behind

Every stage of the public flow writes to your tamper-evident audit log —
the begin attempt, the email verification, the phone verification, and
the submit — with hashed (never raw) identifier values, the source IP,
and the user agent. That is the record a regulator or your
[evidence binder](/guides/compliance-evidence-binder) pulls from when
they ask how a subject's identity was established.

Two consequences to plan around:

* The **breach/incident register** and binder count audit rows across
  both intake paths — portal filings do not need a separate evidential
  story.
* When a filing does **not** match any contact, an audit row is still
  written (scoped to the platform rather than your tenant) so the
  forensic trail exists even for a no-match case — while the portal's
  response shape still never reveals whether a contact matched.

***

## Integrate the API directly

The portal page is a thin client over a public REST sequence. If you
embed your own intake UI (an in-app privacy center, a partner-hosted
form), call the same handlers — the response envelope and rate limits
are documented in the [DSAR reference](/compliance/dsar):

```bash theme={null}
# 1. Begin — collect identifiers, send email OTP
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/public/dsar/begin \
  -H "Content-Type: application/json" \
  -d '{
    "email": "subject@example.com",
    "phone": "+14155551212",
    "request_type": "access",
    "turnstile_token": "<token-from-your-widget>"
  }'
# → 202 { "claim_id": "dsar_claim_…", "email_sent": true, "expires_in": 600 }

# 2. Verify the email code
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/public/dsar/verify-email \
  -H "Content-Type: application/json" \
  -d '{ "claim_id": "dsar_claim_…", "code": "482916" }'

# 3. Send the SMS code
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/public/dsar/send-phone \
  -H "Content-Type: application/json" \
  -d '{ "claim_id": "dsar_claim_…", "phone": "+14155551212" }'

# 4. Verify the SMS code
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/public/dsar/verify-phone \
  -H "Content-Type: application/json" \
  -d '{ "claim_id": "dsar_claim_…", "code": "738201" }'

# 5. Submit the verified request
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/public/dsar/submit \
  -H "Content-Type: application/json" \
  -d '{ "claim_id": "dsar_claim_…" }'
# → 201 { "reference_id": "dsar_pub_…", "queued": true }
```

Only the submit step returns `201`; every earlier step is a `2xx`
progression toward it. Whatever the integration, render a Turnstile
widget at step 1 — production `begin` calls without a token are
rejected with `422 TURNSTILE_REQUIRED`.

***

## Troubleshooting and related links

* [Troubleshooting: DSAR export, decrypt, and cancel failures](/troubleshooting/dsar-export-failures) —
  when a fulfilled export will not download, decrypt, or cancel.
* [Fulfill a DSAR and operate the breach-incident register](/guides/compliance-dsar-breach-register) —
  the operator walkthrough of the queue your portal feeds.
* [Public consent form](/guides/public-consent-form) — a sibling hosted
  public form, for opt-in/opt-out rather than rights requests.
* [DSAR reference](/compliance/dsar) — the full endpoint surface,
  abuse-defence limits, and SLA severity tiers.
