Files
radiantwave/portal_api_v2_schema.md
T

5.1 KiB
Raw Blame History

Portal API v2 — current schema

The kiosk talks to https://portal.radiantwavetech.com/api/v2. This document describes the current contract after the move to an active/inactive license model. There are no subscription levels: a license is either valid (subscribed) or not, and the kiosk treats a successful POST /license validation as the device's "subscribed" flag.

Base URL: https://portal.radiantwavetech.com/api/v2

Authentication: Authorization: Bearer sk_<hex> on every request (the API key is baked into the kiosk binary at build time).


POST /license

Validates a license key / email pair.

Request:

POST /api/v2/license
Content-Type: application/json
Authorization: Bearer sk_<hex>
{
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "email_address": "user@example.com"
}

Response (200):

{
  "key": "XXXX-XXXX-XXXX-XXXX",
  "email_address": "user@example.com"
}

Contract (kiosk parseLicenseJson):

  • key: string, required non-empty (empty key ⇒ parse failure).
  • email_address: string.
  • Any other fields (e.g. the legacy subscription_level) are ignored. A 2xx response means the license is valid and the subscription is active; the kiosk stores no subscription state other than the license_last_verified stamp that drives its 7-day offline grace window.

Errors:

Code Body Meaning
200 success object License valid and owned by the email
400 {"message": "license_key is required"} Missing license_key
400 {"message": "email_address is required"} Missing email_address
400 {"message": "license key not found"} No key with that value
400 {"message": "license key is not active"} Key exists but inactive
400 {"message": "user does not exist"} No user with that email
400 {"message": "key does not belong to specified user"} Key owned by a different user
401 {"error": "..."} Missing/invalid API key

GET /proclamations

Lists every proclamation. There is no subscriptionLevelId — any validated license may access any proclamation.

Response (200):

[
  {
    "id": "b40fdcb9-703c-420e-af32-a081964c6f08",
    "name": "Peace & Relaxation",
    "content": "<p>The text content, HTML formatted</p>",
    "categoryId": 5,
    "solfeggioFrequencyId": 5,
    "colorPalette": ["#32CD32", "#3CB371", "#90EE90", "#98FB98", "#ADFFA9", "#C8FFD2", "#F0FFF0"]
  }
]

Contract (kiosk parseProclamationsJson + parseProclamationPalettesJson):

  • id: string UUID, required non-empty (empty ids are skipped).
  • name: string, used as the display title. Kiosk strips HTML from it.
  • content: string, HTML (the kiosk strips tags and unescapes entities before rendering).
  • categoryId: int, maps to a /categories id.
  • solfeggioFrequencyId: int, must be a canonical id (1–9).
  • colorPalette (optional): array of exactly 7 "#RRGGBB" strings. When absent, the kiosk falls back to /color-palettes, then to its own 528 Hz seed.
  • Legacy subscriptionLevelId fields in the payload are ignored.

Errors:

Code Body Meaning
200 array of proclamation records Success
400 {"message": "not-authorized"} Entitlement headers supplied but key or email does not exist
401 {"error": "..."} Missing/invalid API key

GET /categories

Lists the proclamation categories.

Response (200):

[
  {
    "id": 4,
    "name": "Spiritual",
    "parentId": 0,
    "sortOrder": 0
  }
]

Contract (kiosk parseCategoriesJson):

  • id: int, required non-zero (zero ids are skipped).
  • name: string.
  • parentId: int, null maps to 0 (root).
  • sortOrder: int.

POST /automations/create/account

Creates (or reuses) a user account and issues a license key. No subscription_level is sent — every created license is a standard active license.

Request:

POST /api/v2/automations/create/account
Content-Type: application/json
Authorization: Bearer sk_<hex>
X-Timestamp: <unix seconds>
X-Nonce: <random uuid>
X-Signature: <hex HMAC-SHA256 of canonical request with the onboarding secret>
{
  "email": "user@example.com",
  "name": "Optional Display Name"
}
  • email (required, string).
  • name (optional, string; defaults to the local part of email).

Response (200):

{
  "success": true,
  "message": "Account and license key created",
  "user_id": "uuid"
}

Errors:

Code Body Meaning
200 success object Account (+ license key) created
400 {"message": "email is required"} Missing/empty email
401 {"error": "invalid signature"} Bad/expired/replayed HMAC signature
429 {"message": "rate limit exceeded"} Too many requests from this IP/email
500 {"message": "Failed to create account"} User creation failed

Readiness routes (not yet wired into the app)

  • GET /color-palettes → [{solfeggioFrequencyId, colors[7]}]
  • GET /frequencies → canonical id 1–9 + value in Hz

These exist for future sync steps; the kiosk does not call them yet.