Skip to main content
The Phosra sandbox is a complete, always-on copy of the API, seeded with a demo family and a set of accredited reference providers. It exists so you can build and verify a full integration — connect a platform, set up a family, enforce a policy, sign a request — before you ever provision a key. This guide is the map: what is seeded, what is open, and how to get yourself onto the Trust List. Every response below is verbatim live output, captured while writing this page.

The base URL

export SANDBOX="https://phosra-api-sandbox-production.up.railway.app"
Nothing you do in the sandbox touches a real family or production data. When you are ready for production, swap the base URL for https://prodapi.phosra.com and add a phosra_live_… key — the request shapes are identical.

What’s already seeded

ThingValueUse it for
Demo familyMia, Leo, Ava (children)The connect ceremony shares these three profiles
Reference provider (configured)did:ocss:looplineRun the full OAuth connect flow end-to-end
Reference provider (unconfigured)did:ocss:courierTest the 404 provider connect config not available branch
Trust List entries130+ on the signed Trust List (grows as parties self-register)Verify signatures and accreditation tiers
Reference platforms22 (nextdns, controld, apple, …)Discovery by capability and category
1

Confirm the sandbox is up

The /health endpoint needs no key and is the fastest liveness check:
curl -s "$SANDBOX/health"
# → {"status":"ok"}
2

Read the signed Trust List

The Trust List is the source of truth for who is accredited. It is served at a well-known path and the entire document is Ed25519-signed by the sandbox root key — verify the signature before you trust any entry inside it.
curl -s "$SANDBOX/.well-known/ocss/trust-list" \
  | jq '{alg, key_id, entries: (.document | fromjson | .entries | length)}'
Real response (200):
{
  "alg": "ed25519",
  "key_id": "root-sandbox-2026-06",
  "entries": 135
}
The entries count is a live, growing number — every self-registration (below) adds an entry, so expect a value at or above the one shown here. Verify the signature and each entry’s tier rather than asserting on the total.
The top-level object wraps a signed document: { "document": "…", "key_id": "…", "alg": "ed25519", "sig": "…" }. Parse document (itself JSON) to read the entries array — each entry carries a did, an entity name, its published jwks signing keys, and an accreditation tier. The @ocss/ts SDK verifies the signature and resolves keys for you.
No parameters, no auth. Returns the signed Trust List document.Top-level response fields (200)
FieldTypeDescription
documentstringThe Trust List as a JSON string — parse it to get { version, entries: [...] }. Signed as-is; verify before parsing.
key_idstringThe signing key id, root-sandbox-2026-06 in the sandbox.
algstringSignature algorithm, ed25519.
sigstringBase64url Ed25519 signature over document.
Fields on each entry (inside the parsed document.entries)
FieldTypeDescription
didstringThe party’s DID.
entitystringHuman-readable entity name.
jwksobjectThe party’s published signing_keys (and payload_keys), for verifying its envelopes.
tierstringAccreditation tier: provisional, verified, or accredited.
statusstringactive while the entry is valid.
valid_throughstring (RFC 3339)When the entry expires.
3

Self-register a provisional DID

You do not need anyone’s approval to start testing signed flows. Post your DID and a raw Ed25519 public key (base64url, unpadded) to POST /api/v1/advisors/self-register, and the census adds you to the sandbox Trust List at the provisional tier.First, mint a keypair and extract the raw 32-byte public key:
# Generate an Ed25519 private key
openssl genpkey -algorithm ed25519 -out sandbox-key.pem

# Extract the raw public key as base64url (unpadded)
PUB=$(openssl pkey -in sandbox-key.pem -pubout -outform DER \
  | tail -c 32 | base64 | tr '+/' '-_' | tr -d '=')
echo "$PUB"
Then register:
curl -s -X POST "$SANDBOX/api/v1/advisors/self-register" \
  -H "Content-Type: application/json" \
  -d "{
    \"did\": \"did:ocss:dx-demo\",
    \"public_key_b64url\": \"$PUB\",
    \"roles\": [\"provider\"]
  }"
Real response (200):
{
  "advisor_id": "fa97e1eb-1348-44c0-8954-2dec1df08d5c",
  "did": "did:ocss:dx-demo",
  "key_id": "did:ocss:dx-demo#2026-07",
  "kid": "2026-07",
  "published_key_x": "1NDtvUgkYV6h6XzR3y-FgAdKmqQ-i7XiWen7joyJYgA",
  "trust_tier": "provisional"
}
You are now on the sandbox Trust List. The key_id (did#kid) is what you sign your requests with; the census publishes your public key so counterparties can verify you.
provisional is enough to test the full signed flow in the sandbox. Moving to verified or accredited — the tiers that carry weight in production — is a governance step, not an API call. See Production accreditation.
Request body (application/json)
FieldTypeRequiredDescription
didstringyesYour chosen DID, e.g. did:ocss:dx-demo.
public_key_b64urlstringyesRaw 32-byte Ed25519 public key, base64url, unpadded.
rolesstring[]noRoles to claim, e.g. ["provider"].
key_id / kidstringnoOptional key id; defaults to the current YYYY-MM (e.g. 2026-07).
Response fields (200)
FieldTypeDescription
advisor_idstring (UUID)Your Trust List record id.
didstringEchoes your DID.
key_idstringFully-qualified signing key id, did#kid.
kidstringThe short key id, e.g. 2026-07.
published_key_xstringThe public key the census published for you (base64url).
trust_tierstringprovisional for a self-registration.
Errors
StatusmessageWhen it happens
400did is requireddid is missing from the body.
400public_key_b64url is requiredThe key field is missing.
400invalid_public_key_b64url: must decode to 32 bytes, got NThe key is not a valid 32-byte Ed25519 key (wrong length or bad encoding).

The sandbox host

Everything partner-facing points at one host — the same base URL used throughout these guides. It’s open, seeded, and requires no key:
HostBacks
https://phosra-api-sandbox-production.up.railway.appThe live openchildsafety.com walkthrough — the base URL used throughout these guides

Now build something

Connect a platform

Run the OAuth connect ceremony against the seeded reference provider.

Set up a family & kids

Build a family and an active policy in one call.

Quickstart

Zero to an enforced policy in under five minutes.