endpoint_id_labels
to your app, your platform registers one endpoint with the census. Registration:
- declares your webhook URL — the base URL your
POST /api/ocss/connectreceiver lives under, and - returns two secrets exactly once — the
endpoint_id_label(your §9.3(a) registration name) and theconnect_secret(the HMAC key that authenticates inbound connect-leg deliveries).
@phosra/gatekeeper SDK wraps it end to end.
One endpoint, self-scoped. You register your own platform DID’s endpoint — the
signed request’s caller DID must equal the
{did} in the path. A mismatch answers the
same 404 an unknown platform answers (no existence leak). Re-minting the same
(did, connect_url) pair rotates both credentials — that is the EXT-04 §3.5 re-issue path.Prerequisites
Step 1 — Mint your endpoint — POST /api/v1/platforms/{did}/endpoints
The request is RFC-9421 signed with your DID’s Ed25519 key (the census verifies the
signature against your live Trust-List entry — provisional-tier self-registrations included).
There is no phosra_ API key on this path; the census identifies you by signature, not by a
bearer token.
Request body:
Because the request must be signed, mint through the SDK rather than raw
curl. Using
signRequest from @openchildsafety/ocss:
201 response — the two secrets are here and nowhere else (field order + value format
live-verified against the sandbox census):
endpoint_id_label and connect_secret are each an unprefixed 43-character base64url string
(a raw 32-byte secret, -_ alphabet, no eplbl_/cs_ prefix) — the two example values above are
clearly-fake placeholders in that exact format.
What each returned value is for
Step 2 — Declare your webhook receiver
Theconnect_url you registered is the base your POST /api/ocss/connect receiver lives
under. When a provider completes the connect ceremony, Phosra delivers the
endpoint_id_label server-to-server to that URL. Stand up the receiver and hand it to
@phosra/gatekeeper’s handleConnect — see Platform Quickstart → Step 1:
/api/ocss/connect to your registered base, so register the base
(e.g. https://snaptr.example.com/webhooks/ocss-connect) — the SDK and the census sender
agree on this path convention.
Step 3 — Verify inbound deliveries with the connect-secret
Phosra signs every connect-leg delivery with anX-Phosra-Signature header so your receiver
can prove the request came from Phosra and was not tampered with.
Algorithm: X-Phosra-Signature = lowercase_hex( HMAC-SHA256( connect_secret, rawRequestBody ) ).
@phosra/gatekeeper’s handleConnect implements the verify side for you.
Pass the connect_secret from Step 1 into createGatekeeper and the SDK verifies it for you,
fail-closed:
The @phosra/gatekeeper env contract — the six PHOSRA_* vars
A gatekeeper deployment is fully parametrized by six PHOSRA_* environment variables plus
one secret signing seed. Everything createGatekeeper needs maps 1:1 onto them:
Plus the signing seed — the one genuinely sensitive value, kept out of the six because it
is a private key, not configuration:
PHOSRA_TRUST_ROOT_X is a public key pinned out-of-band on purpose — that is what root
verification means: you do not fetch the root from the census you are about to verify. The
staging census is a Phosra-internal pre-release instance with a different root and is not a
partner surface — always use the canonical production sandbox host above.Conformance
The signed endpoint-mint (Step 1) needs your DID key, so it is exercised by the SDK, not rawcurl. What a docs-only stranger — or the nightly docs-conformance CI — can run with no
credentials is the reachability + trust-anchor check the whole registration depends on: the
canonical census serves a root-signed Trust List whose root matches the PHOSRA_TRUST_ROOT_X
pinned above.
endpoint_id_label at your webhook →
handleConnect 200 → refreshProfile → isAllowed) is exercised end-to-end by
scripts/sandbox/verify-web-engagement-rule.mjs, which exits 0 only if the full chain
survives against the live sandbox census.
Next
- Platform Quickstart — receive the connection, fetch/verify the profile, enforce locally, confirm
- Onboarding — get your sandbox
did:ocss:<slug>(self-serve, no email) - Conformance status — the one canonical sandbox host and every live/preview surface