Verified live. Every header name and every sample value on this page was
captured with
curl -D - against the partner sandbox at
https://phosra-api-sandbox-production.up.railway.app on 2026-07-06. The
reads used below (/health, /api/v1/platforms, /.well-known/ocss/trust-list)
need no API key, so you can reproduce the exact bytes.Request headers
Headers you send. OnlyAuthorization (or X-Api-Key) is required for
authenticated routes; the RFC 9421 triplet is required only for signed census
writes.
Response headers
Headers Phosra sets. The rate-limit trio rides every/api/v1/* response; the
correlation id rides everything.
Authentication headers
A developer API key goes inAuthorization: Bearer. This is the canonical form
and the one every SDK sends:
X-Api-Key: phosra_… is accepted as an exact equivalent — the API checks
Authorization: Bearer first and falls back to X-Api-Key. Reach for it only
when a proxy or framework reserves the Authorization header; otherwise prefer
the bearer form so API keys, WorkOS JWTs, and MCP tokens all share one header.
Full details — key formats, scoping, rotation — live in
Authentication.
Content negotiation
The API speaks JSON in and JSON out. SendContent-Type: application/json on
any request with a body; Accept is optional because responses are JSON
regardless. Signed writes send their body as raw JSON bytes — the exact bytes
you signed the Content-Digest over, never a re-stringified object.
Signed writes (RFC 9421)
Census writes — binding mint (POST /enforcement-endpoints), key rotation,
POST /enforcement-confirmations, and bound-resolver profile GETs — are
authenticated with an RFC 9421
HTTP Message Signature (Ed25519), not just a bearer key. You send exactly one
Signature-Input and one Signature, plus a Content-Digest covering the
body:
keyid must be a did#kid published on the Trust List.
Get the triplet wrong — missing, malformed, duplicated, or an unknown key — and
the census returns 401 signature_invalid before any standing check:
signRequest helper builds all four headers for you — see
Idempotency for a full signed-write example and
Errors for the failure modes.
Rate-limit headers
Every/api/v1/* response tells you exactly where you stand in your window, so
you never have to guess. Read the headers on the response you already have:
X-RateLimit-Reset is Unix epoch seconds, not a duration. When you exhaust
the window you get 429 Too Many Requests with a Retry-After (seconds).
Branch on the status code and honour Retry-After — never parse a
human-readable error string. The full backoff loop, in four languages, is on
Rate limits.
Census safety paths —
/.well-known/ocss/*, the Trust List, enforcement
writes, consent ingest — are never rate-limited (fail-open is a P0
invariant), so they carry no X-RateLimit-* headers. A /.well-known/ocss/trust-list
read returns a cacheable ETag instead:Deprecation signals
Before anything inv1 changes, it carries machine-readable notice on the wire
so a gateway can detect it without reading these docs. A surface in a sunset
window responds with:
Deprecation— RFC 9745, an@-prefixed Unix timestamp of when the deprecation took effect.Sunset— RFC 8594, an HTTP-date of the committed removal.Link— a pointer to the human migration guide.
Sunset header in staging and you will never be
surprised by a removal. Windows and the full lifecycle are on the
Deprecation & Sunset policy.
Idempotency replay
A faithful retry — same body-borne key, same payload — returns the original bytes with200 OK and the header OCSS-Replay: original. Its absence
means a fresh apply. Read the status and this header; never diff bodies. A
conflicting replay (same key, changed payload) is rejected with 409 replay and
carries no OCSS-Replay. Full semantics on Idempotency.
The correlation id
Every response carries a correlation id you can quote in a support ticket so we can pull the exact request from our logs. Grab it before you contact anyone:Straight talk about this header’s name. The correlation id is currently
surfaced as
X-Railway-Request-Id, assigned by the sandbox’s hosting edge
(the census runs on Railway). It is a real, stable-per-request id our support
team can look up — it is not a Phosra-issued API field, and the name may
change to a vendor-neutral alias in a future release. Quote whatever
x-railway-request-id value the failing response actually returned; don’t
synthesize one, and don’t send an inbound X-Request-Id expecting it to be
echoed (it isn’t).See every header at once
curl -D - dumps the full response head. This is the fastest way to inspect
what Phosra actually set on any call:
Related
Authentication
Key formats, the
Authorization vs X-Api-Key fallback, scoping, rotation.Rate limits
The
X-RateLimit-* trio, Retry-After, and a copy-paste backoff loop.Idempotency
Why there is no
Idempotency-Key header, and what OCSS-Replay means.Deprecation & Sunset
The
Deprecation / Sunset / Link signals and the notice windows.Errors
Every status, class, and the
401 signature_invalid header failures.Support
What to send with a ticket — starting with the correlation id above.