POST /setup/quick shape, the connect scopes, and the rules that
govern resets and retries.
Every value on this page was captured live from the sandbox while writing it. For a guided,
step-by-step tour of the same sandbox (health, the signed Trust List, self-registering a DID),
read Test in the sandbox; this page is the flat lookup table.
Base URL
One sandbox, one base URL.
phosra-api-sandbox-production.up.railway.app is the open
partner sandbox — no key, no signup, safe to hammer. Every curl on this page runs against
it verbatim. (You may see a -staging host elsewhere in the census; that one is a
Phosra-internal mirror and does not expose the reference-provider OAuth surface — use the
-production host above.) When you go live, swap the base URL for https://prodapi.phosra.com
and add a phosra_live_… key. The request and response shapes are identical.The cheat sheet
Everything fixed in the sandbox, in one scan. Each row links to its section below.| What | Value | Notes |
|---|---|---|
| Base URL | https://phosra-api-sandbox-production.up.railway.app | No key required |
| Health check | GET /health → {"status":"ok"} | Fastest liveness probe |
| Demo child — Mia | a11ce0fa-0000-4000-8000-0000000000a1 | subject_ref |
| Demo child — Leo | a11ce0fa-0000-4000-8000-0000000000a2 | subject_ref |
| Demo child — Ava | a11ce0fa-0000-4000-8000-0000000000a3 | subject_ref |
| Connectable provider | did:ocss:loopline | GET /providers/{did}/connect → 200 |
| Unconfigured provider | did:ocss:courier | GET /providers/{did}/connect → 404 (the accredited-but-unconfigured case) |
| One-call setup | POST /setup/quick | Family + child + active policy + 20 rules |
| Reference platforms | 22 ids across 4 categories | netflix, apple, nextdns, … |
| Session isolation header | X-Sandbox-Session: <any-string> | Deterministic per-caller data |
| Connect scopes | child_profiles.read (connect) / profiles (token) | Token mint |
| Trust List | GET /.well-known/ocss/trust-list | Signed, key_id=root-sandbox-2026-06 |
Demo child profiles
The sandbox is seeded with one demo family — Mia, Leo, and Ava — each with an active policy already in place. These are the profiles the connect ceremony shares, and theirsubject_ref values are stable across every sandbox reset, so you can hard-code
them in tests.
| Child | subject_ref (stable UUID) | Kind |
|---|---|---|
| Mia | a11ce0fa-0000-4000-8000-0000000000a1 | child |
| Leo | a11ce0fa-0000-4000-8000-0000000000a2 | child |
| Ava | a11ce0fa-0000-4000-8000-0000000000a3 | child |
/oauth/profiles leg returns them as a bare ChildProfile[]:
200 OK):
The consent code and access token are opaque, single-value strings (
sbxauth_… and sbxtok_…).
The sandbox flow is stateless — it does not persist codes or bind PKCE — so any freshly minted
sbxauth_ code exchanges cleanly. This is a sandbox affordance, not a production IdP.Reference providers
Providers live on the signed Trust List. Two are wired for the full connect ceremony and give you the two branches you need to test:| DID | Entity | GET /providers/{did}/connect | Use it to test |
|---|---|---|---|
did:ocss:loopline | Loopline (OCSS reference emitter) | 200 — returns authorize_url, token_url, profiles_url, scopes | The happy path: run the OAuth connect flow end to end |
did:ocss:courier | Courier Messaging | 404 provider connect config not available | The accredited-but-unconfigured branch |
200 OK):
did:ocss:aura, did:ocss:brightcanary, did:ocss:murmur,
did:ocss:beacon, did:ocss:household-acme, and more — plus a growing set of provisional
entries added by self-registration. Because self-registration is open, treat the total entry count
as a live number: verify each entry’s signature and tier rather than asserting on the total. See
Test in the sandbox for the signed-document
shape and how to self-register your own DID.
Reference platforms
GET /api/v1/platforms returns the 22 enforcement targets the sandbox can fan a policy out to,
grouped by category. Use any platform_id when connecting a platform or reading discovery results.
| Category | platform_ids |
|---|---|
device | fire_tablet, fire_tv, android, apple, apple_watch, microsoft |
dns | cleanbrowsing, controld, nextdns |
gaming | nintendo, playstation, xbox |
streaming | prime_video, disney_plus, hulu, max, netflix, paramount_plus, peacock, roku, youtube_tv, youtube |
POST /setup/quick
The fastest path to a working policy. Hand it a child’s name, birth date, and a strictness level; it creates a family, a child, an active policy, and a full set of age-appropriate rules — derived from the birth date, in one call, no follow-ups.Request fields
| Field | Type | Required | Description |
|---|---|---|---|
child_name | string | yes | The child’s display name. |
birth_date | string (YYYY-MM-DD) | yes | Drives the age band and the generated rule set. Send it in exactly this format — a malformed value is not cleanly validated today: the sandbox currently returns 500 Internal Server Error rather than a 400, so treat YYYY-MM-DD as a hard client-side requirement. |
strictness | string | no | relaxed, recommended (default), or strict. Adjusts rule configuration (screen-time minutes, filter level), not the rule count — you always get the full 20-rule set. |
family_id | string (UUID) | no | Reuse an existing family instead of creating one. Also the key to idempotent retries. |
family_name | string | no | Names a newly created family. Defaults to "<child_name>'s Family". |
Response shape (201 Created)
Trimmed to the top-level shape — the live rules array carries all 20 entries:
The 20 generated rule categories
The 20 generated rule categories
Every
POST /setup/quick returns these 20 rule categories (config values vary with the child’s
age and the strictness level):addictive_design_control, age_gate, algo_feed_control, content_rating,
data_deletion_request, dm_restriction, geolocation_opt_in, monitoring_activity,
notification_curfew, privacy_account_creation, privacy_profile_visibility,
purchase_approval, purchase_block_iap, social_chat_control, targeted_ad_block,
time_daily_limit, time_scheduled_hours, usage_timer_notification, web_filter_level,
web_safesearch.These are 20 of the 123 categories in the OCSS rule registry — the
age-based generator selects the subset relevant to a child’s age band.Connect and token scopes
The reference-provider OAuth flow uses two scope strings:| Leg | Scope | Meaning |
|---|---|---|
GET /providers/{did}/connect | child_profiles.read | The scope the provider advertises for the connect ceremony. |
POST /oauth/token response | profiles | The granted scope on the issued access token. |
Reset and idempotency
The sandbox has no destructive “reset” button — instead it gives you two levers so your tests stay clean and repeatable: Deterministic per-caller data (X-Sandbox-Session). Pass an X-Sandbox-Session: <any-string>
header and the sandbox keys all your data to a stable sandbox user for that session. Reuse the same
value across a test run to accumulate against one caller; use a fresh value to start from a clean
slate. Omit it and you share the default session.
family_id). POST /setup/quick deduplicates on
(family_id, child_name, birth_date). A repeat call that passes the family_id from a previous
response — with the same child name and birth date — returns the same child and policy rather
than minting a duplicate. This makes the endpoint safe to retry after a network failure, and it
repairs a half-created child from an interrupted first attempt.
Going to production
Nothing you do in the sandbox touches a real family. When you are ready, three changes flip you to production, and the request shapes are unchanged:Add a live key
Attach an
Authorization: Bearer phosra_live_… header. Create one in
the dashboard.