@phosra/gatekeeper
SDK drives when a platform enforces child-safety rules at the edge. These are not plain
REST: profile reads are RFC 9421-signed by the resolver, binding writes require an
accredited caller signature, and profile responses are root-verifiable signed documents.
Building a parental-controls product (families, children, policies)? That surface is
the Phosra product API — a different plane. This data-plane is
for enforcement partners running a gatekeeper. Start with the
Platform quickstart if you are new.
The nine operations
Bind an endpoint
POST /enforcement-endpoints — mint a §9.3(b) bound-resolver label for a child.Rotate a label
POST /enforcement-endpoints/{id}/rotate — issue a fresh label, invalidate the old.Fetch the signed profile
GET /enforcement-profiles/{endpoint_id} — poll the router-signed enforcement profile.Confirm enforcement
POST /enforcement-confirmations — submit a signed §8.3.8 result receipt.Sandbox: run the connect ceremony
POST /sandbox/test-connect — the provider side of connect, to your own DID.Sandbox: mint test consent
POST /sandbox/consent-attestations — satisfy the consent-first gate with no roster edit.Sandbox OAuth: authorize
GET /oauth/authorize — reference parent-consent authorize leg.Sandbox OAuth: token
POST /oauth/token — exchange an authorization code for an access token.Sandbox OAuth: profiles
GET /oauth/profiles — bearer-scoped seeded child list.Base URL
| Environment | Base URL |
|---|---|
| Hosted sandbox (partner-facing, seeded, stable) | https://phosra-api-sandbox-production.up.railway.app/api/v1 |
| Local development | http://localhost:8080/api/v1 |
/oauth/* reference legs live on the census host root, not under /api/v1 — use
https://phosra-api-sandbox-production.up.railway.app/oauth/authorize.
Every example on these pages was executed against the hosted sandbox above and the real
responses are pasted in verbatim. The sandbox reference OAuth and
sandbox/* legs are
gated on PHOSRA_ENV==sandbox — they return 404 on production, by design.How a signed request is built
Every write and every profile read on this plane carries an RFC 9421 Ed25519 signature under your Trust-List-published key. The census reconstructs the same signature base and verifies provenance + accreditation before processing. Copy-paste signers in curl+openssl, TypeScript, Python, and Go — each verified end-to-end against this sandbox — live in the request-signing guide; the TypeScriptsignRequest from
@openchildsafety/ocss is shown below.

signer.ts
signRequest covers @method, @target-uri, ocss-spec-version, and — when a body is
present — content-digest, in that literal order. It emits:
The end-to-end loop
A gatekeeper binds once, then polls and confirms on a rotation cadence:Bind
POST /enforcement-endpoints returns your endpoint_id_label (the credential),
binding_id (for rotation), and connect_secret (for inbound connect verification) —
all three exactly once.Poll
GET /enforcement-profiles/{endpoint_id_label} returns a router-signed profile. Verify
the signature to the router key, then to the root, before trusting categories[].Enforce + confirm
Apply the
decision locally, then POST /enforcement-confirmations with a signed
§8.3.8 receipt (or call verdict.confirm("applied") in the SDK).