Progression & portable-self state
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
Progression is Atlas's cross-property "portable self" state — a user's XP/level (and tier/flair) that can be carried across every property that shares the Atlas hub. A property grants signals; Atlas folds them into durable state and (optionally) projects them into the session token.
Grant a signal (idempotent)
curl -X POST "https://<fapi>/v1/users/<user_id>/progression/events" \
-H "Authorization: Bearer sk_…" -H "content-type: application/json" \
-d '{"track":"default","amount":50,"reason":"completed onboarding","idempotency_key":"onboard-2026-09-14"}'
# → { "track":"default", "xp": 350, "level": 4, "level_changed": true, "delta": 50 }Idempotent on
(source, idempotency_key)— a retry is a safe no-op that returns current state.sourceis stamped from the authenticated credential, never the body, so one property can't write as another.levelis derived from xp by a configurable curve — never trusted from the caller. Negative amounts (corrections/clawbacks) require the elevated*scope.
Read state
curl "https://<fapi>/v1/users/<user_id>/state" -H "Authorization: Bearer sk_…"
# → { "object": "user_state", "attributes": { "progression": { "default": { "xp": 350, "level": 4 } }, "tier": "...", "flair": "..." }, "entitlements": [], "directives": [], "roles": [] }Project into the session token
Set public_metadata.progression / .tier / .flair on the user and Atlas lifts them to top-level __session claims (present only when set), so a relying party reads the badge from the token with no extra call. See JWT templates for arbitrary custom claims.
Per-source scoping means a shared hub can host many properties without one overwriting another's signals.