Workflows
End-to-end sequences across the resources in the API Reference. If you’re adding a feature, check here first — it’s probably a step inside one of these, not a new flow.
- Purchase → access
- Admin turns an app off for a user
- Role change
- New user, first app
- A customer needs dedicated or regional infrastructure
- An org admin narrows who an org-wide grant reaches
- Settings resolution, in practice
Purchase → access
The most common path: someone buys an app and it shows up, switched on, in their hub.
sequenceDiagram
participant Billing
participant Hub as Hub API
participant User
participant App as Downstream App
Billing->>Hub: POST /v1/webhooks/incoming/billing — order.paid (user, application)
Hub->>Hub: upsert Entitlement(status=active, source=purchase, order_id=...)
Hub->>Hub: emit entitlement.granted
User->>Hub: GET /v1/users/me/entitlements
Hub-->>User: app now listed, status=active
User->>App: launches app (SSO redirect)
App->>Hub: verify token or GET effective-permissions
Hub-->>App: entitlement=active, effective_permissions=[...]
- Billing (the system of record for payment, see Decisions) completes an order and notifies the hub, either by calling the hub’s incoming webhook endpoint or the hub polling billing — whichever direction is chosen, the result is the same write.
- The hub upserts an
Entitlementwithstatus: active,source: purchase, linked to theorder_id. - The hub emits
entitlement.grantedon its own webhook system, for any downstream app that wants to react immediately (e.g. pre-provision a workspace) rather than wait for the user to show up. - The user’s hub dashboard now lists the app as available the next time it calls
GET /v1/users/{id}/entitlements. - The user launches the app. The app verifies the user’s standing against the hub — either by decoding the JWT issued at redirect, or calling the live
effective-permissionsendpoint — per the Trust Model.
Admin turns an app off for a user
The “kill switch” flow — a support agent or admin disabling one user’s access to one app, without touching anything else about their account.
PATCH /v1/entitlements/{id}with{"status": "disabled", "disabled_reason": "..."}.- The hub writes an Audit Event capturing the actor, before/after state, and reason.
- The hub emits
entitlement.revoked. - Any app subscribed to that webhook can invalidate an in-progress session immediately. An app relying only on JWT expiry will honor the change at the next token refresh — see Trust Model for the tradeoff.
- Nothing about the user’s Role assignments, Profile, or Settings for that app changes — re-enabling the entitlement restores exactly what was there before.
Role change
- An admin calls
POST /v1/users/{id}/roles/{roleId}(assign) orDELETE(remove) — platform-scoped or app-scoped. effective_permissionsfor that user (and, if app-scoped, that app) changes immediately on the hub side.- The hub emits
role.assigned/role.removed. - Downstream, this is picked up the next time the app checks — introspection call or next token refresh — not necessarily mid-session, unless the app subscribes to the webhook. This is a materially lower-urgency propagation requirement than an entitlement revocation: a user getting slightly stale permissions for a few minutes is a much smaller problem than a de-provisioned user keeping access.
New user, first app
POST /v1/userscreates the account; a defaultProfileandSettingsrecord is created alongside it; the default platform Role (member) is assigned.- The user acquires an app — either a purchase (see above) or an admin/invite grant (
source: admin_granton the Entitlement, noorder_id). - The first time the user opens that app, an
AppProfileandAppSettingsrecord is created lazily, seeded from the Application’s declared defaults — there’s no separate “provision this user in this app” step to orchestrate; reading or writing either resource for a user who doesn’t have one yet creates it with defaults.
A customer needs dedicated or regional infrastructure
Support-run today — see Decisions → Tenancy tiers for why this isn’t self-service yet.
- A customer (an Application owner) asks support for dedicated infrastructure, or a specific region for data residency.
- Support calls
POST /v1/tenants/{id}/tier-change-requests— see API Reference → Tenancy. - Support schedules a brief maintenance window, flips the Tenant’s
statustomigrating, and runs the snapshot/restore cutover described in Deployment Architecture → Tenancy tiers — every Entitlement, AppProfile, and AppSettings row carrying thattenant_idmoves to the new infrastructure. tier/region/statusare updated back toactive; an Audit Event (tenant.tier_changed) records it.- Nothing about the customer’s Applications, Entitlements, or any end-user’s access changes shape — this workflow only ever moves where the same rows live, never what they say.
An org admin narrows who an org-wide grant reaches
- An org admin (
OrganizationMembership.role: org_admin) callsPATCH /v1/entitlements/{id}on their Organization’sorg_seatEntitlement to an Application, settingmember_scope: allowlistordenylistandmember_overrides. - The hub writes an Audit Event (
entitlement.member_scope_changed) — notentitlement.disabled/entitlement.granted, since the grant’s ownstatusdidn’t change. - Every affected member’s
resolved_entitlement_statusfor that Application is recomputed at read time, not backfilled — there’s no per-member row to update. A member excluded this way keeps any separate, personally-sourced Entitlement to the same app untouched — see Access Control → Organization vs. User precedence. - Downstream, this is picked up the same way a Role change is — next introspection call or token refresh, not necessarily mid-session unless the app subscribes to the matching webhook.
Settings resolution, in practice
When an app needs to know a setting’s value for a user (e.g. notification channel preference), the read order is always:
AppSettings override (this user, this app)
→ Settings override (this user, global)
→ Application's declared default for that key
The hub resolves this server-side — GET /v1/users/{id}/apps/{appId}/settings returns the fully-resolved object, not just the override layer, so callers never have to re-implement the fallthrough themselves.