Files
portal/docs/api_updates.md
T
NeilClack 9e9cabfb2b
Build and Push to Digital Ocean Container Registry / build-and-push (push) Successful in 1m42s
Build and Push to Digital Ocean Container Registry / migrate (push) Failing after 22s
Update docs and formatting; remove obsolete v2 schema doc
- Refresh AI guide docs (api, svelte-patterns, testing-patterns)
- Add API updates notes, drop the outdated portal_api_v2_schema.md
- Format package.json
2026-08-27 12:07:34 -05:00

12 KiB

API Updates — Category Flattening, Groups, Subscription Level Removal

Release: v2 schema change (migration 20260821000000_flat_categories_groups_drop_subscription_levels) Status: Breaking changes. Clients must be updated.

Summary of changes

Endpoint Change
GET /api/v2/categories Breaking: parentId removed from every record. Categories are now a flat list.
GET /api/v2/groups New: returns the group list (former sub-categories).
GET /api/v2/proclamations Breaking: groupId added; subscriptionLevelId removed.
GET /api/v2/subscription-levels Removed: subscription levels no longer exist.
POST /api/v2/license Breaking: response no longer contains subscription_level.
POST /api/v2/automations/create/account Breaking: subscription_level is no longer accepted or required in the payload.
POST /api/v1/license Breaking: response no longer contains subscription_level.
POST /api/v1/automations/create/account Breaking: subscription_level is no longer accepted or required in the payload.
GET /api/v1/categories Payload implicitly changed: rows no longer contain parentId.

Data model mapping

  • Former parent categories (Spiritual, Physical, Mental, Emotional, Financial, Social, Biblical, ...) became the flat Category list.
  • Former child sub-categories (General, Specific, Precise, Prayers, Scripture) became Groups.
  • A proclamation's former child category becomes its group; its former parent category becomes its category. A proclamation may move between categories without changing its group.
  • Proclamations that had no sub-category (e.g. under Custom (Client Specific)) were assigned to the General group.
  • Every proclamation now has exactly one category and one group.

OpenAPI 3.0 specification

openapi: 3.0.3
info:
  title: Rhemawave Portal API
  version: 2.1.0
  description: |
    Changes in this release:
    * ProclamationCategory hierarchy flattened; parentId removed everywhere.
    * New ProclamationGroup resource replaces sub-categories as a movable filter.
    * SubscriptionLevel resource and all level-based gating removed.

