5.1 KiB
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 thelicense_last_verifiedstamp 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/categoriesid.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
subscriptionLevelIdfields 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,nullmaps 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 ofemail).
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 +valuein Hz
These exist for future sync steps; the kiosk does not call them yet.