Consent Registry, signup and paywall checkboxes, site forms, mailing list.

Consents & legal documents

The platform stores evidence of consent: which document and revision were accepted, when, from which IP/platform, with which checkbox label.

Where to author texts

OwnerAdminPublic API
ApplicationApplications → Legal documentsGET /v1/applications/YOUR_APP_CODE/legal
CMS siteCMS Site → Legal documentsGET /v1/sites/YOUR_SITE_CODE/legal

CMS Documents is for arbitrary landing files/links only — not legal templates.

doc_kind slots: privacy_policy, personal_data_consent, marketing_consent, mobile_apps_terms, terms_cyclone, terms_arken, license_offer, payment_data_consent (apps).

HTML page: GET /v1/legal-documents/{id} (public_url in API response).

Screen matrix

Registration / sign-in (app) — 2 required + 1 optional

CheckboxRequireddoc_kind
I accept the User Agreementyesone of mobile_apps_terms, terms_cyclone, terms_arken
I consent to personal data processingyespersonal_data_consent
I want news and special offers from RaidBoss Studionomarketing_consent

Do not pre-check optional marketing.

POST .../users/register requires consents. Missing required → 400 consents_required.

Document versions (important)

SituationWhat to callResult
Auth screen with checkboxesregisterUser + explicit_consent: trueCurrent Platform versions are stored
Silent login without UIomit explicit_consentVersions are not upgraded
Docs updated in admingetMyConsents → modal → acceptConsentsNew versions after explicit checkboxes

Take id / version only from getLegalDocument / pending_reconsent — never hardcode. Send version as a string.

needs_reconsent / pending_reconsent cover registration-required kinds only (agreement + personal data), not paywall offer.

Paywall / purchase

CheckboxRequireddoc_kind
I accept the License Offeryeslicense_offer
I consent to processing data required for paymentnopayment_data_consent

POST /v1/payments requires consents with license_offer. Separate payment_data_consent is optional (usually covered by the offer).

Site forms (contact / newsletter)

Required: personal_data_consent. Link privacy_policy. Optional marketing: marketing_consent.

POST /v1/sites/{code}/leads.

Client integration checklist

  1. Before checkboxes: getLegalDocument(...) for current id, version, document URL.
  2. After Auth on the checkbox screen: registerUser({ explicit_consent: true, consents }) (Flutter: explicitConsent: true).
  3. After login / app start: getMyConsents(); if needs_reconsent — modal → acceptConsents.
  4. Never send accepted: true / explicit_consent: true without showing checkboxes.
  5. Surface API error / message to the user on save failure.

SDK (TypeScript)

import {
  createRaidBossClient,
  CONSENT_CHECKBOX_LABELS,
} from "@raidboss/platform-sdk";

const terms = await platform.getLegalDocument("mobile_apps_terms");
const pd = await platform.getLegalDocument("personal_data_consent");

await platform.registerUser({
  platform: "android",
  explicit_consent: true, // checkbox UI; omit for silent sync (no version upgrade)
  consents: [
    {
      document_id: terms.data.id,
      version: String(terms.data.version),
      checkbox_text: CONSENT_CHECKBOX_LABELS.user_agreement,
      accepted: true,
    },
    {
      document_id: pd.data.id,
      version: String(pd.data.version),
      checkbox_text: CONSENT_CHECKBOX_LABELS.personal_data,
      accepted: true,
    },
  ],
});

const mine = await platform.getMyConsents();
if (mine.data.needs_reconsent) {
  await platform.acceptConsents({
    consents: mine.data.pending_reconsent.map((p) => ({
      document_id: p.document_id,
      version: String(p.published_version),
      checkbox_text: /* checkbox label on screen */,
      accepted: true,
    })),
    source_screen: "reconsent_modal",
  });
}

SDK (Flutter)

final terms = await platform.getLegalDocument('mobile_apps_terms');
final pd = await platform.getLegalDocument('personal_data_consent');

await platform.registerUser(
  platform: 'android',
  explicitConsent: true,
  consents: [
    {
      'document_id': terms['id'].toString(),
      'version': terms['version'].toString(),
      'checkbox_text': 'I accept the User Agreement',
      'accepted': true,
    },
    {
      'document_id': pd['id'].toString(),
      'version': pd['version'].toString(),
      'checkbox_text': 'I consent to personal data processing',
      'accepted': true,
    },
  ],
);

final mine = await platform.getMyConsents();
if (mine['needs_reconsent'] == true) {
  await platform.acceptConsents(
    sourceScreen: 'reconsent_modal',
    consents: [/* document_id, version.toString(), checkbox_text, accepted */],
  );
}

Methods: listLegalDocuments, getLegalDocument, getMyConsents, acceptConsents, listSiteLegalDocuments, getSiteLegalDocument, submitSiteLead.

HTTP:

POST /v1/applications/YOUR_APP_CODE/users/register
Authorization: Bearer <jwt>
{ "explicit_consent": true, "consents": [ ... ] }

GET  /v1/applications/YOUR_APP_CODE/users/me/consents
POST /v1/applications/YOUR_APP_CODE/users/me/consents

Consent journal

Each acceptance stores: user/email, app or site, doc_kind, version, text content_hash, checkbox label, IP, UA, platform, source (registration / paywall / site_form / newsletter / other with metadata.flow=reconsent for the modal), timestamp.

Admin: user profile → Consents tab; sidebar Mailing — active marketing_consent + CSV export.

Notes

  • Server computes content_hash from published body.
  • Client-sent version must match the published document (string).
  • Version bump: old acceptances stay in the ledger; the new version is written only with checkboxes (explicit_consent or acceptConsents), not via silent login.