Exchange a presented magic-link token for a first-party session
const url = 'https://quikstik-core.fly.dev/login/sessions';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"token":"example","device":{"name":"example","platform":"ios"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://quikstik-core.fly.dev/login/sessions \ --header 'Content-Type: application/json' \ --data '{ "token": "example", "device": { "name": "example", "platform": "ios" } }'Consumes the token (single-use, storage-arbitrated) and mints a first-party session for the
resolved (issuer, subject) actor. Expired, consumed, unknown, and unresolvable subjects
are one indistinguishable 404.
With an optional device, the session is also registered as a device session and the
response adds refresh_token (returned once) and refresh_expires_at_ms (now + 90 days).
A malformed device is a 400 returned before the link is consumed, so it never burns
the single-use token.
Request Bodyrequired
Section titled “Request Bodyrequired”object
Supplied by a device that wants a refresh credential (staff POST /login/sessions only).
object
Human label (“Wilton’s iPhone”); trimmed.
Responses
Section titled “Responses”Session minted (plus a refresh credential when a device was supplied)
object
The effective permission tokens of the session’s membership, sorted (empty when the membership is not active).
The highest role the scopes imply. Open (see contracts/openapi/README.md); the app reads ownership here, not from GET /team.
First-party bearer session; present as Authorization: Bearer.
Present only when a device was supplied. 32 random bytes, hex encoded. Shown exactly
once; only its SHA-256 digest persists.
Present with refresh_token; now + 90 days, epoch ms.
Example generated
{ "scopes": [ "example" ], "role": "example", "session_token": "example", "refresh_token": "example", "refresh_expires_at_ms": 1}Malformed body
object
Example generated
{ "reason": "example"}Expired, consumed, unknown, or unresolvable — indistinguishable by design
object
Example generated
{ "reason": "example"}No durable backend is wired for this operation (fail-closed)
object
Stable, machine-readable reason code (e.g. “sold_out”, “processor_not_configured”, “rail_refused”).
Example
{ "reason": "sold_out"}