Skip to main content
POST
/
enforcement-confirmations
import { createGatekeeper } from "@phosra/gatekeeper"
const gk = createGatekeeper({
  platformDid: "did:ocss:loopline",
  platformKeyId: "did:ocss:loopline#2026-06",
  gatekeeperSigningKey: { seed: new Uint8Array(32) /* real Ed25519 seed */, keyID: "did:ocss:loopline#2026-06" },
  censusBaseUrl: "https://phosra-api-sandbox-production.up.railway.app",
  trustRootXB64Url: process.env.PHOSRA_TRUST_ROOT_X,
  endpointId: "iGrFqzp43O0S9YTNN2oAT6zMzcugEX_EwZbraWrE1AA",
})
const verdict = gk.check("infinite_scroll_block")
// ...apply the decision at the edge, then attest the outcome:
await verdict.confirm("applied") // signs the §8.3.8 receipt + POSTs it
{
  "id": "rcpt_01KWVD0ABX041061050R3GG28A",
  "type": "enforcement_result",
  "spec": "OCSS-v1.0-pre",
  "body": {
    "applied_at": "2026-07-06T09:43:59.612Z",
    "enforcement_state": "applied",
    "envelope_ref": "env_9f2c1a7e",
    "method_class": "platform_gate",
    "rule_ref": "rr_loopline_infinite_scroll_block"
  },
  "key_id": "did:ocss:loopline#2026-06",
  "sig": "ed25519:mGm30Y7TKrhTnTXH8fq2H8BaaVwFGOJCmJpI_F1hqefhCf9u9I5TRZawk2t12KSiq0pyuCbgzxjeQF11djnUAA"
}
The enforcing app POSTs its own signed enforcement_result receipt attesting that it applied a rule. The census verifies the caller’s RFC 9421 signature (the caller must equal the receipt’s signer — first-person binding, §8.3.8 cl.1) and records the receipt verbatim. It does not re-sign or append to the Receipt rail. The request body is the full outer receipt (id, type, spec, body, key_id, sig), not just the inner EnforcementResultBody. Three spec-pinned invariants:
  • §6.2 NOT-A-WRITE — this is the app’s attestation, not a policy write.
  • §10.6 NEVER-GATES-THE-RULE — a missing or rejected confirmation never blocks or revives the rule’s enforcement.
  • HONEST CEILING (§8.3.8) — “reported applied, never proven applied.”

Worked example

The @phosra/gatekeeper SDK is the supported path — verdict.confirm() constructs and signs the receipt, then POSTs it for you:
import { createGatekeeper } from "@phosra/gatekeeper"

const gk = createGatekeeper({
  platformDid:          "did:ocss:loopline",
  platformKeyId:        "did:ocss:loopline#2026-06",
  gatekeeperSigningKey: { seed: /* 32-byte Ed25519 seed */ new Uint8Array(32), keyID: "did:ocss:loopline#2026-06" },
  censusBaseUrl:        "https://phosra-api-sandbox-production.up.railway.app",
  trustRootXB64Url:     process.env.PHOSRA_TRUST_ROOT_X!,
  endpointId:           "iGrFqzp43O0S9YTNN2oAT6zMzcugEX_EwZbraWrE1AA",
})

const verdict = gk.check("infinite_scroll_block")
// ...apply the decision at the edge, then attest the outcome:
await verdict.confirm("applied")   // signs the §8.3.8 receipt + POSTs /enforcement-confirmations
The Python/Go sign_receipt here is byte-verified: signing the receipt body shown in the 201 capture below reproduces its exact sig (ed25519:mGm30Y7T…). It is a faithful port of the SDK’s signReceipt (JCS over {body, spec, type}, §8.3.8 D-9 boundary). A live rule_ref from a profile you actually enforced is required — a fabricated one is rejected 401/403, which is why verdict.confirm() (recommended tab) is the reliable path.

What comes back

