This guide covers integrating Phosra into your application from scratch, including API key provisioning and your first enforcement run.
One auth header, everywhere. Every raw HTTP call on this page sends your key as
Authorization: Bearer $PHOSRA_API_KEY — the one canonical form (X-Api-Key is accepted as
an exact equivalent, but we use Bearer consistently so keys, WorkOS JWTs, and MCP tokens all
share one header). Full detail: Authentication.
1. Create Your Account
Sign up at dashboard.phosra.com/signup via the WorkOS AuthKit hosted sign-up flow. There is no /auth/register endpoint on the Go API — account creation is handled by WorkOS. Once signed in, continue to step 2. (Full walkthrough: Create your account & get keys.)
2. Get an API Key
Use the developer console’s Keys page or call the API with your WorkOS session:
curl -X POST https://prodapi.phosra.com/api/v1/developers/orgs \
-H "Authorization: Bearer <workos_access_token>" \
-H "Content-Type: application/json" \
-d '{"name": "My Integration"}'
# Then create a key for the org:
curl -X POST https://prodapi.phosra.com/api/v1/developers/orgs/{orgId}/keys \
-H "Authorization: Bearer <workos_access_token>" \
-H "Content-Type: application/json" \
-d '{"name": "server-key", "scopes": ["read:families","write:policies","write:enforcement"]}'
The response includes the key once. Store it immediately:
# Production key
export PHOSRA_API_KEY="phosra_live_4a1b2c..."
# Sandbox key (use against https://phosra-api-sandbox-production.up.railway.app/api/v1)
export PHOSRA_API_KEY="phosra_test_4a1b2c..."
Key format: phosra_live_<64 hex chars> (production) or phosra_test_<64 hex chars> (sandbox). There is no _sk_ infix.
3. Use Quick Setup for Onboarding
The fastest path for your end users. When a parent signs up and adds their first child in your app, call the quick setup endpoint:
curl -X POST https://prodapi.phosra.com/api/v1/setup/quick \
-H "Authorization: Bearer $PHOSRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"child_name": "Emma",
"birth_date": "2016-03-15",
"strictness": "recommended"
}'
This returns a family, child, and an active policy with age-appropriate rules populated across the applicable rule categories for the requested strictness level, plus age_group, max_ratings, and rule_summary. Store the family.id and child.id for subsequent calls.
Prefer to try this without a key first? The Quickstart runs the exact same call against the open sandbox — no auth — and shows the real response.
For each platform the family uses, create a compliance link:
curl -X POST https://prodapi.phosra.com/api/v1/compliance \
-H "Authorization: Bearer $PHOSRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"family_id": "FAMILY_UUID",
"platform_id": "nextdns",
"credentials": "nextdns-api-key"
}'
List available platforms with GET /platforms to see what integrations are supported, and check each platform’s enforcement_mode — one of dns, device, or manual_attested. dns and device apply rules programmatically (a live DNS-provider write, or on-device via the Phosra app); manual_attested returns guided steps for the parent to attest. See Platforms & enforcement modes.
5. Register Webhooks
Set up webhooks to receive real-time event notifications (policy changes, new family members, etc.):
curl -X POST https://prodapi.phosra.com/api/v1/webhooks \
-H "Authorization: Bearer $PHOSRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"family_id": "FAMILY_UUID",
"url": "https://yourapp.com/webhooks/phosra",
"events": ["policy.updated", "family.created"]
}'
Note: webhooks do not fire on enforcement job completion. To verify enforcement results, poll GET /enforcement/jobs/{jobId}/results — see Enforcement.
6. Trigger Enforcement
Push the policy to all connected platforms, then poll the returned job for results:
BASE="https://prodapi.phosra.com/api/v1"
CHILD_ID="CHILD_UUID" # from setup.child.id in step 3
# Trigger — returns a job (202 Accepted)
JOB_ID=$(curl -s -X POST "$BASE/children/$CHILD_ID/enforce" \
-H "Authorization: Bearer $PHOSRA_API_KEY" | jq -r .id)
# Poll results
curl -s "$BASE/enforcement/jobs/$JOB_ID/results" \
-H "Authorization: Bearer $PHOSRA_API_KEY"
A non-empty manual_steps array on any result means that platform is parent-guided, not programmatically applied.
Handle errors
Every failure returns a JSON envelope of the shape {"error", "message", "code"} (OCSS routes add
class and, on standing checks, failed_step). Branch on code + class, never on the human-readable
message. The full status/class matrix — every 4xx and 5xx, its cause, and its fix — is in the
Errors reference. The one you will hit first while wiring auth:
| Code | Meaning | Fix |
|---|
401 | invalid API key | Key not in this environment’s store — a phosra_test_ key only works against the sandbox, phosra_live_ only against production. |
403 | no API scopes in context | Request reached a /developer/* route with no phosra_ key at all — attach Authorization: Bearer $PHOSRA_API_KEY. |
403 | missing required scope: … | Key authenticated but lacks the scope — mint a key with the scope named in the message. |
429 | rate limited | Wait until X-RateLimit-Reset, then retry. |
500 | internal error | Transient — retry with exponential backoff. |
Base URLs
| Environment | Base URL |
|---|
| Production | https://prodapi.phosra.com/api/v1 |
| Sandbox | https://phosra-api-sandbox-production.up.railway.app/api/v1 — seeded demo family + phosra_test_ keys |
| Local dev | http://localhost:8080/api/v1 |
api.phosra.com has no DNS record — do not use it. Use prodapi.phosra.com for production. phosra-api.fly.dev is a legacy Fly.io address being decommissioned; use prodapi.phosra.com instead.
Checklist