/api/v1/sessions
Exchange a publishable key + identity for a principal session (200)
Terminal-user session exchange (Gate B W3). Credential: `Authorization: Bearer
pk-eaas-…` ONLY — machine keys, platform keys and principal tokens are rejected at
the prefix gate. The body declares at most one provider: {anonymous:true} (the
server assigns a random prn_ principalId — lost credentials cannot be recovered
from the sub alone) or {identityToken} (a unified-login platform access JWT; the
server pins token_use:'access', aud containing 'web', role:'human' and the
revocation blacklist, then binds the im_users identity — the SAME identity on the
SAME project recovers the SAME principalId across devices/re-issues, even after the
old session rows were revoked).
200 (not 202): a session is a synchronously issued non-async resource. Re-issuing
mints a NEW token every time; unexpired previous tokens stay valid side by side.
environmentId is a server-validated NOMINATION (must exist inside the publishable
key's pinned tenant+project, else 404 not_owned); a session without one has an
empty reachable set (fail-closed). Re-binding means re-issuing.
Client-declared principalId / environmentIds / unknown fields are explicit 400s
(never silently ignored). Response is exactly five fields — token (ps-eaas-…,
plaintext shown once; only its sha256 is stored), expiresAt, principalId,
effectiveScopes (key scopes ∩ principal subset) and effectiveBudget (the
principal-granularity ledger view; limitCredits: null = the project sets no
principalBudget). Budget top is re-read from the project policy at spend time, so
policy edits affect existing sessions immediately.
Rate limiting, in order: an IP bucket (60/min, XFF last hop) runs BEFORE key parsing;
the key-sha256 bucket (30/min) follows; issuance is additionally capped at 100
sessions per publishable key per UTC day (429 + Retry-After to the next UTC day).
Revoking a publishable key does NOT retroactively kill already-issued sessions —
session rows have their own expiry/revocation face.
Request Body
| Field | Type | Req | Default | Description |
|---|---|---|---|---|
| anonymous | boolean | N | — | true → anonymous provider; principalId is a server-assigned `prn_` id, unrecoverable if lost. |
| identityToken | string | N | — | Unified-login platform access JWT. Validated (`token_use:'access'`, `aud` contains `'web'`, `role:'human'`, revocation blacklist) and bound to `im_users` — the same identity on the same project recovers the same principalId. |
| ttlSeconds | integer | N | 86400 | Session lifetime in seconds. |
| environmentId | string | N | — | Environment NOMINATION — must exist inside the publishable key's pinned tenant+project (404 `not_owned` otherwise); one session binds one environment, a session without one reaches nothing (fail-closed). |