Skip to main content
Short answers to the questions integrators hit in the first hour. Each one links to the authoritative page if you want the full detail. Looking up a specific error instead? The Troubleshooting and Errors pages are organized for that.
Every status, header, and error body quoted below was captured live from the partner sandbox at https://phosra-api-sandbox-production.up.railway.app on 2026-07-06. Package versions were verified against the public npm registry the same day.

Keys & environments

The prefix tells you which environment a developer API key belongs to, and each key works against exactly one base URL:
Sandbox / testProduction / live
Prefixphosra_test_phosra_live_
Base URLhttps://phosra-api-sandbox-production.up.railway.app/api/v1https://prodapi.phosra.com/api/v1
Touches real families?No — isolated sandbox dataYes
A phosra_test_ key only authenticates against the sandbox, and a phosra_live_ key only against production. Crossing them returns 401 invalid API key — the key’s hash simply isn’t in that environment’s store. Mint both on the same Keys page (pick the environment). Full detail: Authentication → Test keys vs live keys.
Authorization: Bearer phosra_… is the canonical header and the one every example on this site uses. X-Api-Key: phosra_… is accepted as an exact equivalent — use it only if a proxy or framework reserves the Authorization header. When both are present, Authorization wins. There is no Basic auth and no query-string key. See Authentication → The one correct header.
No. The sandbox’s consumer routes (/api/v1/families, /api/v1/children/…, /api/v1/setup/quick, /health, the Trust List) are open, so your first request returns real data with zero credentials — the Quickstart proves it. You only need a phosra_test_ key when you want to exercise the /api/v1/developer/* routes and hit the exact scope + rate-limit behavior you’ll see in production.

The sandbox

There is no scheduled destructive wipe. The seeded reference data — the demo family (Mia, Leo, Ava) and the accredited reference providers — is always present. Anything you create persists, and the write endpoints are idempotent: POST /setup/quick de-dupes on (family, child_name, birth_date) and self-registering a DID is create-only (a repeat returns 409, never a silent overwrite). To start from a clean object, use a new child name or a fresh self-registered DID rather than looking for a reset button — there isn’t one. See Test in the sandbox.
Yes. Nothing you do in the sandbox touches a real family or production data — it runs on its own database. Going to production is a two-line change: swap the base URL to https://prodapi.phosra.com/api/v1 and send a phosra_live_… key. The request and response shapes are byte-for-byte identical. See Test in the sandbox.
No — sandbox services auto-sleep when idle and cold-start on the first request, so an occasional 502/503 or a slow first response is expected. Retry once after a few seconds and it’ll be warm. See Errors → Server errors.

401 vs 403

401 = we don’t know who you are. The credential is missing, malformed, unknown, revoked, or expired.
{ "error": "Unauthorized", "message": "invalid API key", "code": 401 }
403 = we know who you are, but you’re not allowed to do this. The credential is valid but lacks the scope, standing, or accreditation tier for the request. A /developer/* call with no key at all is a 403 (the request reached the scope check with an empty scope set):
{ "error": "Forbidden", "message": "no API scopes in context", "code": 403 }
A valid key that’s missing a scope returns { "message": "missing required scope: write:enforcement", "code": 403 }. Fix a 401 by correcting the credential; fix a 403 by granting the scope (or standing). Full matrix: Errors → Client errors and Authentication → Error responses.
Same status, different cause. On OCSS Trust Framework routes (rule writes, enforcement confirmations, consent) a 401 means the request signature is missing or invalid, and the body carries "class": "signature_invalid":
{ "error": "Unauthorized", "message": "exactly one Signature-Input and one Signature header are required", "code": 401, "class": "signature_invalid" }
Branch on code and class, never on the prose message. See Do I need to sign my requests? below and Errors → OCSS error classes.
They mean different things and never substitute for each other: a 404 not_found means the resource genuinely does not exist (a stale ID is never silently redirected to a live one), while a 401 means an auth/signature problem. The Troubleshooting → 401 vs 404 section walks through telling them apart.

Signing

Do I need to sign my requests?

It depends on the surface — most integrations never sign anything.
  • Developer REST routes (/api/v1/developer/* and the consumer /api/v1/* routes): no signing. A phosra_ API key (or a WorkOS session JWT) in the Authorization header is all you need. This is the vast majority of the API — families, children, policies, enforcement, devices, webhooks.
  • OCSS Trust Framework routes (signed rule writes, enforcement confirmations, consent attestations, receipts): yes — RFC 9421 HTTP Message Signatures are required, signed with a key that’s published on the Trust List. These carry the extra class field and return 401 signature_invalid when the signature is absent or wrong.
You don’t hand-roll the signature: the @openchildsafety/ocss library signs and verifies OCSS envelopes, and @phosra/link wraps the consent ceremony + signed rule-write directives. See Authentication for how API keys, WorkOS JWTs, and request signing fit together.
First-party parent apps (web / iOS / Android) sign users in with WorkOS AuthKit and pass the resulting RS256 access token as Authorization: Bearer <workos_jwt>. The API only validates the JWT — there is no /auth/register, /auth/login, or /auth/refresh on the Phosra API (those live in WorkOS). Server-to-server integrations use a phosra_ API key instead. See Authentication → Consumer path.

Rate limits

The free/sandbox default is 100 requests per 60-second rolling window. Authenticated calls are counted per developer org (every key in the org shares one bucket, so adding keys does not add quota); unauthenticated sandbox reads are counted per source IP. Paid plans raise the ceiling. The unauthenticated OCSS discovery reads (Trust List, profiles, Annex B editions) are unmetered. Full detail: Rate limits.
Read the headers on the response you already have — don’t hard-code a number. Every metered /api/v1/* response carries:
x-ratelimit-limit: 100
x-ratelimit-remaining: 89
x-ratelimit-reset: 1783334580
X-RateLimit-Reset is Unix epoch seconds. On a 429, honour Retry-After (seconds) and retry exactly once — there’s a copy-paste backoff loop in curl, TypeScript, Python, and Go on the Rate limits page.

SDKs & npm package names

Phosra’s client libraries publish under @phosra/*, and the vendor-neutral OCSS reference library under @openchildsafety/*. There is no published @ocss/* npm scope — if you saw that anywhere, it’s stale. Versions verified live against the npm registry on 2026-07-06:
PackageVersionWhat it does
@phosra/sdk0.1.0Typed control-plane client (PhosraClient) — families, children, policies, rules, enforcement
@openchildsafety/ocss0.1.3OCSS reference library — sign/verify receipts, sealed envelopes, Trust List, vocabulary
@phosra/link0.1.2Writer-plane SDK — consent ceremony + signed rule-write directives
@phosra/gatekeeper0.2.2Platform-side — verify signed profiles, local decision engine, §8.3.8 receipts
@phosra/connect0.1.1Embeddable Connect component (the “Plaid Link” for parental-controls apps)
@phosra/mcp0.4.0MCP server exposing Phosra tools to AI agents (npx @phosra/mcp)
@phosra/cli0.2.0Partner CLI — scaffold configs, verify OCSS setup, sandbox round-trip checks
@phosra/provider0.1.0Provider-side helpers over @openchildsafety/ocss
@phosra/classify0.1.1Rule-category classification helpers
Start with @phosra/sdk for the REST API, or the SDK overview for the full map.
TypeScript is the first-party REST SDK today; a typed Python client is planned. Every other language calls the plain-JSON REST API directly — the Quickstart proves the curl, Python, and Go paths run copy-paste against the live sandbox, and the OpenAPI spec drives code generators for any language. The native iOS and Android enforcement SDKs are distributed privately (not on npm or Maven Central) — email developers@phosra.com for repo access. See iOS SDK and Android SDK.
Yes — npx @phosra/mcp --api-key=KEY exposes Phosra’s tools over the Model Context Protocol to any MCP-compatible agent (Claude, and others). See MCP Server.

Going to production

Two changes, no code rewrite: (1) swap the base URL from the sandbox host to https://prodapi.phosra.com/api/v1, and (2) swap your phosra_test_… key for a phosra_live_… key from the same Keys page. Request and response shapes are identical. Note that production and sandbox Trust Lists differ — the production census admits only accredited parties (governance-gated). See Authentication → Verify your setup.
Both operations use your WorkOS session bearer. POST …/keys/{keyId}/regenerate issues a new secret in place (the old one stops working); DELETE …/keys/{keyId} kills a key permanently (any request with it then returns 401 "API key has been revoked"). For zero-downtime rotation, mint a second key, deploy it, then revoke the old one. Full steps: Authentication → Rotation.

Still stuck?

Troubleshooting

Symptom-first fixes — find what you’re seeing, run the check, apply the fix.

Errors reference

Every HTTP status and error class, each with its cause, its fix, and a live example.

Authentication

How API keys, WorkOS sessions, and RFC 9421 request signing fit together.

Support

Reach a human — the developer inbox, filing bugs, and honest response expectations.