Skip to main content
POST
/
sandbox
/
consent-attestations
Signed curl (wire shape)
# Signed headers are per-request — compute with the SDK (Node tab).
curl -X POST https://phosra-api-sandbox-production.up.railway.app/api/v1/sandbox/consent-attestations \
  -H "Content-Type: application/json" \
  -H "OCSS-Spec-Version: OCSS-v1.0-pre" \
  -H 'Signature-Input: ocss=("@method" "@target-uri" "ocss-spec-version" "content-digest");created=1783315514;keyid="did:ocss:loopline#2026-06";alg="ed25519"' \
  -H 'Signature: ocss=:<base64-ed25519-sig>:' \
  -H 'Content-Digest: sha-256=:<base64-sha256-of-body>:' \
  -d '{"band":"13_15","consent_scope":"collection_parental_authority"}'
{
  "ok": true,
  "app_ref": "did:ocss:dx24c6fcc23",
  "target_ref": "child:c22fd864-a783-5354-bfbb-d7d066b17592",
  "standing_ref": "consent:attestation:sbx-consent:did:ocss:dx24c6fcc23:child:c22fd864-a783-5354-bfbb-d7d066b17592",
  "idempotency_key": "sbx-consent:did:ocss:dx24c6fcc23:child:c22fd864-a783-5354-bfbb-d7d066b17592",
  "band": "13_15",
  "consent_scope": "collection_parental_authority",
  "expiry": "2027-07-06T09:01:54Z",
  "note": "sandbox-only test consent; pass audience_did=<this DID> and child_ref=<target_ref> to POST /api/v1/enforcement-endpoints to complete the consent-first mint"
}
Sandbox only. Gated on PHOSRA_ENV==sandbox — returns 404 on dev, staging, and production. Production §8.3.2 consent semantics are unchanged.
Mints a §8.3.2-shaped test consent row with app_ref = your RFC 9421 caller DID, so a cold self-registered platform can satisfy the consent-first gate on POST /enforcement-endpoints with no OCSS_CONSENT_ATTESTATION_APPS roster edit and no live counterparty. With no child_ref, the census auto-provisions the sandbox self-serve test child and targets it. A supplied child_ref must already exist — the door never fabricates a caller-named child. The response gives you the target_ref to pass straight into the bind call.

Worked example

import { signRequest } from "@openchildsafety/ocss"

const BASE  = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
const seed  = new Uint8Array(Buffer.from("bG9vcGxpbmUBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE", "base64url"))
const keyID = "did:ocss:loopline#2026-06"

const targetURI = BASE + "/sandbox/consent-attestations"
const body = { band: "13_15", consent_scope: "collection_parental_authority" }   // both optional; these are the defaults
const bodyText = JSON.stringify(body)
const headers = signRequest({ method: "POST", targetURI, body: new TextEncoder().encode(bodyText), keyID, seed, created: Math.floor(Date.now() / 1000) })
headers["Content-Type"] = "application/json"

const res = await fetch(targetURI, { method: "POST", headers, body: bodyText })
const consent = await res.json()
console.log(res.status, consent.target_ref)   // pass target_ref to POST /enforcement-endpoints
Real 201 response (captured from the hosted sandbox):
{
  "ok": true,
  "app_ref": "did:ocss:loopline",
  "target_ref": "child:5ba0d00c-0000-4000-8000-0000000000c1",
  "standing_ref": "consent:attestation:sbx-consent:did:ocss:loopline:child:5ba0d00c-0000-4000-8000-0000000000c1",
  "idempotency_key": "sbx-consent:did:ocss:loopline:child:5ba0d00c-0000-4000-8000-0000000000c1",
  "band": "13_15",
  "consent_scope": "collection_parental_authority",
  "expiry": "2027-07-06T05:26:40Z",
  "note": "sandbox-only test consent; pass audience_did=<this DID> and child_ref=<target_ref> to POST /api/v1/enforcement-endpoints to complete the consent-first mint"
}
The call is idempotent on (app_ref, target_ref) — re-minting returns the same standing_ref. Next: bind the endpoint.

Body

application/json
child_ref
string

Optional child: target. Empty ⇒ the auto-provisioned sandbox self-serve test child.

Example:

"child:5ba0d00c-0000-4000-8000-0000000000c1"

band
enum<string>
default:13_15
Available options:
under_13,
13_15,
16_17,
adult
Available options:
collection_parental_authority,
third_party_disclosure

Response

Test consent minted. Pass audience_did= and child_ref=<target_ref> to POST /api/v1/enforcement-endpoints to complete the consent-first mint.

ok
boolean
required
Example:

true

app_ref
string
required
Example:

"did:ocss:playnest"

target_ref
string
required
Example:

"child:5ba0d00c-0000-4000-8000-0000000000c1"

standing_ref
string
required
Example:

"consent:attestation:sbx-consent-playnest-5ba0d00c"

band
string
required
Example:

"13_15"

Example:

"collection_parental_authority"

expiry
string<date-time>
required
idempotency_key
string
note
string