Runnable. The signed worked example below was executed live against
https://phosra-api-sandbox-production.up.railway.app on 2026-07-06 using the
then-published @openchildsafety/ocss signer (v0.1.4). The response bytes are
pasted verbatim as historical evidence. Public integrations should install
current @openchildsafety/ocss@0.1.5, which preserves this signing behavior.Where the key lives — there is no Idempotency-Key header
Unlike some APIs, Phosra does not read an Idempotency-Key HTTP header. A write
gets its key one of two ways:
Either way the key is scoped to its operation (a frozen operation → namespace
table), so one operation’s replay space can never bleed into another’s.
The two outcomes
Once a(scope, key) has been applied, redelivering it has exactly two possible
results — decided by whether the payload is byte-identical to the first one:
1
First application → 201 Created
The write happens. You get
201 and the freshly signed receipt.2
Faithful replay → 200 + OCSS-Replay: original
Same key, byte-identical payload. Nothing runs a second time. You get
200,
the header OCSS-Replay: original, and the byte-identical original
receipt. This is a success, not an error.3
Conflicting replay → 409 replay
Same key, different payload. The key is bound to its first payload and cannot
be rebound:
409 Conflict, class: "replay", and nothing is applied. The
stored receipt is withheld.A faithful replay is success-shaped. It returns the original bytes and never
emits a failed-call receipt. The
200 vs 201 distinction is how you tell a
fresh apply from a replay without diffing bodies — read the status and the
OCSS-Replay header.Worked example — a server-derived key, live
The sandbox consent-attestation route is a signed (RFC 9421) write. Send the same signed request twice and the census returns a stable, server-derivedidempotency_key — proof that the operation is deduplicated on a deterministic
identity rather than on wall-clock time.
TypeScript
Response · both calls
idempotency_key is derived from (caller DID, target child) — no timestamp —
so it is identical on every honest retry. Pass the returned target_ref straight
into POST /enforcement-endpoints to
finish the consent-first mint.
Client-supplied keys
Where an endpoint accepts a client key (rule writes, source syncs), put it in the body and reuse it — with the same payload — on every retry:curl
200 with OCSS-Replay: original and the exact
receipt bytes from the first call.
The one pitfall: a changed payload
A409 replay almost always means a retried request mutated its body between
attempts — a regenerated timestamp, a fresh nonce, or a reordered array. The key is
frozen to its first payload; a different payload under the same key is rejected.
Response · 409 conflicting replay
Retry rules
Next steps
Errors
The
409 replay class in the full error table.Rate limits
How to retry safely without tripping the throttle.