Skip to main content
Phosra has three authentication surfaces, one per caller. Pick the row that matches what you are building — the rest of this page drills into each.

Which credential do I use?

Most integrations use the developer API key — start there. The WorkOS JWT path is for first-party parent apps that sign users in; the device key is for the iOS on-device agent only.

The one correct header

A developer API key goes in the Authorization: Bearer header. This is the canonical form and the one we use in every example on this site:
X-Api-Key: phosra_… is also accepted as an exact equivalent. The API checks Authorization: Bearer first and falls back to X-Api-Key; when both are present, Authorization wins. Use X-Api-Key only if a proxy or framework reserves the Authorization header — otherwise prefer Authorization: Bearer so keys, WorkOS JWTs, and MCP tokens all share one header. Both were verified against the live sandbox: a well-formed-but-unknown key returns the same 401 invalid API key on either header.
Do not wrap an API key in any other scheme — there is no phosra_sk_ infix, no Basic auth, no query-string key. A request with no phosra_-prefixed credential falls through to the next auth layer and, on a /developer/* route, returns 403 no API scopes in context.

Test keys vs live keys

Every developer key is bound to one environment at creation time. The prefix tells you which (the full per-environment base-URL matrix lives on Environments & base URLs):
A phosra_test_ key only works against the sandbox base URL, and a phosra_live_ key only works against production. Crossing them returns 401 invalid API key — the hash simply isn’t in that environment’s key store.
The sandbox is designed to be tried without any signup: its consumer routes (/api/v1/families, /api/v1/children/…) are open so you can explore request/response shapes with zero credentials. The /api/v1/developer/* routes still require a real phosra_test_ key so you can exercise the exact scope + rate-limit behavior you will hit in production. See Test in the sandbox.

Mint a server key

Key creation is self-serve and needs no pre-existing key — you authenticate the creation call with your WorkOS session bearer (from signing in), then the minted phosra_ key authenticates everything after. Full walkthrough: Create your account & get keys.
1

Sign in to the developer console

Sign up or log in via WorkOS AuthKit at dashboard.phosra.com/signup. The developer dashboard auto-provisions your developer org on first visit.
2

Create a key — in the browser or via API

The Keys page mints keys in the UI. Or call the API with your WorkOS session bearer:
Set "environment": "test" for a phosra_test_ key or "live" for phosra_live_.
3

Copy the key — it is shown exactly once

The response body carries the raw key in the key field. It is never retrievable again — only a SHA-256 hash is stored. Save it to a secret manager immediately.

Use the key

Point baseUrl at the sandbox and send the key as a bearer token. Every tab below is copy-paste and runs against the live sandbox as-is:
/api/v1/{resource} (WorkOS JWT) and /api/v1/developer/{resource} (API key) are the same handlers — the prefix just selects the auth path. Pick the prefix that matches your credential; both return identical response shapes. See the surface map.

Scoping

Every key carries an explicit list of scopes. A request to a route whose scope your key lacks returns 403, never silent success. Grant the fewest scopes the integration needs. These are the scopes you can attach to a key at creation time:
These 13 are the scopes the key-minting endpoint accepts. Requesting any other string returns 400 invalid scope: <name> naming the valid set — so only ask for the ones above. (Child operations are covered by the families scopes; there are no separate children, devices, or webhooks read/write pairs.)
Split keys by service, not one key to rule them all. A read-only reporting job should hold only read:* scopes; an enforcement worker holds write:enforcement. If one leaks, the blast radius is that key’s scopes on that environment — and you rotate just that key.

Rotation

Rotate on a schedule and immediately on any suspected exposure. Two operations, both requiring your WorkOS session bearer:
Zero-downtime rotation without regenerate cutting you off mid-flight:
1

Mint a second key

POST …/keys with the same scopes. You now have two valid keys.
2

Deploy the new secret

Roll the new phosra_… value into your secret manager and restart workers. Both keys work, so there is no gap.
3

Revoke the old key

DELETE …/keys/{oldKeyId}. Confirm traffic is all on the new key (check the key’s last_used_at via GET …/keys), then you are done.
Never commit a key, embed it in client-side code, or log it. Keys live in environment variables / secret managers and are used server-side only. If a key ever lands in a commit, revoke it — do not just remove the line.

Consumer path — WorkOS AuthKit JWT

First-party parent apps sign users in with WorkOS AuthKit and pass the resulting access token to the API.
There is no /auth/register, /auth/login, or /auth/refresh on the Phosra API — those return 404. Account creation, sessions, and refresh all happen in WorkOS. The API only validates the JWT.
The API verifies each token as an RS256 JWT against WorkOS’s JWKS:
  • Web: the authkit-nextjs SDK manages the session cookie and refresh automatically.
  • Native (iOS/Android): run AuthKit’s hosted login, exchange the code through your own BFF, then send the WorkOS access token to the API. Token lifetime and refresh are handled entirely by WorkOS (native clients call your BFF’s /api/auth/mobile/refresh — a Next.js route, not an API route).
Routes under /auth that do exist: GET /auth/me (authenticated profile) and POST /auth/logout (no-op; WorkOS owns revocation).

On-device path — Device key

For iOS on-device enforcement via Apple FamilyControls. Device keys are issued by POST /children/{childID}/devices, stored in the iOS Keychain, and sent in X-Device-Key:
They authorize only device endpoints: GET /device/policy, POST /device/report, POST /device/ack.
X-Device-Key is for Apple FamilyControls on-device enforcement only. The CompiledPolicy it returns is shaped for iOS ManagedSettings and does not carry engagement rules (e.g. infinite_scroll_block, addictive_pattern_block). Web / server-side platforms use the OCSS provider path instead: RFC-9421 DID-signed requests + the signed enforcement profile. See Platform integration.

Consumer vs developer surface

/api/v1/{resource} and /api/v1/developer/{resource} are the same handlers — the split is an auth-path decision, not a capability split. Choose the prefix that matches your credential. Both return identical response shapes.

Error responses

Every auth failure returns a JSON body of the shape {"error", "message", "code"}. These are the exact responses the live API returns (verified against the sandbox):
Also "API key has been revoked" (after DELETE) and "API key has expired". For the WorkOS JWT path: "missing authorization header", "invalid authorization header format", or "invalid or expired token".
A /developer/* request with no phosra_ key at all returns { "error": "Forbidden", "message": "no API scopes in context", "code": 403 }.
Returned by POST …/keys when a requested scope isn’t one of the 14 above (also "name is required", "environment is required").

Verify your setup

Run this against the sandbox before wiring anything up. A 200 proves your key, header, and base URL all line up; a 401/403 maps directly to the errors above:
Then swap the base URL to https://prodapi.phosra.com/api/v1 and the key to your phosra_live_… value to go to production — the request shapes are identical.