Substratal Apps Substratal Apps Hub specs
GitHub

Help

What's new

Changes to the Hub apps and the API they're built on. The API's own history is in its changelog.

Recently updated help

Hub changes

This package targets API spec v1.8.0 (2026-10-22; openapi.yaml 1.0.0-draft.9, 124 operations). Sections 03–07 are new in this revision; 00–02 came with v1.7.3 (draft.5, 121 operations). Before that the package targeted v1.4.0 (draft.3, 118 operations), and the one before that v1.2.2 (98 operations). The API changes, and what they did to the apps:

00. API version moves from the URL to a header (API v1.7.0–v1.7.3)

Breaking for every client. The /v1 path prefix is gone; requests name their version in a header instead, so endpoint URLs stay the same across every future version.

POST https://api.substratalapps.com/users
Substratal-Version: 1
API change Effect on the Hub
Paths drop /v1 (POST /v1/users → POST /users); /v1/… returns 404 not_found, no redirect Base URL is https://api.substratalapps.com (CLIENT-ARCHITECTURE §4). Every path in API-SCREEN-MAP.csv and the screen specs is now unprefixed, matching openapi.yaml.
Substratal-Version required on every request; 400 api_version_required / unsupported_api_version with details.supported; echoed on every response The API client layer sends Substratal-Version: 1 on every call, pinned per build. New CLIENT-ARCHITECTURE §4.1 API versioning.
Exempt: GET /health, POST /auth/oauth/token, /.well-known/*, /scim/v2 Nothing to special-case: sending the header to them is harmless.
Deprecation (RFC 9745) and Sunset (RFC 8594) on responses to a deprecated version; unsupported_api_version after Sunset GLB-03 gains Update available (banner) and a defined Update required (blocking) state, with copy in COPY-AND-STATES. New telemetry api_version_deprecated, api_version_unsupported. The PWA can't read Deprecation/Sunset until the API exposes them through CORS (OPEN-QUESTIONS #15).
openapi.yaml declares the shared ApiVersion header parameter (draft.5) Regenerate clients from draft.5; set the header in middleware, not per call.
Webhook api_version (a date) is versioned separately from Substratal-Version WHK-02/WHK-03 label it Payload version (mockups and renders updated) so the two aren't confused.
405 method_not_allowed with Allow for a known path and wrong method Treated as a client bug: logged, generic error.
Additive changes ship within a version Decoders ignore unknown fields and enum values. Persistent caches are tagged with the API version and dropped when it changes.

01. SCIM provisioning (API v1.7.2, 3 new operations)

API change Effect on the Hub
POST/GET/DELETE /organizations/{id}/scim-token (org admin or organizations.manage) ORG-08 gains a SCIM provisioning section: status, set up / rotate (one-time secret with base_url), turn off. Behind the scim flag.
/scim/v2 is called by identity providers Not called by the Hub. Provisioned people arrive as ordinary invitations (ORG-03, ORG-09).

02. Other API updates since v1.4.0

  • Push notifications are built (2026-10-18): no Notifications operation returns 501 any more (OPEN-QUESTIONS #16 resolved). Flags stay as a safety net.
  • Billing options settled: monthly USD only, no annual plan, no trial (OPEN-QUESTIONS #18 resolved).
  • idempotency_key_reused is 409, not 422 (corrected in CLIENT-ARCHITECTURE and COPY-AND-STATES).
  • Test-mode User expiry, self-service app registration and audit exports, in progress at v1.7.3, shipped in v1.8.0: see sections 03–05.

03. Test-mode User expiry (API v1.8.0, draft.6)

API change Effect on the Hub
Test-mode Users have expires_at (24 h default, at most 30 days after creation); live Users always null USR-03 shows it for test-mode Users ("Expires in 3 h") in developer builds.
users.manage may move expires_at with PATCH /users/{id}, which also brings back an expired User until the 30-day purge USR-03 gains Extend… (test-mode Users only).
Login, MFA verify and refresh return 403 test_user_expired; no token outlives expires_at AUTH-01 shows "This test account has expired." A running session ends with 401 like any revoked session. OPEN-QUESTIONS #24 resolved.

04. Self-service Application registration (API v1.8.0, draft.7)

API change Effect on the Hub
Any User with a verified email can POST /applications; it starts pending_review, public, standard, owned by the caller or an Organization they're an org_admin of APL-01 Register app shows for everyone with a verified email (flag app_registration_self_service), and is disabled with a reason until the email is verified (403 email_not_verified). OPEN-QUESTIONS #25 resolved.
Moderation fields (visibility, access_tier, review_status, review_notes, another owner) are staff-only: 403 moderation_field_forbidden; 10 submissions per User per day APL-02 hides them for non-staff.
Applications gain read-only self_registered; only applications.manage can turn on receives_platform_notifications for one APL-03 shows a Third-party chip, and the Platform alerts toggle is disabled with a reason for the owner.
POST /auth/app-tokens refuses a self-registered Application: 403 embedded_login_not_allowed APP-03 uses the hosted launch for it (flag hosted_launch); until hosted launch ships, it opens the app's launch_url without a token.
Platform-managed Entitlements are granted only once an Application is approved APL-02's result copy no longer promises access on registration for a self-service app.

05. Audit Event exports (API v1.8.0, draft.8, 2 new operations)

API change Effect on the Hub
POST /audit-exports takes the AUD-01 filters plus format (ndjson or csv), needs Idempotency-Key, returns 202 AUD-01 gains Export… (flag audit_export) using the current filters. OPEN-QUESTIONS #11 resolved.
GET /audit-exports/{id} shows status; once ready, a download_url signed for 15 minutes; files kept 7 days; 20 per caller per day Poll every 3 s while pending/running, then offer the download. Re-fetch the export for a fresh link. 429 → "You can export 20 times a day."
New audit action audit.exported Grouped under audit.* in the AUD-01 action filter.

06. Console milestone M1 (API v1.8.0, draft.9, 1 new operation)

API change Effect on the Hub
CORS: allow-listed origins may call every endpoint with a User token, and browsers can read Retry-After, Audit-Hot-Window-Start, Deprecation and Sunset The PWA honours Retry-After, shows the AUD-01 hot-window caption and GLB-03 Update available, with no fallbacks. OPEN-QUESTIONS #15 resolved.
An API Key sent from a browser is refused: 400 api_key_in_browser The Hub never sends API Keys; KEY-03 says to use the secret from a backend.
GET /users?role_id= (repeatable, explicit assignments, up to 20) ROL-02 Holders links to USR-01 filtered by the Role. OPEN-QUESTIONS #5 resolved.
POST /users/{id}/sessions/revoke-all (self or users.manage; keep_current for self), returns {revoked}; revoked_reason revoked_all; audit user.sessions_revoked ACC-04 Sign out of all other sessions is one call with keep_current: true. USR-04 gains Sign out everywhere for staff.

07. Console screens (web)

The management console is the web Hub, built management-first (see the web console plan in CompositeCode/substratalapps.com-web). It adds 12 screens in a new C · Console domain: OPS-01…07, SEC-01, CFG-01, CFG-02, RPT-01 and INT-01. They're listed in PRODUCT-SPEC §2a with an adopt or skip decision per platform (web adopts them; the native apps skip them for now) and the API gap each depends on, and specified in SCREEN-SPECS § C. The 75 shared screens are unchanged in number.

09. The web Hub's address (this revision)

The web Hub is served at https://hub.substratalapps.com, not the planned dashboard.substratalapps.com (never served, dropped).

The new host now appears everywhere the old one did:

  • deep links and Universal Links / App Links (INFORMATION-ARCHITECTURE §4)
  • billing return URLs (CLIENT-ARCHITECTURE §9)
  • the web platform spec and the help center

The API's emailed links and CORS allow-list move with it, in API PR #76. The section numbers in entries 00–08 above still name the old host; they're history.

08. Product naming (this revision)

PRODUCT-SPEC gains §0 Names:

  • The product is Substratal Hub on every platform, with "the Hub" as the short form.
  • Substratal is the name where space is tight: home-screen and launcher labels, and the PWA short_name.
  • Substratal Apps is the brand, and Substratal Apps Platform API is the API.
  • "Dashboard", "console" and "admin app" aren't product names.
  • The web app's manifest name changes from "Substratal" to "Substratal Hub", with short_name "Substratal" (web PLATFORM-SPEC §7).

08. Hub identifiers and theme settings (2026-10-24)

  • Bundle id com.substratalapps.hub on iOS and macOS (shared, for Universal Purchase and the one APNs topic), and Android applicationId com.substratalapps.hub; Linux app ID com.substratalapps.Hub; Windows package identity CompositeCode.SubstratalHub. The iOS app moved from com.substratal.hub.
  • Theme settings are light_theme and dark_theme on app_hub, not appearance.*: the API's setting names can't contain dots. OPEN-QUESTIONS #22 resolved.

0a. Themes (this revision)

  • Adds the theme system: 5 light themes (Teal Ledger, Indigo Root, Moss Paper, Coral Clay, Spore Pink) and 5 dark themes (Night Soil, Deep Teal, Graphite Spore, Forest Floor, Ember Clay). Defaults are Moss Paper and Forest Floor. Rules are in THEMES.md; tokens are in themes/themes.json and themes/themes.csv.
  • SET-01 now has Light theme and Dark theme pickers next to Appearance, plus a new reference screen SET-01-appearance-themes on every platform. The choices are stored as app_hub settings (OPEN-QUESTIONS #22).
  • Every reference screen and mockup is rendered in both default themes (screens/light/, screens/dark/). Mockups preview any theme with ?mode=dark&light=<id>&dark=<id>.
  • New per-platform theme code in <platform>/theme/: Swift ThemeStore and palettes (iOS/macOS); WinUI theme dictionaries and ThemeService (Windows); Material 3 colour schemes (Android); libadwaita CSS (Linux); CSS variables with a TypeScript resolver (web).
  • COMPONENTS adds ThemePicker. CLIENT-ARCHITECTURE adds §13 Themes. Theming is now in scope (PRODUCT-SPEC).

0. Logo standard and app icons (this revision)

  • Adopted logo: interlined root twist mark with the [substratal] wordmark (JetBrains Mono, coral brackets, ink sub, teal stratal, ◆ apps descriptor). Rules: brand/BRAND.md.
  • Placed in every design: AUTH-01/02 sign-in (all platforms), web sidebar header, Windows title bar, notification rows for source: platform. Reference screens and mockups have been re-rendered.
  • New per-platform kits under <platform>/brand-assets/: Xcode asset catalogs (AppIcon with dark/tinted, Icon Composer layers, logo imagesets, colour sets), .icns, Windows .ico and full MSIX asset set, Android adaptive/themed/notification icons as vectors and PNGs, Linux hicolor and symbolic icons with .desktop and AppStream branding, and the web favicon set, PWA icons (any/maskable/monochrome), Web Push badge and OG image.
  • Each PLATFORM-SPEC.md has a new Brand & app icon section. COMPONENTS adds BrandLockup.

1. Push notifications and the notification inbox (API: Push Notifications, 17 new operations)

API change Effect on the Hub
Devices per Application (/users/{id}/devices), APNs / FCM / Web Push The Hub registers itself as first-party app app_hub and registers each install (CLIENT-ARCHITECTURE §2, §6). New flow F12, screens NTF-03 Devices & notifications and NTF-04 Turn on notifications.
Inbox (/users/{id}/notifications, unread-count, mark-read) The client-composed inbox is gone. NTF-01 Inbox and NTF-02 Notification read the real inbox; badges use unread-count everywhere. Inbox is a top-level destination on every platform (mobile tab bar: Home · Inbox · Orgs · Manage · Account).
Platform alerts (security.*, account.*) pushed to apps with receives_platform_notifications app_hub opts in; categories get native actions (Review sessions, Accept invitation…). Flow F13.
notifications.push channel in Settings (global and per app) Push toggles in SET-01 and SET-02.
Push credentials per Application (/applications/{id}/push-credentials) New APL-07 Push credentials tab for app owners; receives_platform_notifications toggle on APL-03. Flow F15.
notifications.send permission and POST /users/{id}/notifications New staff tool NTF-06 Send notification; app keys can carry confined notifications.send (KEY-02).
Support can read any inbox and devices (users.list), delete devices (users.manage) New user-detail tab NTF-05. Flow F16.
Webhook events device.*, notification.push_failed, push_credential.failed WHK-02 event list and "Push health" preset.
Logout / session revoke / suspend / delete deactivate devices Copy for sign-out, suspend and "sign out everywhere" updated.
All Notifications operations return 501 until implemented Everything above ships behind flags that a 501 turns off.
No WNS provider; no Linux push Windows and Linux keep polling and show local notifications (OPEN-QUESTIONS #2).

The old push-relay assumption (previous OPEN-QUESTIONS #2) is withdrawn for iOS, macOS, Android and Web.

2. Free / Standard pricing (API: Billing rewritten)

API change Effect on the Hub
Developers/Tenants are no longer billed; Tenant plan, subscription_status, restricted and /tenants/{id}/usage removed Old "Plan & usage" developer screen removed. BIL-04 Tenant & infrastructure keeps tier/region and tier-change requests only, under Developer › Tenant.
Users have plan and plan_sources; GET /users/{id}/subscription; individual Checkout/Portal New BIL-01 My plan under Personal › Plan & Billing (Account on mobile). Flow F10 rewritten.
Organization subscription with member_scope and Checkout/Portal New BIL-02 Organization subscription tab on organizations. Flow F14.
Checkout success ≠ coverage; poll until plan = standard BIL-03 returns to https://dashboard.substratalapps.com/billing/return… and polls.
Applications gain access_tier (free / standard) Home separates "Included with Standard" tiles with an upsell; APL-02/03 show access tier (staff-only field).
402 subscription_required, plan caps, seat_limit removed; plan_limit_reached reserved Removed from every screen and from COPY.
Store policy Standard is now a consumer subscription unlocking apps → mobile upgrade buttons default off pending policy review (OPEN-QUESTIONS #10).

3. Platform-managed entitlements

API change Effect on the Hub
Entitlement.source adds free and subscription; subscription_id New source labels; APP-02 and ACX-01 show "Managed by Substratal" paths.
Only disable / re-enable allowed; anything else 409 entitlement_platform_managed ACX-01/03 hide term, scope and delete for those rows; confirm copy explains.
Platform rows and developer grants coexist ACX-02 no longer blocks on platform rows; ACX-05 adds a "Show platform-managed" filter.

4. Smaller changes

  • Audit hot window is one year for every Tenant (AUD-01 reads Audit-Hot-Window-Start); new audit actions subscription.*, push_credential.*, device.deleted.
  • Seed role superadmin gains notifications.send; billing.manage now means people's and organizations' subscriptions.
  • Signup with an invited user's email returns 409 email_taken and re-sends the invitation (AUTH-03 copy).
  • ID prefixes added: sbs_, dvc_, pcr_, ntf_, ndl_.
  • Web host is https://dashboard.substratalapps.com (matches the API's billing examples).

5. Package changes

  • 75 screens (was 68): +NTF-01…06, +APL-07, BIL screens replaced; GLB-03 Inbox folded into NTF-01; GLB-02 is now the combined Manage hub; GLB-03 is System states.
  • 16 flows (was 11): F10 rewritten; F12–F16 added.
  • New: CHANGES.md. Updated: every shared document and every platform spec and screen list; mockups add Inbox, Devices, My plan, and Push credentials screens.

Last updated 2026-10-24 · Built 2026-10-25 from a9ef3be · API 1.0.0-draft.13 · Substratal-Version: 1