paths:
  /api/v2/categories:
    get:
      summary: List categories (flat)
      description: >
        Returns all proclamation categories as a flat, ordered list.
        BREAKING: the previous version returned a hierarchical list where each
        record carried a nullable parentId linking children to parents. That
        field no longer exists.
      tags: [Categories]
      responses:
        '200':
          description: Flat category list.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Category'
              examples:
                newResponse:
                  summary: New response
                  value:
                    - id: 4
                      name: Spiritual
                      sortOrder: 0
                    - id: 2
                      name: Physical
                      sortOrder: 1
                oldResponseDeprecated:
                  summary: Old (removed) response shape
                  value:
                    - id: 5
                      name: General
                      sortOrder: 0
                      parentId: 4
                    - id: 9
                      name: Specific
                      sortOrder: 1
                      parentId: 4

  /api/v2/groups:
    get:
      summary: List groups
      description: >
        NEW ENDPOINT. Returns all proclamation groups ordered by sortOrder.
        Groups replace the former sub-categories and act as a movable filter:
        a proclamation can be moved from one category to another while keeping
        its group.
      tags: [Groups]
      responses:
        '200':
          description: Group list.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Group'
              example:
                - id: 1
                  name: General
                  sortOrder: 0
                - id: 2
                  name: Specific
                  sortOrder: 1

  /api/v2/proclamations:
    get:
      summary: List proclamations
      description: >
        Returns proclamations with their canonical frequency id and optional
        color palette. BREAKING: each record now carries groupId (required,
        always present) and no longer carries subscriptionLevelId. When the
        optional entitlement headers are supplied, only the caller's entitled
        proclamations are returned; there is no longer any per-level gating.
      tags: [Proclamations]
      parameters:
        - in: header
          name: x-license-key
          required: false
          schema: { type: string }
          description: License key. Must be paired with x-email.
        - in: header
          name: x-email
          required: false
          schema: { type: string }
          description: Account email. Must be paired with x-license-key.
      responses:
        '200':
          description: Proclamation list.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Proclamation'
              examples:
                newResponse:
                  summary: New response
                  value:
                    - id: b40fdcb9-703c-420e-af32-a081964c6f08
                      name: Peace & Relaxation
                      content: <p>The text content</p>
                      categoryId: 4
                      groupId: 1
                      solfeggioFrequencyId: 5
                      colorPalette:
                        [
                          '#32CD32',
                          '#3CB371',
                          '#90EE90',
                          '#98FB98',
                          '#ADFFA9',
                          '#C8FFD2',
                          '#F0FFF0'
                        ]
                oldResponseDeprecated:
                  summary: Old (removed) response shape
                  value:
                    - id: b40fdcb9-703c-420e-af32-a081964c6f08
                      name: Peace & Relaxation
                      content: <p>The text content</p>
                      categoryId: 5
                      solfeggioFrequencyId: 5
                      subscriptionLevelId: 1
        '400':
          description: Entitlement headers incomplete or invalid.

  /api/v2/subscription-levels:
    get:
      summary: REMOVED
      deprecated: true
      description: >
        This endpoint was removed. Subscription levels no longer exist in the
        data model; clients must stop calling it.
      tags: [Removed]
      responses:
        '404':
          description: Route no longer exists.

  /api/v2/license:
    post:
      summary: Validate a license key
      description: >
        Validates a key/email pair. BREAKING: the response no longer contains a
        subscription_level object.
      tags: [License]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [license_key, email_address]
              properties:
                license_key: { type: string, example: ABCD-EFGH-IJKL-MNOP }
                email_address: { type: string, format: email }
      responses:
        '200':
          description: Key is valid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LicenseResponse'
              examples:
                newResponse:
                  summary: New response
                  value:
                    key: ABCD-EFGH-IJKL-MNOP
                    email_address: user@example.com
                oldResponseDeprecated:
                  summary: Old (removed) response shape
                  value:
                    key: ABCD-EFGH-IJKL-MNOP
                    email_address: user@example.com
                    subscription_level:
                      id: 2
                      name: Advanced
                      description: General + Specific
        '400':
          description: Validation failure (missing fields, unknown key, wrong owner).

  /api/v2/automations/create/account:
    post:
      summary: Create account + license key (GoHighLevel automation)
      description: >
        Creates a portal account when needed and issues a license key.
        BREAKING: subscription_level was removed from the request contract. The
        field is neither required nor validated anymore; sending it is ignored.
        Signature headers (x-timestamp, x-nonce, x-signature) are unchanged.
      tags: [Automations]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email: { type: string, format: email }
                name: { type: string }
      responses:
        '200':
          description: Account and license key created.
        '400':
          description: Missing/invalid email.
        '401':
          description: Invalid signature.

components:
  schemas:
    Category:
      type: object
      required: [id, name, sortOrder]
      properties:
        id: { type: integer }
        name: { type: string }
        sortOrder: { type: integer }

    Group:
      type: object
      required: [id, name, sortOrder]
      properties:
        id: { type: integer }
        name: { type: string }
        sortOrder: { type: integer }

    Proclamation:
      type: object
      required: [id, name, content, categoryId, groupId, solfeggioFrequencyId]
      properties:
        id:
          type: string
          format: uuid
        name: { type: string }
        content: { type: string, description: HTML formatted content. }
        categoryId:
          type: integer
          description: Flat category this proclamation belongs to.
        groupId:
          type: integer
          description: >
            Group membership (movable filter). Independent of categoryId;
            changing the category does not change the group.
        solfeggioFrequencyId:
          type: integer
          minimum: 1
          maximum: 9
          description: Canonical kiosk frequency id (not the DB autoincrement id).
        colorPalette:
          type: array
          items: { type: string }
          minItems: 7
          maxItems: 7
          description: Present only when a palette exists for the frequency.

    LicenseResponse:
      type: object
      required: [key, email_address]
      properties:
        key: { type: string }
        email_address: { type: string, format: email }

Client migration checklist

  1. Kiosk / API consumers

    • Stop reading parentId; treat /api/v2/categories as flat.
    • Fetch /api/v2/groups once at startup for the filter list.
    • Read groupId from each proclamation record for filtering.
    • Remove all references to subscriptionLevelId and /api/v2/subscription-levels.
    • Remove subscription_level handling from license validation responses.
  2. GoHighLevel automation

    • Remove subscription_level from the account-creation webhook payload (optional but recommended; the field is now ignored).
  3. Admin portal

    • Manage categories under Admin → Proclamation Categories (flat list, drag to reorder).
    • Manage groups under Admin → Proclamation Groups (drag to reorder).
    • Proclamations now select one Category and one Group independently.