Skip to main content

Public consent form

Orbit can host a public landing page where recipients enter their email or phone, choose channels, and opt in or out of receiving messages. Submissions write to the same consent surfaces as carrier-side STOP / START keywords — consent_records, channel_preferences, and suppression_list — so the platform’s outbound send gate immediately honours the new state. The feature is off by default. Each tenant explicitly turns it on under Settings → Compliance → Public consent form. When disabled, the public URL returns 404.

When to use it

  • The footer of email / SMS campaigns where you’d otherwise embed a vendor unsubscribe link.
  • Sender bios (Instagram, LinkedIn) where recipients ask you to stop messaging.
  • Operator-driven opt-in capture, e.g. when transcribing paper-form consent.
  • Bulk re-permissioning campaigns after a privacy-policy change.
The page does not replace carrier-side STOP / START keywords or per-channel inline unsubscribe headers — it complements them.

Enable the form

  1. Sign in as an owner or admin.
  2. Go to Settings → Compliance → Public consent form.
  3. Toggle Enable public consent form on.
  4. Copy the public URL (under the toggle) — it has the form https://orbit.devotel.io/<locale>/consent/<tenantId>.
The URL becomes live the moment you save changes.

Optional configuration

All fields below are optional. Leave blank to use Orbit defaults. Branding
  • Business name — shown above the headline.
  • Primary color — 3- or 6-digit hex (e.g. #0ea5e9). Drives the submit button and success badge.
  • Logo URL — must be https:// (or http://). Rendered above the business name.
Page copy
  • Headline — replaces the default “Manage your preferences” (max 240 chars).
  • Body — short explanatory paragraph (max 2000 chars).
  • Footer — fine print, support contact, link to your privacy policy (max 1000 chars).
Allowed channels Restrict which channels appear on the form. When unchecked, the channel is hidden on the page and submissions for it are rejected with 422 INVALID_CHANNEL. Leave all 11 channels selected to accept the platform default (email, fax, instagram, line, messenger, push, rcs, sms, viber, voice, whatsapp).

Pre-fill the recipient identifier

Append ?contact=<email-or-phone> to the URL to pre-fill the form. The recipient can still edit the value before submitting.
Use this in campaign footers so the recipient lands one-tap away from saving their preferences.

Programmatic submissions

The form is a thin client over a public REST endpoint. Direct integrations (e.g. an embedded preference centre on your own marketing site) can POST against the same handler.
Response:

Body

Errors

Read the tenant’s public config

For embedding teams that want to render their own UI against the same config the Orbit-hosted form uses:
When the tenant has NOT enabled the form, the response carries enabled: false and empty branding / copy / channels. Render a 404 — that matches how the Orbit-hosted page reacts.

What the form writes

Every submission writes to the same three surfaces the carrier-side handleOptIn / handleOptOut routes touch:
  1. consent_records — one row per submitted channel with consent_state = 'opted_in' / 'opted_out'. The send-side gate at outbound time checks this column.
  2. contacts.channel_preferences JSONB — per-channel opted_out flag flipped, global_opt_out flipped on opt-out, and an entry appended to consent_history for audit continuity.
  3. suppression_list — opt-out inserts a channel='all' row that survives soft-delete. Opt-in sets revoked_at = NOW() on every active row (audit-friendly, NOT a DELETE).
A redis-backed STOP-fence cache key is also flipped so in-flight campaign batches converge within sub-RTT, and an entry lands on the tamper-evident audit log (action: consent.public_opt_in / consent.public_opt_out).

Limits and abuse defence

  • The POST + GET endpoints are rate-limited per source IP (RATE_LIMIT_PUBLIC_UNAUTH — 10 requests per minute).
  • There is no Clerk session or API key on this route.
  • Logs capture source IP, user-agent (truncated to 500 chars), and a contact-identifier kind classifier (email / phone / whatsapp_id).
  • Suppression and consent state are authoritative in Postgres; the STOP-fence cache is a sub-RTT convenience that fails open.

Disabling the form

Toggle Enable public consent form off. The public URL returns 404 from that moment, and the POST handler returns 422 INVALID_TENANT for that tenant — no in-flight submissions can land. Stored consent records remain — disabling only stops new submissions. Re-enabling restores the previous configuration block (branding, copy, allowed channels) so an accidental toggle doesn’t lose the customisation.