Quickstart

A runnable walkthrough: create a user, grant them an app, check their access, then turn it off. Every call here is a real endpoint documented in the API Reference — this page just stitches them into one story. Getting Started is where to go for orientation; this page is where to go to see it work.

  1. 1. Create a user
  2. 2. Confirm they own nothing yet
  3. 3. Grant access to an app
  4. 4. Check what they can actually do
  5. 5. Assign a role inside the app
  6. 6. Turn it off
  7. What this skipped

All requests below assume the Conventions base URL and an admin bearer token:

export SUBSTRATAL_API=https://api.substratalapps.com/v1
export TOKEN=<an access token for a superadmin or support user>

1. Create a user

curl -s -X POST "$SUBSTRATAL_API/users" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "email": "jordan@example.com", "status": "invited" }'
{
  "id": "usr_01JAG3Z9X8QS3F6K2M4N5P6R7S",
  "email": "jordan@example.com",
  "status": "invited",
  "...": "..."
}

See Users. A default Profile, Settings, and the member platform role were created alongside this — nothing further to call for those.

2. Confirm they own nothing yet

curl -s "$SUBSTRATAL_API/users/usr_01JAG3Z9X8QS3F6K2M4N5P6R7S/entitlements" \
  -H "Authorization: Bearer $TOKEN"
{ "data": [], "page": { "next_cursor": null, "has_more": false } }

3. Grant access to an app

In production, the Application developer’s own backend does this with its app-scoped API Key after its own billing confirms a payment (see Workflows → Purchase → access). Here, we grant directly, the way an admin comp or early-access grant would:

curl -s -X POST "$SUBSTRATAL_API/users/usr_01JAG3Z9X8QS3F6K2M4N5P6R7S/entitlements" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "application_id": "app_timetrack", "source": "admin_grant" }'
{
  "id": "ent_01JAGA1B2C3D4E5F6G7H8J9K0L",
  "application_id": "app_timetrack",
  "status": "active",
  "source": "admin_grant",
  "...": "..."
}

See Entitlements. status: active is the whole point — this is the on/off switch, and it’s now on.

4. Check what they can actually do

curl -s "$SUBSTRATAL_API/users/usr_01JAG3Z9X8QS3F6K2M4N5P6R7S/apps/app_timetrack/effective-permissions" \
  -H "Authorization: Bearer $TOKEN"
{
  "user_id": "usr_01JAG3Z9X8QS3F6K2M4N5P6R7S",
  "application_id": "app_timetrack",
  "allowed": false,
  "user_status": "invited",
  "entitlement_status": "active",
  "access_paths": [ { "source": "admin_grant", "entitlement_id": "ent_01JAGA1B2C3D4E5F6G7H8J9K0L", "status": "active" } ],
  "roles": [],
  "effective_permissions": [],
  "computed_at": "2026-10-05T12:00:00Z"
}

allowed is still false: the user is invited, and access requires an active user. Activate them so the rest of the walkthrough works (outside a quickstart, they’d accept the emailed invitation instead):

curl -s -X PATCH "$SUBSTRATAL_API/users/usr_01JAG3Z9X8QS3F6K2M4N5P6R7S" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "active" }'

Check again: allowed: true, entitlement_status: "active".

effective_permissions is still empty, because no Role has been assigned yet (and app_timetrack here has no default_app_role) — owning an app and having a role inside it are different axes. See Access Control.

5. Assign a role inside the app

curl -s -X POST "$SUBSTRATAL_API/users/usr_01JAG3Z9X8QS3F6K2M4N5P6R7S/roles/role_timetrack_admin" \
  -H "Authorization: Bearer $TOKEN"

Repeat step 4 and effective_permissions now includes whatever role_timetrack_admin grants (e.g. app.timetrack.export).

6. Turn it off

curl -s -X PATCH "$SUBSTRATAL_API/entitlements/ent_01JAGA1B2C3D4E5F6G7H8J9K0L" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "disabled", "disabled_reason": "quickstart_demo" }'

Repeat step 4 again: allowed is false, entitlement_status is now disabled, and effective_permissions is back to [] — the Role assignment from step 5 is still there underneath, untouched, ready the moment the entitlement is re-enabled. See Workflows → Admin turns an app off for a user.

What this skipped

Login/token issuance (Auth), the app-launch JWT and introspection that a downstream app calls rather than an admin (Trust Model), and webhook delivery (Webhooks) — all real, all documented, just not needed to see the core access model work end to end.


Back to top

Substratal Apps Platform API — living specification. This site is the system of record; see git history for how it has changed over time.

This site uses Just the Docs, a documentation theme for Jekyll.