The census records your receipt and echoes it back byte-for-byte — it never re-signs or wraps it (§8.3.8 cl.3: the app’s own receipt IS the artifact). So the 201 body is the exact receipt you POSTed. A byte-identical re-submit returns 200 with an OCSS-Replay: original header (the census deduplicates on rule_ref + caller DID); the same rule_ref with different content is a 409 replay.
The response bodies below are real wire captures — a live did:ocss:loopline-signed POST /enforcement-confirmations against the sandbox census (https://phosra-api-sandbox-production.up.railway.app), then the byte-identical re-POST. Not hand-written.
201 Created — your receipt, echoed verbatim
{
  "id": "rcpt_01KWVD0ABX041061050R3GG28A",
  "type": "enforcement_result",
  "spec": "OCSS-v1.0-pre",
  "body": {
    "applied_at": "2026-07-06T09:43:59.612Z",
    "enforcement_state": "applied",
    "envelope_ref": "env_9f2c1a7e",
    "method_class": "platform_gate",
    "rule_ref": "rr_loopline_infinite_scroll_block"
  },
  "key_id": "did:ocss:loopline#2026-06",
  "sig": "ed25519:mGm30Y7TKrhTnTXH8fq2H8BaaVwFGOJCmJpI_F1hqefhCf9u9I5TRZawk2t12KSiq0pyuCbgzxjeQF11djnUAA"
}
200 OK — idempotent re-submit (byte-identical body)
HTTP/2 200
content-type: application/json
ocss-replay: original
A 409 Conflict is returned only when the same rule_ref is re-submitted with different content (a D-13 replay), never for a faithful re-submit:
409 Conflict — same rule_ref, different content
{
  "error": "Conflict",
  "message": "(rule_ref, app_did) replayed with a different enforcement_result (D-13)",
  "code": 409,
  "class": "replay"
}
rule_ref must be a live per-child reference from a profile the caller actually enforced (§8.3.8 cl.1 first-person binding); the receipt signer must equal the RFC 9421 caller. A fabricated rule_ref or a signer/caller mismatch is rejected 401/403 — which is why the SDK’s verdict.confirm() (it carries the exact rule_ref from the verdict) is the reliable path.

Body

application/json

Full §8.3.8 signed receipt (the app's first-person apply attestation). The confirmation POST body IS this outer receipt — not the inner body alone. Sig covers canon.Marshal({body, spec, type}); id and key_id ride outside the signed bytes (D-9 exposure rule). Source: receipt.Receipt in internal/ocss/receipt/types.go with body = EnforcementResultBody.

id
string
required

rcpt_ — rides outside signed bytes (D-9).

Example:

"rcpt_01JTEST00000000000000000"

type
enum<string>
required

Always "enforcement_result" for §8.3.8 confirmations.

Available options:
enforcement_result
spec
string
required

OCSS spec version — §11.4 domain separation.

Example:

"OCSS-v1.0-pre"

body
object
required

JSON-encoded EnforcementResultBody. Kept as raw bytes: re-marshaling would alter the canonical signed bytes and break verification.

key_id
string
required

DID key id of the submitting enforcing app (rides outside signed bytes). Verified indirectly: the signature only verifies if the resolved key matches.

Example:

"did:ocss:snaptr#snaptr-2026-06"

sig
string
required

"ed25519:" + base64url-raw signature over canon.Marshal({body,spec,type}).

Response

Idempotent re-submit of the same receipt (same (rule_ref, app_did), byte-identical content). The body is the original receipt echoed verbatim — identical to the 201 body — and the response carries an OCSS-Replay: original header so a client can tell the write already landed.

Full §8.3.8 signed receipt (the app's first-person apply attestation). The confirmation POST body IS this outer receipt — not the inner body alone. Sig covers canon.Marshal({body, spec, type}); id and key_id ride outside the signed bytes (D-9 exposure rule). Source: receipt.Receipt in internal/ocss/receipt/types.go with body = EnforcementResultBody.

id
string
required

rcpt_ — rides outside signed bytes (D-9).

Example:

"rcpt_01JTEST00000000000000000"

type
enum<string>
required

Always "enforcement_result" for §8.3.8 confirmations.

Available options:
enforcement_result
spec
string
required

OCSS spec version — §11.4 domain separation.

Example:

"OCSS-v1.0-pre"

body
object
required

JSON-encoded EnforcementResultBody. Kept as raw bytes: re-marshaling would alter the canonical signed bytes and break verification.

key_id
string
required

DID key id of the submitting enforcing app (rides outside signed bytes). Verified indirectly: the signature only verifies if the resolved key matches.

Example:

"did:ocss:snaptr#snaptr-2026-06"

sig
string
required

"ed25519:" + base64url-raw signature over canon.Marshal({body,spec,type}).