API Reference
The Open Record REST API.
Read the open record — the 32 entities behind every wave, outcome, and contribution.
Provisional
@veraq/contracts — the single source of truth — and agree with the protocol reference (the seven entities). The REST resources, cursor pagination, and state-shaped errors are documented here; the live servers, authentication, and rate limits are gated on the product backend this repository does not contain, and are marked [OWNER TO CONFIRM].Conventions
- One REST resource per entity —
/waves,/mechanisms,/participants,/participations,/outcomes,/contributions,/causes— plural in paths, singular in prose. - Every list endpoint is cursor-paginated (
cursor+limit). - Every record carries its open-record reference, so a reader can cross-check it.
- Errors are documented as states, never failures-of-luck: a mismatch is
record_mismatch, a closed window iscommit_window_closed.
Error
A request error, named as a state (e.g. record_mismatch, commit_window_closed, not_found) — never a failure-of-luck.
codestringrequiredMachine-readable state.
messagestringrequiredHuman-readable, exact, never alarmist.
open_record_refstring | nullWhere applicable, the open-record entry the reader can cross-check.
Example response — every verifiable field (✓) is checkable against the open record
{
"id": "014",
"opens_at": "2026-06-14T16:00:00Z",
"closes_at": "2026-06-14T16:00:00Z",
"resolves_at": "2026-06-14T16:00:00Z",
"mechanism_id": "string",
"seats": {
"total": 1,
"taken": 0
},
"charitable_share": 0,
"beneficiary_cause_id": "string",
"status": "announced"
}Wave
A round of participation. Runs one mechanism; contains many participations; resolves to outcomes.
A round of participation. Runs one mechanism; contains many participations; resolves to outcomes. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200WavePageA page of waves.
A round of participation. Runs one mechanism; contains many participations; resolves to outcomes.
Parameters
idpath · requiredThe wave id.
Responses
200WaveThe wave.404
Wave
A round of participation. Runs one mechanism; contains many participations; resolves to outcomes.
idstringrequiredSequential wave identifier, zero-padded.
opens_atstringrequiredWhen participants may begin seating.
closes_atstringrequiredLast moment to seat a participation. Must be ≥ opens_at.
resolves_atstringrequiredWhen the mechanism seed is revealed and the outcome resolves. Must be ≥ closes_at.
mechanism_idstringrequiredULID reference to the published mechanism for this wave. The mechanism is published — including its seed commitment — before the wave opens.
seatsobjectrequiredtotalintegerrequiredtakenintegerrequiredcharitable_sharenumberrequiredFraction of the wave's outcome that flows to the beneficiary cause. Expressed in [0, 1], e.g. 0.12 == 12%.
beneficiary_cause_idstringrequiredSlug of the verified cause receiving the charitable share.
statusenumrequiredannounced · open · resolving · settled · cancelledWave lifecycle. 'announced' = mechanism published, not yet open. 'resolving' = window between closes_at and the recorded outcome. 'settled' = outcome verified and contributions transferred.
Mechanism
The published selection rule (commit-reveal-v1), committed to the open record before a wave runs.
The published selection rule (commit-reveal-v1), committed to the open record before a wave runs. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200MechanismPageA page of mechanisms.
The published selection rule (commit-reveal-v1), committed to the open record before a wave runs.
Parameters
idpath · requiredThe mechanism id.
Responses
200MechanismThe mechanism.404
Mechanism
The published selection rule (commit-reveal-v1), committed to the open record before a wave runs.
idstringrequiredULID of this mechanism document.
algorithmstringrequiredIdentifier of the algorithm spec in the veraq-protocol repository.
parametersobjectAlgorithm-specific parameters. Shape is determined by the algorithm field and validated by the spec in veraq-protocol/algorithms/<algorithm>.md.
seed_commitmentstringrequiredLowercase hex SHA-256 of (seed || parameters_canonical_json). Binding commitment published before the wave opens.
seed_revealedstring | nullLowercase hex of the 32-byte seed. Null until resolves_at; non-null after. Verifying: SHA-256(seed_revealed || parameters_canonical_json) must equal seed_commitment.
published_atstringrequiredWhen the commitment was published. Must be < the linked wave's opens_at.
revealed_atstring | nullWhen seed_revealed was published. Null while undisclosed; ≥ wave.resolves_at when set.
verifying_transcript_urlstring | nullOptional URL to a verifying transcript (re-run output) for additional inspectability.
Participant
A person taking part. Makes participations; chooses a cause.
A person taking part. Makes participations; chooses a cause. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ParticipantPageA page of participants.
A person taking part. Makes participations; chooses a cause.
Parameters
idpath · requiredThe participant id.
Responses
200ParticipantThe participant.404
Participant
A person taking part. Makes participations; chooses a cause.
idstringrequiredStable participant identifier (ULID).
verdify_identity_idstringrequiredForeign key into Verdify's own identity space (ADR 0011). Names the `usr_…` identity this participant record projects. Required and non-null — an explicit design decision of this epic, not an inference from a ceremony this repo has not built yet (`04` `W6-E04`, `W6-E09` are unbuilt): ADR 0011 and `01-platform-architecture.md` §3.4 D4 establish only that Veraq builds no sign-in of its own, not when a `Participant` row is first created relative to identity resolution. If a future epic finds a real lifecycle state where a seat exists before its Verdify identity resolves, this field's nullability is this epic's call to revisit, not a settled fact to work around. Only the `usr_` prefix is validated; the token's own internal structure is Verdify's to define, not Veraq's — following the same opaque-external-id convention `commitment_id` and `product_id` already use (ADR 0023 Decision 6).
handlestring | nullOptional public-facing handle. May be null for participants who choose not to display one.
created_atstringrequiredWhen the participant first seated.
verified_atstring | nullWhen identity verification was completed, if applicable. Null if unverified.
Participation
One participant's entry into a wave; written to the open record.
One participant's entry into a wave; written to the open record. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ParticipationPageA page of participations.
One participant's entry into a wave; written to the open record.
Parameters
idpath · requiredThe participation id.
Responses
200ParticipationThe participation.404
Participation
One participant's entry into a wave; written to the open record.
idstringrequiredWave-scoped participation id. Format: wave_id, hyphen, 4-character suffix.
wave_idstringrequiredparticipant_pseudonymstringrequiredReplaces `participant_id` per `01-platform-architecture.md` §4.3 change 5: "Replace `participant_id` and any durable signature in published entries with a per-instance pseudonym; hold the mapping salted in Custody, so erasure destroys the salt rather than the record." PER-INSTANCE, LOAD-BEARING NOT DECORATIVE: this value is scoped to THIS participation record only — never a stable value reused across the same participant's other participations in other waves. A single durable pseudonym reused across many published Participation records would ITSELF become "a durable signature" and re-enable cross-wave correlation of one participant's activity, which is exactly what change 5 also separately bans by naming "any durable signature," not only the literal field `participant_id`. RESOLUTION (pseudonym → the real participant) happens ONLY via a salted mapping held in Custody — the `.net` port `04` W2-E03 builds — never inline in this record, and never derivable from these bytes alone by an outside reader. NO PATTERN, DELIBERATELY, on fund.schema.json `id`'s own precedent ("no document fixes an id space for this... inventing one would freeze a byte before its gate"): this schema commits only to SHAPE — opaque, non-empty, per-instance, unlinkable without Custody's mapping — never to a derivation scheme (which hash, which KDF). The exact construction is UNSPECIFIED because the authority that was meant to specify it, "Core blueprint §11.4," does not exist anywhere in this repository or its git history — `G-blueprint` (`03-product-model.md`:611, "UNRESOLVED — recorded, not removed"; `04-implementation-roadmap.md`:169). Building that mapping, its salt storage and the cascade it must survive is `W8-E14`'s job (`04-implementation-roadmap.md`:740-742), not this schema-shape change's. ERASURE (later, `W8-E14`'s job) destroys the salt in Custody's mapping, not this record — the published Participation entry survives unchanged, append-only, per this corpus's Open Record philosophy, while re-identification becomes permanently impossible.
seated_atstringrequiredweightnumberOptional weighting used by weighted-selection mechanisms. Omitted means weight = 1.
kindenumcontributor · recipientADR 0039 — the participation-role distinction. OPTIONAL, WITH NO DEFAULT: a family whose participations play one undifferentiated role (official-result, sponsored-funding, forecasts, community-participation) simply never sets this field, and omission asserts nothing about whether that participation paid into the container — declaring a default here would misdescribe those families' non-paying, free-entry seated participants as payers by default, exactly the false assertion ADR 0039 exists to avoid. `contributor`: this participation funded the container's pool. `recipient`: this participation did not fund the pool and may instead receive value the mechanism assigns to it — `sortition-funding`'s qualified-proposal recipient (`03-product-model.md` §5.2) is the motivating case, and `allocation.schema.json`'s `recipient_participation_id` is expected to resolve to a `recipient`-kind participation for that family, never to a `contributor`-kind one, though this schema enforces no cross-document check. BOTH KINDS MAY COEXIST IN ONE CONTAINER: this is a per-participation leaf property, never a per-container setting, because `sortition-funding`'s own pool holds contributing participants and qualified-proposal recipients side by side — that coexistence is exactly what invariant 3's 2026-08-14 qualification (`03` §5.2) names. THIS DOES NOT REACH ADR 0015 §5's closed, seven-item crossing-authority set: `Allocation` still discharges 'to a participant, from `OBLIGATION_PARTICIPANT`' (ADR 0015:100) exactly as written — this field only names which role a given `Participation` record plays; it neither widens, renames nor adds to the authority set, and `allocation.schema.json`'s own description already distinguishes the record-level `Allocation` entity from ADR 0015's crossing authority for the identical reason. NOT A REGULATORY CLAIM: this field records a mechanical fact — who paid in and who did not — and settles no question about whether any family is a chance-prize product in any jurisdiction; see `03` §5.2's own 'Regulatory character' paragraph and ADR 0012's classification-memo gate, which this field neither answers nor forecloses.
signaturestring | nullOptional Ed25519 signature (hex, 64 bytes) by the participant over canonical(wave_id || participant_pseudonym || seated_at) — updated from canonical(wave_id || participant_id || seated_at) now that `participant_id` no longer exists as a field (`01-platform-architecture.md` §4.3 change 5). When present, the open record can verify the participation was authorised by the participant's key. OPEN — RECORDED, NOT RESOLVED: change 5 names "any durable signature" as in scope, not only the literal `participant_id` field. A signature verified against a participant's own STABLE, reused Ed25519 key would itself remain a durable, cross-participation-correlatable signal — regardless of this pseudonym fix — if the same key is reused across a participant's multiple participations. Whether the signing key itself must become per-instance too (e.g. a fresh keypair per participation) is a genuine open cryptographic-protocol design question this schema-shape change does not resolve. Flagged, citing `G-blueprint` (the "Core blueprint §11.4" authority this all traces to does not exist in this repository or its git history — `03-product-model.md`:611): key-management policy is `W8-E14`'s to decide (or a future epic's), not this one's. No key-rotation scheme is asserted here.
Outcome
What a wave resolves to. A defined share routes to a contribution.
What a wave resolves to. A defined share routes to a contribution. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200OutcomePageA page of outcomes.
What a wave resolves to. A defined share routes to a contribution.
Parameters
idpath · requiredThe outcome id.
Responses
200OutcomeThe outcome.404
Outcome
What a wave resolves to. A defined share routes to a contribution.
idstringrequiredWave-scoped composite (03 §2 level 6 — an Outcome is genuinely container-bound, unlike Contribution.outcome_id, which W1-E11 deliberately decoupled). NO LONGER derived from, or equal to, any recipient_participation_id by convention (canon-defect-register.md D20, resolved by this epic): W1-E08's Allocation set already gives an Outcome many recipients, so no single recipient_participation_id is left for this id to be named after — the derivation convention the pre-Allocation design practised is gone, not merely undocumented.
wave_idstringrequiredrecipient_participation_idstringrequiredThe participation selected by the mechanism. The participant behind it can be looked up via the participation record.
mechanismobjectrequiredSnapshot of the mechanism state at the moment of settlement. Sufficient on its own — combined with the wave's participation list — for an independent verifier to reproduce the selection.
mechanism_idstringrequiredalgorithmstringrequiredseed_revealedstringrequiredverifying_transcript_sha256string | nullOptional content hash of the verifying transcript, if one was published.
verifiedbooleanrequiredWhether at least one independent verifier has replayed the mechanism and matched the recipient. Outcomes are not considered fully settled until verified == true.
settled_atstringrequiredContribution
The defined share routed to a cause, derived from an outcome.
The defined share routed to a cause, derived from an outcome. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ContributionPageA page of contributions.
The defined share routed to a cause, derived from an outcome.
Parameters
idpath · requiredThe contribution id.
Responses
200ContributionThe contribution.404
Contribution
The defined share routed to a cause, derived from an outcome.
idstringrequiredoutcome_idstringrequiredThe outcome this transfer settles. NO PATTERN: this field previously carried the wave-scoped composite pattern (`^[0-9]{3,6}-[0-9A-HJKMNP-TV-Z]{4}$`), which made this money leg wave-shaped in the frozen bytes even though `01` §1.3 calls it primitive-agnostic — the defect `03` §1.4 diagnoses: "`contribution.schema.json:25` patterns `outcome_id` as the wave-scoped composite, so the money leg that `01` §1.3 calls primitive-agnostic is wave-shaped in the frozen bytes." ADR 0025 §7 confirms `W1-E11` acceptance 3 undoes that here, on `Allocation.outcome_id`'s own no-pattern precedent (`allocation.schema.json`). `minLength: 1` is strictly weaker than any pattern: it refuses only the empty string, which names no outcome, and freezes no id space.
cause_idstringrequiredamountobjectrequiredvaluestringrequiredDecimal string. Stored as string to avoid floating-point precision loss.
currencystringrequiredISO-4217 alphabetic code, or a supported crypto ticker (e.g. USDC, ETH). The supported crypto set is defined at the application layer (@veraq/i18n CRYPTO); other pattern-valid codes are not rejected here. `01` §4.3 change 4 ('upstream the crypto currency pattern') is resolved by this field ALREADY carrying the correct, product-matching pattern — no schema edit was needed here. `packages/contracts/upstream/schemas/contribution.schema.json` is deliberately left untouched and still shows the older `^[A-Z]{3}$` shape: per its own `MANIFEST.json` ('This file DECIDES NOTHING... a refresh is a claim about what the world serves and should be made by a person'), that file is a dated, human-attested capture of a real historical commit, not a mirror to keep in sync with local fixes — editing it without a genuine new capture would misrepresent history. The resulting VENDORED divergence `tooling/ci/contracts-drift-check.mjs` reports for this field is therefore permanent and expected, not a residual defect; `G-Q5` (ADR 0029: satellite repos archived) governs whether that snapshot is ever regenerated, and this schema-authoring epic does not pre-empt it.
transferred_atstring | nullWhen the transfer was confirmed. Null while pending.
proof_urlstring | nullOptional URL to a third-party transfer proof — bank receipt, on-chain transaction, etc.
Cause
A verified public-good recipient of contributions chosen by participants.
A verified public-good recipient of contributions chosen by participants. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200CausePageA page of causes.
A verified public-good recipient of contributions chosen by participants.
Parameters
idpath · requiredThe cause id.
Responses
200CauseThe cause.404
Cause
A verified public-good recipient of contributions chosen by participants.
idstringrequiredStable slug. Used wherever a cause is referenced.
namestringrequireddescriptionstringrequiredverificationobjectrequiredHow this cause was verified as eligible to receive charitable share. The brand promise requires this to be inspectable.
methodenumrequiredregistry · manual-review · third-party-attestationHow verification was performed.
registrystring | nullWhen method == 'registry', the registry identifier (e.g., 'gs1-charities-uk:1148231').
verified_atstringrequiredverifierstringrequiredName or identifier of the verifying party.
evidence_urlstring | nullpayout_addressobjectWhere the contribution is transferred — now the payout-rail discriminated union `payout-rail.schema.json` defines (`01-platform-architecture.md` §4.3 change 3, driven by D5, ADR 0012; `04` W4-E02), rather than opaque free text. `01` §4.3 change 3's own defect text: 'Nullable free text, mixing escrow handles, IBANs and `0x` addresses — three incompatible rails, no discriminator.' `$defs.payoutRail` above is a byte-for-byte copy of `payout-rail.schema.json`'s own `oneOf` — `cause.schema.json` is a vendored schema and this package's ajv setup compiles each schema independently with no cross-file `$ref` registration (no `ajv.addSchema` linking files together), so the only reuse mechanism available here is verbatim duplication into a local `$defs` entry, proven never to silently diverge by this schema's own structural test in `cause.test.mjs` (`schemas.cause.$defs.payoutRail.oneOf` deep-equals `schemas.payout_rail.oneOf`). `null` remains valid — unchanged from this field's prior nullability, meaning 'not yet set.' Any non-null value must now match exactly one of the three named, `kind`-discriminated rails: `bank_iban`, `crypto_address`, or `escrow_handle`; the old bare free-text form no longer validates. Wired in HERE, in one commit with `01` §4.3's other five changes, because `04` W1-E11's own acceptance 5 requires exactly that sequencing.
operating_jurisdictionstringrequiredADR 0031 Decision 3: '`Fund` and `Cause` gain a jurisdiction-linked, computed-allocation-input field at v1 — an actual schema field, not descriptive text — landing as part of `W1-E11`'s one-shot migration.' `02-ecosystem-architecture.md` §8, the Foundation Principle: 'The system records jurisdiction faithfully and makes jurisdiction-linked flows reportable... The system does not encode an allocation rule... The architecture supplies the evidence; the Foundation makes the decision.' THIS FIELD CARRIES NO ALLOCATION LOGIC ITSELF — ADR 0031 Consequences: 'No allocation-rule code exists yet... this is a decision, not an implementation.' A plain jurisdiction value, the same record-shape-not-computation separation this corpus draws everywhere (e.g. `reserve-obligation.schema.json`'s own top-level description: 'THIS IS A RECORD SHAPE, NOT A COMPUTATION'). Named `operating_jurisdiction`, deliberately NOT `source_jurisdiction` (`fund.schema.json`'s own field, ADR 0013 Decision 1) — `Cause` is destination-side while `Fund` is source-side (ADR 0028 Decision 4: Fund/Cause cardinality stays orthogonal), and this field creates no foreign key or cardinality relationship to `Fund`; each entity independently carries its own jurisdiction dimension. REQUIRED, not optional or nullable — matching this batch's established precedent of adding new required fields to existing vendored entities rather than leaving one that could silently go unpopulated (see `participant.schema.json`'s `verdify_identity_id`). ISO 3166-1 alpha-2 shape, the SAME pattern `fund.schema.json`'s `source_jurisdiction` uses. `G-jurisdictions` (which real markets are served) remains OPEN, so every real fixture uses an ISO 3166-1 user-assigned test code (e.g. `ZZ`), never a real market — matching `fund.schema.json`'s own fixtures' convention.
Allocation
One recipient's share of the participant-distributable class, reaching that recipient at the resolution of one outcome — a level-6 record entity (03 §2; ADR 0016 §1 spells the level out as 'the per-event record entities').
One recipient's share of the participant-distributable class, reaching that recipient at the resolution of one outcome — a level-6 record entity (03 §2; ADR 0016 §1 spells the level out as 'the per-event record entities'). Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200AllocationPageA page of allocations.
One recipient's share of the participant-distributable class, reaching that recipient at the resolution of one outcome — a level-6 record entity (03 §2; ADR 0016 §1 spells the level out as 'the per-event record entities').
Parameters
idpath · requiredThe allocation id.
Responses
200AllocationThe allocation.404
Allocation
One recipient's share of the participant-distributable class, reaching that recipient at the resolution of one outcome — a level-6 record entity (03 §2; ADR 0016 §1 spells the level out as 'the per-event record entities').
idstringrequiredIdentity. NO PATTERN, on container.schema.json's precedent: no document fixes an id space for this leaf, and inventing one would freeze a byte before its gate. ITS IDENTITY IS INDEPENDENT OF THE RECIPIENT: an entry is not named after the participation it allocates to, and no description here says otherwise — which is the convention 04 W1-E08 acceptance 3 strikes, applied at the level this epic owns. The vendored `Outcome` still states the derivation for its own id; that sentence is 04 W1-E11's to remove, and ADR 0025 §3 records why it could not be removed here. NON-EMPTY: an empty string is not an identity, and a leaf naming nothing would validate while referring to no object. `minLength: 1` is strictly weaker than any pattern, so it freezes no id space — it only refuses the one value that can never be one.
outcome_idstringrequiredThe outcome whose distribution this entry belongs to. MANY entries may name one outcome — that is the whole point, and it is what the singular `Outcome.recipient_participation_id` could not express. NO PATTERN, DELIBERATELY: 03 §1.4 diagnoses the defect a pattern would repeat — 'contribution.schema.json:25 patterns outcome_id as the wave-scoped composite, so the money leg that 01 §1.3 calls primitive-agnostic is wave-shaped in the frozen bytes. That leak happened BECAUSE THE CONTAINER HAD NO LEVEL, so its shape defaulted sideways into its neighbour.' 04 W1-E11 acceptance 3 has to undo that in `contribution`; committing it a second time here would double the migration. NON-EMPTY: an empty string is not an identity, and a leaf naming nothing would validate while referring to no object. `minLength: 1` is strictly weaker than any pattern, so it freezes no id space — it only refuses the one value that can never be one.
recipient_participation_idstringrequiredThe participation this entry allocates to. NO PATTERN: participation.schema.json owns that id space and 04 W1-E11 owns the one-shot migration that may change it, so repeating the pattern here would put one piece of knowledge in two places and make the migration two edits. THE RECIPIENT IS A PARTICIPATION, NOT A PARTICIPANT — 01 §4.3 change 5 replaces participant identifiers in published entries with a per-instance pseudonym, and an allocation naming a participant directly would be a durable identifier in an anchored entry. NON-EMPTY: an empty string is not an identity, and a leaf naming nothing would validate while referring to no object. `minLength: 1` is strictly weaker than any pattern, so it freezes no id space — it only refuses the one value that can never be one.
amountAllocation_positiveQuantityrequiredThe amount allocated, in the CONTAINER'S DECLARED UNIT — the same unit as that container's `target` (03 §1.3), resolved through this entry's outcome. No currency member, deliberately: the unit is declared once, by the container, and a per-entry currency would be a second place to say one thing AND would drag in contribution.schema.json's `^[A-Z]{3,4}$`, which is 01 §4.3 change 4 and blocked by G-Q5.
allocated_atAllocation_instantrequiredWhen this entry was recorded. Ordering against the container's resolution is not expressible in JSON Schema and is 04 W3-E09's, on the precedent container.schema.json set for `opens_at`.
Attestation
An independent party's report that it replayed a settled outcome and what it found — the open class 03 §5.5(b) names as the source of Outcome.verified: '.net's open attestation class, which anyone may publish and for which Veraq certifies nobody and pays nobody.' THE OPENNESS IS THE CONTROL, NOT A CONVENIENCE.
An independent party's report that it replayed a settled outcome and what it found — the open class 03 §5.5(b) names as the source of Outcome.verified: '.net's open attestation class, which anyone may publish and for which Veraq certifies nobody and pays nobody.' THE OPENNESS IS THE CONTROL, NOT A CONVENIENCE. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200AttestationPageA page of attestations.
An independent party's report that it replayed a settled outcome and what it found — the open class 03 §5.5(b) names as the source of Outcome.verified: '.net's open attestation class, which anyone may publish and for which Veraq certifies nobody and pays nobody.' THE OPENNESS IS THE CONTROL, NOT A CONVENIENCE.
Parameters
idpath · requiredThe attestation id.
Responses
200AttestationThe attestation.404
Attestation
An independent party's report that it replayed a settled outcome and what it found — the open class 03 §5.5(b) names as the source of Outcome.verified: '.net's open attestation class, which anyone may publish and for which Veraq certifies nobody and pays nobody.' THE OPENNESS IS THE CONTROL, NOT A CONVENIENCE.
idstringrequiredIdentity. NO PATTERN, on container.schema.json's precedent: no document fixes an id space for this class, and inventing one would freeze a byte before its gate. NON-EMPTY, because an empty string is not an identity.
outcome_idstringrequiredThe settled outcome this attestation reports on. NO PATTERN, DELIBERATELY: 03 §1.4 records that contribution.schema.json patterns `outcome_id` as the wave-scoped composite, so 'the money leg that 01 §1.3 calls primitive-agnostic is wave-shaped in the frozen bytes', and 04 W1-E11 acceptance 3 has to undo it there. Repeating it here would make that migration one file wider. NON-EMPTY, because an attestation of nothing is not an attestation.
attesterstringrequiredWHO REPLAYED IT — AN OPEN SET. Resolved against nothing: no pattern, no enum, no registry, no format. 03 §5.5(b): 'anyone may publish, and for which Veraq certifies nobody and pays nobody.' This is the exact inverse of the envelope's `publisher`, which specs/record-envelope-v1.md §2 makes registry-resolved and fail-closed; see this schema's own description for why the two do not share a name. `minLength: 1` is the ONLY bound and is not a narrowing of the set: an unnamed attester is not a party, and an attestation nobody made cannot be checked by anyone. A verifier reading this member learns who to go and ask, and learns nothing about whether Veraq agrees.
stateenumrequiredattested · pending · mismatchWhat the attester found. `attested` — replayed and matched. `mismatch` — replayed and did not match. `pending` — has not finished. The three are 04 W1-E09 acceptance 1's, and NONE of them names Veraq or an endorsement, because the value set is as much a surface for an upward default as a member name is. A CLOSED enum rather than a registry: 03 §11's resolution discipline is for the SEVEN registry kinds, an eighth would fail tooling/ci/registry-artefact-check.mjs's seven-artefact rule, and 05 §11 forbids this epic adding a registry row. The cost of the closed set — 03 §1.3's 'a new enum member added after the first anchor invalidates every existing verifier's exhaustiveness check' — is real and recorded at ADR 0026 open item 1 rather than resolved here.
observed_digestobjectrequiredThe transcript digest the attester actually computed — 03 §5.5's 'an attestation that a published algorithm on published inputs produced transcript digest D'. NULL while `pending`, present otherwise, and never absent: 03 §1.4 rules out an optional field in an anchored proof format, so a verifier reads a present null rather than guessing at an absence. It is the OBSERVED value only. The published value it is compared against is reached through `outcome_id` and is not copied here, because a figure with two homes in one record is a figure that can disagree with itself. The hex shape is stated ONCE, in `$defs/digest`, and reached here through a `oneOf` with null — the shape commitment.schema.json uses for `revealed_at`.
attested_atAttestation_instantrequiredWhen the attester recorded this report. Ordering against the outcome's settlement is not expressible in JSON Schema and belongs to the verification pipeline, on the precedent container.schema.json set for `opens_at`.
Challenge
A dispute raised against a container's settlement — 03 §2 level 6's sixth and last leaf ('Participation, Outcome, Allocation, Contribution, Funding, Challenge'), never built until 04 W3-E13.
A dispute raised against a container's settlement — 03 §2 level 6's sixth and last leaf ('Participation, Outcome, Allocation, Contribution, Funding, Challenge'), never built until 04 W3-E13. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ChallengePageA page of challenges.
A dispute raised against a container's settlement — 03 §2 level 6's sixth and last leaf ('Participation, Outcome, Allocation, Contribution, Funding, Challenge'), never built until 04 W3-E13.
Parameters
idpath · requiredThe challenge id.
Responses
200ChallengeThe challenge.404
Challenge
A dispute raised against a container's settlement — 03 §2 level 6's sixth and last leaf ('Participation, Outcome, Allocation, Contribution, Funding, Challenge'), never built until 04 W3-E13.
idstringrequiredIdentity. NO PATTERN, on `container.schema.json`/`attestation.schema.json`'s shared precedent: no document fixes an id space for this class, and inventing one would freeze a byte ahead of its own gate.
container_idstringrequiredThe container this challenge is raised against — container-generic from the start (`03` §1.2's container level, ADR 0023), never a family-scoped id space. Deliberately NOT `wave_id`: `participation.schema.json`'s own inherited mismatch (a Wave-only id pattern at a container-generic entity) is a defect this schema, authored after the container level already existed, has no reason to repeat.
statusenumrequiredraised · upheld · dismissed`raised` — filed, undecided. `upheld` — the challenge stands; `03` §5.1's own reward-model line names exactly this state ('surviving void, an empty match set and an upheld challenge'), and it is what `apps/io`'s `provisional -> final` gate checks for (04 W3-E13 criterion 3). `dismissed` — the challenge does not stand; final is unaffected. A CLOSED enum, on `attestation.schema.json`'s own precedent for the identical reason: `03` §11's registry discipline is for the seven registry KINDS, and adding an eighth here would fail `tooling/ci/registry-artefact-check.mjs`'s seven-artefact rule for no corpus-named benefit — this is a small, closed, non-extensible outcome set, not a membership `03` §11 ever asks to keep open. This epic does not build the adjudication workflow that moves a Challenge from `raised` to `upheld`/`dismissed` — out of scope, `04` W3-E13's own acceptance criteria test only that an ALREADY-`upheld` challenge blocks `final`, never how one comes to be upheld. THE ONE LATER STATE, `remedied` (ADR 0071 §2.7, slice S20; `tooling/io/migrations/0062_draw_result_correction.sql`), IS NOT A VALUE THIS SCHEMA ADMITS ON WRITE: an upheld challenge of a draw becomes `remedied` only when its remedy has executed (for a result correction, only once the correction is published on `.net`), the storage layer refuses a challenge written as `remedied`, and only `remedied`, never `upheld`, stops blocking `final`. This schema describes a challenge as it is WRITTEN, so the enum stays closed over the three values a writer may choose.
reasonstring | nullThe challenger's stated grounds. Optional and nullable — no acceptance criterion of `04` W3-E13 requires a Challenge's own reason to be present (contrast `container.schema.json`'s forthcoming void-reason requirement, `03` §6.2, which is a DIFFERENT record — the container's own `void_reason` column, `tooling/io/migrations/0004_challenge_window.sql` — not this entity). Carried here anyway, matching every other leaf's own practice of recording why, because a Challenge with no stated ground is harder to adjudicate honestly, not because a numbered criterion requires it.
raised_atChallenge_instantrequiredWhen the challenge was filed. Ordering against the container's own `provisional_at` (when its challenge window began counting, `tooling/io/migrations/0004_challenge_window.sql`) is not expressible in JSON Schema and belongs to the write path, on `container.schema.json`'s own precedent for `opens_at`.
Commitment
What was pinned before a container opened, per container, discriminated on verification form.
What was pinned before a container opened, per container, discriminated on verification form. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200CommitmentPageA page of commitments.
What was pinned before a container opened, per container, discriminated on verification form.
Parameters
idpath · requiredThe commitment id.
Responses
200CommitmentThe commitment.404
Commitment
What was pinned before a container opened, per container, discriminated on verification form.
SealedCommitment
03 §4: the determining input is a secret committed before opening and revealed after. Carries the mechanism state 03 §1.2 moves out of Wave — the seed commitment, the revealed seed, the reveal time and the transcript. The trust statement is 03 §4's and lives there, not here. THE REVEAL IS ATOMIC: `seed_revealed` and `revealed_at` are null together or present together, which is the invariant mechanism.schema.json enforced before these members moved and which a move must not drop. A `revealed_at` with a null `seed_revealed` would record a reveal that revealed nothing, and a verifier replaying ALG(secret, params, inputs) — 03 §4's sealed action — would have a time and no secret.
idstringrequiredIdentity.
container_idstringrequiredThe container this commitment belongs to. 03 §1.2: a PER-CONTAINER Commitment.
formobjectrequiredpublished_atCommitment_instantrequiredWhen the commitment was published. Must be STRICTLY EARLIER than the container's `opens_at` (03 §1.3; 04 W3-E09 tests the equal-timestamp boundary). The comparison is not expressible in JSON Schema and is W3-E09's.
seed_commitmentCommitment_digestrequiredThe binding commitment published before the container opens. Never null: it is the thing being committed, and a sealed commitment without one commits nothing.
seed_revealedstring | nullrequiredLowercase hex of the revealed seed. NULL until the reveal, present after — never absent, per 03 §1.4.
revealed_atobjectrequiredWhen the seed was revealed. Null until then.
transcript_digestCommitment_nullableDigestrequiredDigest of the verifying transcript, once one exists. A DIGEST and not a URL: a Commitment is a proof artefact, and a URL commits to a location rather than to bytes.
ExternalCommitment
03 §4: the determining input is a fact published by an independent authority. THIS BRANCH IS DELIBERATELY MINIMAL. 04 W1-E07 owns the external-form record shapes and the rest of 03 §5.1's committed parameters — the observation window, the fallback rule (void | extend | substitute_none), the evidence digest algorithm and the observer set — alongside ResultSource and ResultObservation. What is fixed here is the one member W1-E07 acceptance 4 already names: the source is carried BY DIGEST REFERENCE and never inline.
idstringrequiredIdentity.
container_idstringrequiredThe container this commitment belongs to. 03 §1.2: a PER-CONTAINER Commitment.
formobjectrequiredpublished_atCommitment_instantrequiredWhen the commitment was published. 02 §7 requires the commitment to predate opening, and a third party confirms it via the anchor (03 §5.1).
result_source_digestCommitment_digestrequiredDigest of the committed ResultSource. 04 W1-E07 acceptance 4: the external branch accepts a digest reference and REJECTS an inline source — pinning the source by its bytes is what defeats source substitution (02 §7.1).
observer_set_digestCommitment_nullableDigestrequiredDigest of the committed observer set (03 §5.1's own list of parameters committed before opening names 'the observer set' alongside source authority, publication URL, field, format, revision policy, observation window, fallback rule and evidence digest algorithm) — the SAME digest-reference convention result_source_digest already uses on this branch, never an inline array. Computed as sha256_hex(canonical(observer_set sorted ascending)) — sorted because this is a SET of observers, not an ordered sequence, so two callers naming the identical set in a different order commit to the identical digest; this ordering rule is fixed by 04 W3-E10's own verifier (apps/io/src/observations/pipeline.ts), not by any corpus document. NULLABLE, NOT OPTIONAL, on `transcript_digest`'s own precedent above and 03 §1.4's own rule this file's test suite enforces mechanically (a Commitment branch may declare no optional member): this member was deferred at 04 W1-E07 (this branch's own description above: 'the rest of 03 §5.1's committed parameters ... alongside ResultSource and ResultObservation') and no external-form Commitment already on record before this fix carried one, so `null` is what every such Commitment reads back as, honestly, rather than omitting the member and inviting the absence 03 §1.4 forbids. 04 W3-E10's own capture pipeline is what actually depends on this value being genuinely committed rather than trusted off a request body (criterion 4's real guarantee, an adversarial-review fix), and enforces it as REQUIRED-NON-NULL at the one write path that matters — apps/io refuses to capture at all when a container's external Commitment carries a null observer_set_digest (E_OBSERVER_SET_NOT_COMMITTED), never silently falling back to an unverified caller-supplied array.
Container
A cohort with a freeze predicate.
A cohort with a freeze predicate. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ContainerPageA page of containers.
A cohort with a freeze predicate.
Parameters
idpath · requiredThe container id.
Responses
200ContainerThe container.404
Container
A cohort with a freeze predicate.
idstringrequiredIdentity. NO PATTERN: 03 §1.2 preserves Wave's own id space ('Wave keeps its name, its id space and its app destination'), which is `^[0-9]{3,6}$`, while Pool's is unfixed — so a shared pattern would either break the one the corpus preserves or invent the other.
product_idstringrequiredProvenance: the product this container belongs to. Opaque and NOT registry-resolved (record-envelope-v1.md §2, corrected 2026-08-05). The kill switch is specified at product_id granularity (03 §8.4), and 04 W3-E04 requires killing a product to prevent its containers reaching `open` — which is why the container must carry it.
opens_atContainer_instantrequiredThe start. A container is immutable after `opens_at` (03 §2 level 5), and its Commitment must be timestamped STRICTLY EARLIER (03 §1.3; 04 W3-E09 tests the equal-timestamp boundary).
closes_onobjectrequiredThe freeze predicate, as a DISCRIMINATED OBJECT and never a shape enum. 03 §1.3: 'A new enum member added after the first anchor invalidates every existing verifier's exhaustiveness check. A new keyed branch is purely additive — if and only if verifiers are required to fail closed on an unknown kind.' Two members ship and no third is named; a third (continuous participation) is 03 §9 item 5 and 04 §12, deliberately unscheduled. Both branches are closed, so a document mixing their parameters matches neither.
statusenumrequiredannounced · open · closed · observing · provisional · final · void · cancelledThe container's state. 03 §1.2 keeps a status in the shared container, so the member is REQUIRED — 03 §1.4 rules out an optional field in an anchored proof format. THE VALUE SET LANDS HERE, per ADR 0023 §5's own delegation ('The enum lands there, with the transitions, in one change'): the six main-sequence states 03 §5.1 names for the `official-result` family (announced, open, closed, observing, provisional, final), promoted to the CONTAINER level by 04 W3-E09 as shared vocabulary — `observing` is harmless for a non-`external` container, which simply never visits it — plus `void`/`cancelled`, the two exits that same section names. 04 W3-E09 owns the transition machine (`apps/io/src/lifecycle.ts`, `tooling/io/migrations/0002_containers.sql`) and its own dedicated table-driven test enumerates every ordered pair of the SIX main-sequence states; `void`/`cancelled` reachability is a separate, explicitly flagged, provisional design choice — see that epic's own report.
termsobjectrequiredA digest-bound snapshot of the product manifest, and THE ONLY PLACE a regulated fact may live (03 §1.2). Open on purpose: its members are the product's — the partition rule, the assistance binding, share origin, funded_by, the cause class — and several are blocked on counsel or on an owner decision. What is fixed today is `value_bearing`, plus `challenge_window` (04 W3-E13). Note that a `terms` carrying a value outside canonical-form-v1.md §2's domain has no canonical form, so its `terms_digest` cannot be computed; that is enforced by Rule D4's computation refusing, not by this schema, which is schema-blind to the distinction.
value_bearingbooleanrequiredTrue iff money moves through the container, regardless of who pays it in (03 §2). The estate's real gate boundary — per container, not per family — and the flag `standing` may not be declared against.
challenge_windowstringThe product's binding-5 resolution policy (`03` §3: 'challenge window, dispute route, void rule, and the maximum float duration'), snapshotted in ALONGSIDE `value_bearing` — the same 'digest-bound snapshot of the product manifest' the top-level description names, not a second mechanism. `03` §3.1: 'A declared challenge window. Settlement is provisional until it closes' — `apps/io`'s `provisional -> final` transition trigger (`tooling/io/migrations/0004_challenge_window.sql`, 04 W3-E13 criterion 2) reads exactly this member, cast to a real Postgres INTERVAL, and refuses to gate a container that lacks one rather than silently treating an absent window as `provisional -> final` remaining unconditional. NOT REQUIRED at this schema — deliberately: `04` W3-E09's own container fixtures (and every other epic's, across the monorepo) predate this member and construct `terms: {value_bearing: false}` alone; making it required here would retroactively invalidate every one of those, which is not this epic's `.io + contracts`-scoped job. The gate this member exists to serve is enforced at the point that actually needs it (the storage-layer trigger, at the moment `final` is attempted), not by widening this schema's own `required` list estate-wide. ISO 8601 DURATION, matching `packages/product-registry/src/manifest.ts`'s `ResolutionPolicyInput.challenge_window` (04 W3-E03's own pre-existing, previously-unenforced fixture convention — `P7D`, `P30D`, `P90D` already appear in that package's own test fixtures) — SAME PATTERN TEXT as `packages/product-registry/src/duration.ts`'s `ISO8601_DURATION_PATTERN`, cross-referenced rather than silently re-derived, so the two do not drift into accepting different strings for the identical concept. A known, flagged simplification: this pattern does not enforce ISO 8601's rule that a week designator (`W`) may not combine with `Y`/`M`/`D` in the same duration — every fixture and every real product declares day-only durations (`P7D`), so the simplification costs nothing today and is recorded here rather than silently assumed correct for every future value.
selection_offerobjectWHAT A PARTICIPANT MAY CHOOSE FROM — added on `challenge_window`'s own precedent (a field `terms` grows over time, NOT REQUIRED so every existing container's own frozen `terms`/`terms_digest` stays valid). Closes the real, previously-documented product-model gap `apps/app/src/lib/catalog.ts`'s own header named: 'apps/io's real container.schema.json carries... NO selection kind, no min/max/step/band-options/date-bounds' — this member is that data, real rather than fabricated, so `apps/app`'s wizard can render actual bounds instead of an unbounded numeric guess. Discriminated on `kind`, the SAME four members `packages/contracts/src/schemas/selection.schema.json`'s `Selection` ships (`range`/`band`/`date`/`number_set`) — an offer and a selection are two ends of the identical vocabulary: this is what a container OFFERS, `Selection` is what a participant CHOSE from it, and, for the first three, `PredictionSelection`'s own three-way union (`apps/app/src/lib/predictions.ts`, this repository's own already-approved `06` UX design) is the fixture precedent this real field promotes. A future kind is a new, additive branch on both schemas together, never a redesign of an existing one. `min`/`max`/`step` reuse this file's own `quantity` $def for the identical Rule N3/N4 reason `target` does immediately above: `terms` is digested whole for `terms_digest`, so a fractional bound (`predictions.ts`'s own worked example: 'guess the mean temperature to the nearest half-degree') must be a Rule-N4 decimal string, never a raw float.
terms_digeststringrequiredcanonical-form-v1.md Rule D4: SHA-256(utf8(canonicalForm(terms))) over the `terms` object ALONE — no wrapper, no key added, no reference to the product manifest included — rendered per Rule D3 as lowercase unprefixed hexadecimal. The partition rule and the assistance binding are bound BY INCLUSION, as members of `terms`, so neither needs a separate digest.
commitment_idstringrequiredThe per-container Commitment (03 §1.2) — where the mechanism state that left Wave now lives, `oneOf` on verification form. Built by 04 W1-E06; this is the reference, not the object.
ContainerClassTotal
A container's open-record total for one obligation class — the shape `04` W4-E10's own design artefact (docs/ops/foundation-principle-reporting-dimension.md:82-93) specifies for `03` §7.3 rule 2's first half: 'Per-container class totals are open-record entries.' ADR 0015 §6 states the same rule in its own words: 'Per-container class totals are Open Record entries.
A container's open-record total for one obligation class — the shape `04` W4-E10's own design artefact (docs/ops/foundation-principle-reporting-dimension.md:82-93) specifies for `03` §7.3 rule 2's first half: 'Per-container class totals are open-record entries.' ADR 0015 §6 states the same rule in its own words: 'Per-container class totals are Open Record entries. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ContainerClassTotalPageA page of containerclasstotals.
A container's open-record total for one obligation class — the shape `04` W4-E10's own design artefact (docs/ops/foundation-principle-reporting-dimension.md:82-93) specifies for `03` §7.3 rule 2's first half: 'Per-container class totals are open-record entries.' ADR 0015 §6 states the same rule in its own words: 'Per-container class totals are Open Record entries.
Parameters
idpath · requiredThe containerclasstotal id.
Responses
200ContainerClassTotalThe containerclasstotal.404
ContainerClassTotal
A container's open-record total for one obligation class — the shape `04` W4-E10's own design artefact (docs/ops/foundation-principle-reporting-dimension.md:82-93) specifies for `03` §7.3 rule 2's first half: 'Per-container class totals are open-record entries.' ADR 0015 §6 states the same rule in its own words: 'Per-container class totals are Open Record entries.
container_idstringrequiredThe container this total is computed over. NO PATTERN, on container.schema.json's and funding.schema.json's precedent: no document fixes an id space for a container reference here. NON-EMPTY: an empty string is not an identity, and a total naming no container belongs to no container's report.
class_idstringrequiredOne of ADR 0015 §4's seven segregation domains, or a policy-extensible obligation class mapping onto one — the design doc's own wording (docs/ops/foundation-principle-reporting-dimension.md:89). NO ENUM, deliberately: the design doc's own description already states the set is policy-extensible, and `03` §11's registry-resolution discipline is reserved for the SEVEN registry kinds — an enum here would freeze a membership the design doc itself declares open. NON-EMPTY, on the same reasoning as `container_id`.
total_amountContainerClassTotal_nonNegativeAmountrequiredThe container's total for this class, in the container's declared unit (paired with `currency` below, the way `03` §1.3 pairs a Funding `amount` with a Container's declared unit). Decimal string, per canonical-form-v1.md Rule N4 — never a float (docs/ops/foundation-principle-reporting-dimension.md:90).
currencystringrequiredISO-4217 alphabetic code, or a supported crypto ticker — the identical spelling contribution.schema.json's `amount.currency` uses (`^[A-Z]{3,4}$`), reused rather than reinvented so one pattern governs one meaning across the corpus. The supported crypto set is defined at the application layer (`@veraq/i18n` `CRYPTO`); other pattern-valid codes are not rejected here.
DrawArchive
ADR 0063 §2.1's `draw_archive_v1` entry_kind payload -- the complete draw-verification tuple (ADR 0062's sibling design for randomness, `10` §4.3.3): beacon round, signature, public key, cohort root and known-answer tests for the derivation code, sealed so a draw is re-verifiable decades later with no live service.
ADR 0063 §2.1's `draw_archive_v1` entry_kind payload -- the complete draw-verification tuple (ADR 0062's sibling design for randomness, `10` §4.3.3): beacon round, signature, public key, cohort root and known-answer tests for the derivation code, sealed so a draw is re-verifiable decades later with no live service. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200DrawArchivePageA page of drawarchives.
ADR 0063 §2.1's `draw_archive_v1` entry_kind payload -- the complete draw-verification tuple (ADR 0062's sibling design for randomness, `10` §4.3.3): beacon round, signature, public key, cohort root and known-answer tests for the derivation code, sealed so a draw is re-verifiable decades later with no live service.
Parameters
idpath · requiredThe drawarchive id.
Responses
200DrawArchiveThe drawarchive.404
DrawArchive
ADR 0063 §2.1's `draw_archive_v1` entry_kind payload -- the complete draw-verification tuple (ADR 0062's sibling design for randomness, `10` §4.3.3): beacon round, signature, public key, cohort root and known-answer tests for the derivation code, sealed so a draw is re-verifiable decades later with no live service.
container_idstringrequiredThe container this draw resolves.
spec_digestDrawArchive_drawArchiveDigestrequiredDigest of the mechanism spec this draw was performed under.
cohort_rootDrawArchive_drawArchiveDigestrequiredThe container's frozen `ticket_batch_v1` cohort root the draw is bound against -- `IRandomnessSource.requestRandomness`'s `commitment` argument is computed from this same value, so a round cannot be pinned before the cohort it determines is itself frozen.
beacon_roundintegerrequiredThe drand `quicknet` (or `evmnet`/BN254 fallback) round number consumed -- strictly after the round `IRandomnessSource.requestRandomness`'s `notBeforeRound` pinned, per that interface's `RoundTooEarly` guard.
beacon_signatureDrawArchive_hexBytesrequiredThe beacon round's own BLS12-381 (drand `quicknet`) or BN254 (`evmnet` fallback) signature, exactly as submitted to `IRandomnessSource.fulfil`.
beacon_public_keyDrawArchive_hexBytesrequiredThe beacon's public key the signature verifies against -- recorded alongside the signature (rather than assumed from a hardcoded constant) so a verifier decades from now can confirm which key was actually used, even if Veraq's own registry of known beacon keys has since changed.
derivation_katsarray<object>requiredKnown-answer test vectors for the seed-derivation code (`seed = H(dom || round || sha256(signature) || commitment)`, foundation report §4.3.3 step 5) -- fixed input/output pairs sealed alongside the draw so the derivation itself, not just this draw's own output, stays independently re-verifiable without trusting a live Veraq service.
DrawResultCorrectionEntry
ADR 0071 §2.7's remedy ground (b), slice S20 (B-215): the `draw_result_correction_v1` entry_kind payload -- the CORRECTION of a published `draw_result_v1` that does not recompute from the pinned inputs.
ADR 0071 §2.7's remedy ground (b), slice S20 (B-215): the `draw_result_correction_v1` entry_kind payload -- the CORRECTION of a published `draw_result_v1` that does not recompute from the pinned inputs. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200DrawResultCorrectionEntryPageA page of drawresultcorrectionentries.
ADR 0071 §2.7's remedy ground (b), slice S20 (B-215): the `draw_result_correction_v1` entry_kind payload -- the CORRECTION of a published `draw_result_v1` that does not recompute from the pinned inputs.
Parameters
idpath · requiredThe drawresultcorrectionentry id.
Responses
200DrawResultCorrectionEntryThe drawresultcorrectionentry.404
DrawResultCorrectionEntry
ADR 0071 §2.7's remedy ground (b), slice S20 (B-215): the `draw_result_correction_v1` entry_kind payload -- the CORRECTION of a published `draw_result_v1` that does not recompute from the pinned inputs.
container_idstringrequiredThe container (draw) this result is for.
draw_archive_digestDrawResultCorrectionEntry_drawResultDigestrequiredThe digest of the container's `draw_archive_v1` payload: the result is the one the archive determines.
winning_selectionobjectrequiredThe winning numbers per pool id, as the archive's derivation determines them.
tiersarray<DrawResultCorrectionEntry_drawResultTier>requiredOne row per award tier of the container's award structure, in the structure's order.
pool_total_minorDrawResultCorrectionEntry_drawResultMinorrequiredThe pool of exactly the issued, not-returned orders.
beacon_roundintegerrequiredThe drand round R the draw consumed, as its `draw_archive_v1` records it (fixed at mint, before any sale, by the SealedCommitment). With `container_id` (bytewise) it is the draw's place in its product's carry chain.
previous_container_idstring | nullrequiredThe draw immediately before this one in its product's carry chain, whose `carry_out_minor + breakage_minor` is this draw's `carry_in_minor` (zero when it left nothing), or null when no draw of the product takes part before this one. Never the draw itself.
carry_in_minorDrawResultCorrectionEntry_drawResultMinorrequiredCarried into this draw: exactly what the draw named by `previous_container_id` left (its `carry_out_minor + breakage_minor`), or '0' when that is null.
carry_out_minorDrawResultCorrectionEntry_drawResultMinorrequiredThe unwon amount, routed `carry_forward`, that MOVES out of this draw's pool into the carry of its product (together with `breakage_minor`) for the next draw of its product's carry chain.
breakage_minorDrawResultCorrectionEntry_drawResultMinorrequiredThe rounding remainder no line can be credited. It is carried forward with `carry_out_minor`: both leave this draw's pool for the next draw of its product's carry chain.
line_countintegerrequiredThe number of lines of the bound cohort: the SIZE of the `awards_root` tree (one leaf per line). A proof is valid only at this tree size.
ledger_currencystringrequiredThe ledger currency every amount in this payload is in.
awards_rootDrawResultCorrectionEntry_drawResultDigestrequiredThe Merkle root over every line's `(ticket_digest, line_no, tier_id, amount_minor)`, by the rule in this schema's own description.
supersedesstringrequiredThe digest of the `.net` entry this correction supersedes: the container's `draw_result_v1`, or the latest correction of it. Lowercase hexadecimal, unprefixed, as `.net`'s `entryDigest`.
challenge_refstringrequiredThe remedied challenge's reference: 256 random bits (lowercase hexadecimal) minted by the publisher's CSPRNG when the remedy is approved and stored with that approval. It is NOT a function of the challenge id or of anything an operator or a participant chose, so no one who knows an id can recompute it and no reference can be linked to an id. Opaque and non-identifying; at most one correction per reference.
DrawResultEntry
ADR 0071 §2.4's `draw_result_v1` entry_kind payload -- the AGGREGATE tier result of one number-match draw, and the root over EVERY line's award, so the result and each line's award are provable from public evidence.
ADR 0071 §2.4's `draw_result_v1` entry_kind payload -- the AGGREGATE tier result of one number-match draw, and the root over EVERY line's award, so the result and each line's award are provable from public evidence. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200DrawResultEntryPageA page of drawresultentries.
ADR 0071 §2.4's `draw_result_v1` entry_kind payload -- the AGGREGATE tier result of one number-match draw, and the root over EVERY line's award, so the result and each line's award are provable from public evidence.
Parameters
idpath · requiredThe drawresultentry id.
Responses
200DrawResultEntryThe drawresultentry.404
DrawResultEntry
ADR 0071 §2.4's `draw_result_v1` entry_kind payload -- the AGGREGATE tier result of one number-match draw, and the root over EVERY line's award, so the result and each line's award are provable from public evidence.
container_idstringrequiredThe container (draw) this result is for.
draw_archive_digestDrawResultEntry_drawResultDigestrequiredThe digest of the container's `draw_archive_v1` payload: the result is the one the archive determines.
winning_selectionobjectrequiredThe winning numbers per pool id, as the archive's derivation determines them.
tiersarray<DrawResultEntry_drawResultTier>requiredOne row per award tier of the container's award structure, in the structure's order.
pool_total_minorDrawResultEntry_drawResultMinorrequiredThe pool of exactly the issued, not-returned orders.
beacon_roundintegerrequiredThe drand round R the draw consumed, as its `draw_archive_v1` records it (fixed at mint, before any sale, by the SealedCommitment). With `container_id` (bytewise) it is the draw's place in its product's carry chain.
previous_container_idstring | nullrequiredThe draw immediately before this one in its product's carry chain, whose `carry_out_minor + breakage_minor` is this draw's `carry_in_minor` (zero when it left nothing), or null when no draw of the product takes part before this one. Never the draw itself.
carry_in_minorDrawResultEntry_drawResultMinorrequiredCarried into this draw: exactly what the draw named by `previous_container_id` left (its `carry_out_minor + breakage_minor`), or '0' when that is null.
carry_out_minorDrawResultEntry_drawResultMinorrequiredThe unwon amount, routed `carry_forward`, that MOVES out of this draw's pool into the carry of its product (together with `breakage_minor`) for the next draw of its product's carry chain.
breakage_minorDrawResultEntry_drawResultMinorrequiredThe rounding remainder no line can be credited. It is carried forward with `carry_out_minor`: both leave this draw's pool for the next draw of its product's carry chain.
line_countintegerrequiredThe number of lines of the bound cohort: the SIZE of the `awards_root` tree (one leaf per line). A proof is valid only at this tree size.
ledger_currencystringrequiredThe ledger currency every amount in this payload is in.
awards_rootDrawResultEntry_drawResultDigestrequiredThe Merkle root over every line's `(ticket_digest, line_no, tier_id, amount_minor)`, by the rule in this schema's own description.
DrawVoidEntry
D-PRV-79 (PROVISIONAL): the `draw_void_v1` entry_kind payload -- the record that a BOUND number-match draw was voided BEFORE its commit line `time(R) - margin_seconds`, so it left its product's carry chain in time.
D-PRV-79 (PROVISIONAL): the `draw_void_v1` entry_kind payload -- the record that a BOUND number-match draw was voided BEFORE its commit line `time(R) - margin_seconds`, so it left its product's carry chain in time. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200DrawVoidEntryPageA page of drawvoidentries.
D-PRV-79 (PROVISIONAL): the `draw_void_v1` entry_kind payload -- the record that a BOUND number-match draw was voided BEFORE its commit line `time(R) - margin_seconds`, so it left its product's carry chain in time.
Parameters
idpath · requiredThe drawvoidentry id.
Responses
200DrawVoidEntryThe drawvoidentry.404
DrawVoidEntry
D-PRV-79 (PROVISIONAL): the `draw_void_v1` entry_kind payload -- the record that a BOUND number-match draw was voided BEFORE its commit line `time(R) - margin_seconds`, so it left its product's carry chain in time.
container_idstringrequiredThe voided draw (container).
commit_line_atDrawVoidEntry_drawVoidInstantrequiredThe draw's commit line `time(R) - margin_seconds`, as io stores it (`draw_bindings.commit_line`): io's statement, held by `.net` to be strictly after this entry's `.net`-attested `recorded_at`, and recomputed from the committed terms by a verifier rather than trusted.
Fund
A long-lived economic, governance and accounting boundary anchored to a jurisdiction — ADR 0028 Decision 1, answering `01` §8 Q14 ('What is a Fund?'), OPEN from ADR 0013 (2026-08-02) until ADR 0028 (2026-08-11).
A long-lived economic, governance and accounting boundary anchored to a jurisdiction — ADR 0028 Decision 1, answering `01` §8 Q14 ('What is a Fund?'), OPEN from ADR 0013 (2026-08-02) until ADR 0028 (2026-08-11). Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200FundPageA page of funds.
A long-lived economic, governance and accounting boundary anchored to a jurisdiction — ADR 0028 Decision 1, answering `01` §8 Q14 ('What is a Fund?'), OPEN from ADR 0013 (2026-08-02) until ADR 0028 (2026-08-11).
Parameters
idpath · requiredThe fund id.
Responses
200FundThe fund.404
Fund
A long-lived economic, governance and accounting boundary anchored to a jurisdiction — ADR 0028 Decision 1, answering `01` §8 Q14 ('What is a Fund?'), OPEN from ADR 0013 (2026-08-02) until ADR 0028 (2026-08-11).
idstringrequiredIdentity. NO PATTERN: ADR 0028's Consequences say a Fund is 'keyed by its own id (e.g. a ULID)' — an illustrative example, not a mandate, exactly as funding.schema.json's own `id` reasons: 'no document fixes an id space for this leaf, and inventing one would freeze a byte before its gate.' NON-EMPTY: an empty string is not an identity, and a Fund naming nothing would validate while referring to no object.
source_jurisdictionstringrequiredISO 3166-1 alpha-2 — the one shape the corpus already fixes for a jurisdiction value: `04`:236 tests `01` §8 Q1 against '≥1 market by ISO 3166-1 alpha-2'. ADR 0013 Decision 1: 'Fund becomes a first-class Core entity carrying source_jurisdiction. Every inflow inherits its classification from the Fund it lands in.' `G-jurisdictions` — 'the named target market set' — is OPEN today; no repository names one. This field fixes SHAPE only, never a real value: every fixture in this corpus uses an ISO 3166-1 user-assigned code (e.g. `ZZ`), reserved by the standard for exactly this — a value that validates without naming a target market this schema-authoring epic is not authorised to name. DUAL ROLE, per ADR 0031 Decision 3 (answering `G-FD6`, 2026-08-11): this field satisfies ADR 0031's requirement that `Fund` 'gain a jurisdiction-linked, computed-allocation-input field at v1' — it is not only a reported dimension (`04` W4-E10's own scope) but also the computed *input* Decision 1 activates for how a `ReserveObligation`'s disposition is allocated. No SECOND field is added for this: `source_jurisdiction` already carries the one fact both roles need, and duplicating it would put one piece of knowledge in two places (the same reasoning `source_fund_id`'s own description gives for not restating `Fund`'s fields elsewhere). ADR 0031's own Consequences are explicit that this is 'a decision, not an implementation' — no allocation-rule code exists yet, and none is authorised by this field's presence.
creation_tierenumrequireddefault · additionalWhich of ADR 0028 Decision 7's two creation tracks this Fund was created on. `default`: 'A jurisdiction's first Fund is created by the operator, once, at jurisdiction onboarding.' `additional`: 'Any additional Fund in an already-served jurisdiction requires an owner-recorded governance reason before it may be created... following an admission discipline analogous to 03 §11's before-code gate.' A Fund is never created by a container, a product, or a participant action (Decision 7's own closing sentence). CLOSED to these two, because Decision 7 names exactly two tracks and no document names a third.
governance_reason_digeststring | nullrequiredThe recorded governance reason for an `additional` Fund, by digest reference — a SHA-256 digest in canonical-form-v1.md Rule D3's rendering (the spelling commitment.schema.json and attestation.schema.json both use for the same kind of value), or NULL for a `default` Fund, because Decision 7 gives the jurisdiction's first Fund no reason to record (it coincides with jurisdiction onboarding, an operational event ADR 0013 already assumes) — PRESENT for an `additional` Fund, whose creation 'requires an owner-recorded governance reason BEFORE it may be created.' Present-but-null rather than absent, on record-envelope-v1.md's and attestation.schema.json's shared convention: 03 §1.4 rules out an optional field in an anchored proof format, so a verifier reads a present null instead of guessing at an absence. The pairing is enforced structurally by this schema's top-level `if`/`then`/`else`, on attestation.schema.json's own precedent for its `pending`/`observed_digest` pairing — never left to review. `pattern` applies only where `type` resolves to `string`, per JSON Schema's own per-keyword type scoping, so it constrains the digest form without rejecting `null`.
Funding
One inflow recorded against a container — a level-6 record entity (03 §2), and the moving input a threshold container's freeze predicate is read against.
One inflow recorded against a container — a level-6 record entity (03 §2), and the moving input a threshold container's freeze predicate is read against. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200FundingPageA page of fundings.
One inflow recorded against a container — a level-6 record entity (03 §2), and the moving input a threshold container's freeze predicate is read against.
Parameters
idpath · requiredThe funding id.
Responses
200FundingThe funding.404
Funding
One inflow recorded against a container — a level-6 record entity (03 §2), and the moving input a threshold container's freeze predicate is read against.
idstringrequiredIdentity. NO PATTERN, on container.schema.json's precedent: no document fixes an id space for this leaf, and inventing one would freeze a byte before its gate. NON-EMPTY: an empty string is not an identity, and a leaf naming nothing would validate while referring to no object. `minLength: 1` is strictly weaker than any pattern, so it freezes no id space — it only refuses the one value that can never be one.
container_idstringrequiredThe container this inflow is recorded against, and therefore the container whose `raised` it projects into. REQUIRED: 03 §1.3 makes the projection per-container, and an entry that names no container belongs to no projection and can be counted into any of them. NO PATTERN — container.schema.json carries none, because 03 §1.2 preserves Wave's id space while a Pool's is unfixed. NON-EMPTY: an empty string is not an identity, and a leaf naming nothing would validate while referring to no object. `minLength: 1` is strictly weaker than any pattern, so it freezes no id space — it only refuses the one value that can never be one.
amountFunding_positiveQuantityrequiredThe amount, in the CONTAINER'S DECLARED UNIT — the same unit as that container's `closes_on.target` (03 §1.3: 'a quantity in the container's declared unit'). No currency member, deliberately: the unit is declared once, by the container, and a per-entry currency would be a second place to say one thing AND would drag in contribution.schema.json's `^[A-Z]{3,4}$`, which is 01 §4.3 change 4 and blocked by G-Q5.
funded_atFunding_instantrequiredWhen the inflow was recorded. The threshold predicate reads the entries whose `funded_at` falls inside the container's window; that ordering is not expressible in JSON Schema and is 04 W3-E09's, on the precedent container.schema.json set for `opens_at`.
JurisdictionBalanceCommitment
Control-ledger only, per `03` §7.3 rule 2's second half and ADR 0015 §6, same rule — 'Per-jurisdiction balances remain control-ledger, anchored as digests only.' The shape `04` W4-E10's own design artefact specifies (docs/ops/foundation-principle-reporting-dimension.md:94-104).
Control-ledger only, per `03` §7.3 rule 2's second half and ADR 0015 §6, same rule — 'Per-jurisdiction balances remain control-ledger, anchored as digests only.' The shape `04` W4-E10's own design artefact specifies (docs/ops/foundation-principle-reporting-dimension.md:94-104). Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200JurisdictionBalanceCommitmentPageA page of jurisdictionbalancecommitments.
Control-ledger only, per `03` §7.3 rule 2's second half and ADR 0015 §6, same rule — 'Per-jurisdiction balances remain control-ledger, anchored as digests only.' The shape `04` W4-E10's own design artefact specifies (docs/ops/foundation-principle-reporting-dimension.md:94-104).
Parameters
idpath · requiredThe jurisdictionbalancecommitment id.
Responses
200JurisdictionBalanceCommitmentThe jurisdictionbalancecommitment.404
JurisdictionBalanceCommitment
Control-ledger only, per `03` §7.3 rule 2's second half and ADR 0015 §6, same rule — 'Per-jurisdiction balances remain control-ledger, anchored as digests only.' The shape `04` W4-E10's own design artefact specifies (docs/ops/foundation-principle-reporting-dimension.md:94-104).
container_idstringrequiredThe container whose per-jurisdiction breakdown this digest commits to. NO PATTERN, NON-EMPTY, on `container-class-total.schema.json`'s precedent — the same container a `ContainerClassTotal` for the same `class_id` totals without a jurisdiction breakdown.
class_idstringrequiredThe obligation class this per-jurisdiction breakdown belongs to — the same open, policy-extensible set `container-class-total.schema.json`'s `class_id` names (ADR 0015 §4's seven segregation domains, or a policy-extensible mapping onto one). NO ENUM, on the same reasoning: the membership is not this schema's to freeze.
jurisdiction_balances_digestJurisdictionBalanceCommitment_digestrequiredSHA-256 hex digest over the per-jurisdiction breakdown, per canonical-form-v1.md Rule D2's computation and Rule D3's rendering (docs/ops/foundation-principle-reporting-dimension.md:102). The breakdown itself stays control-ledger — THIS FIELD IS THE ONLY MEMBER of this schema that carries jurisdiction-linked information, and it carries it as an opaque committed digest, never as a raw jurisdiction value, a balance keyed by jurisdiction, or any structure a reader could invert into one. `additionalProperties: false` plus this `required` list is what makes 'anchored as digests only' (ADR 0015 §6) a fact this schema cannot violate, rather than a sentence a future author could work around by adding a member.
OutcomeCertificate
ADR 0063 §2.1's `outcome_certificate_v1` entry_kind payload -- the VOA protocol's settleable artefact (ADR 0062 'Veraq Outcome Attestation'), sealed into the open record once finalised.
ADR 0063 §2.1's `outcome_certificate_v1` entry_kind payload -- the VOA protocol's settleable artefact (ADR 0062 'Veraq Outcome Attestation'), sealed into the open record once finalised. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200OutcomeCertificatePageA page of outcomecertificates.
ADR 0063 §2.1's `outcome_certificate_v1` entry_kind payload -- the VOA protocol's settleable artefact (ADR 0062 'Veraq Outcome Attestation'), sealed into the open record once finalised.
Parameters
idpath · requiredThe outcomecertificate id.
Responses
200OutcomeCertificateThe outcomecertificate.404
OutcomeCertificate
ADR 0063 §2.1's `outcome_certificate_v1` entry_kind payload -- the VOA protocol's settleable artefact (ADR 0062 'Veraq Outcome Attestation'), sealed into the open record once finalised.
cert_idOutcomeCertificate_digestrequiredA digest of `(spec_digest, container_id, slot)` -- ADR 0062 §2.1. `slot` disambiguates a container with more than one determining instant (e.g. a recurring draw series); a container with exactly one determination uses a fixed sentinel slot, so `cert_id` stays deterministic and collision-free across both cases.
formenumrequiredsealed · external · judged · countedWhich of `apps/io`'s four verification forms this certificate attests -- resolves against the `verification_form` kernel registry (`packages/kernel/registries/verification-forms.v1.json`), fail-closed on an unregistered value, per this estate's standard registry discipline.
spec_digestOutcomeCertificate_digestrequiredDigest of the `OutcomeSpec` this certificate resolves under (ADR 0062 §2.1), registered into `IMechanismRegistry` before the container's `opens_at`.
container_idstringrequiredThe container this certificate settles.
cohort_rootOutcomeCertificate_digestrequiredThe container's own frozen `ticket_batch_v1` cohort root (ADR 0062 §2.1's naming resolution: `cohort_root` and the source report's `cohort_digest` are the SAME value; this field name is used exclusively). A certificate attests an outcome AGAINST this exact frozen participation set.
sourcestringrequiredThe authority id this certificate's `OutcomeSpec` names (ADR 0062 §2.1's `OutcomeSpec.authority id`) -- e.g. the publisher whose statistic or determination is being attested. Free-text identifier resolved by the spec, not by this schema.
observationobjectrequiredvaluestringrequiredThe extracted value, as canonical-form text (ADR 0062 §2.1's `OutcomeSpec` value selector/canonicalisation rule fixes how this was derived; this field carries the result, not the derivation).
unitstringrequiredThe value's unit, or an empty string for a dimensionless/enumerated outcome.
as_ofOutcomeCertificate_instantrequiredThe authority's own as-of time for the observed value, per the spec's `as_of` rule.
etagstring | nullrequiredThe source response's ETag header, if any -- ADR 0062 §2.1's fetch-policy header capture. Null, never absent, when the source sent none.
last_modifiedstring | nullrequiredThe source response's Last-Modified header, if any.
http_statusintegerrequiredThe source response's HTTP status code at capture time.
evidencearray<OutcomeCertificate_evidenceCore>requiredOne entry per observer's capture (ADR 0062 §2.1's commit/reveal-then-agree flow) -- `n` entries for an `n`-observer determination; `single_party` VOA v1 (ADR 0062 §3) carries exactly one.
observersarray<string>requiredThe observer identities that produced `evidence`, in the same order. VOA v1 is `single_party` (ADR 0062 §3): exactly one operator-run process, not yet registered independent parties with bonds.
policyobjectrequirednintegerrequiredThe observer committee size this certificate was resolved under.
tintegerrequiredThe agreement threshold -- ADR 0062 §2.1: t >= floor(n/2)+1, t >= 2, n odd, once n > 1.
agreement_ruleobjectrequiredADR 0062 §2.1: fixed at exact match, never a median -- 'medians are for prices, not for facts'.
fallback_usedenumrequiredvoid · extend · substitute_none · Which of the spec's `fallback` branches was invoked, or null if agreement succeeded on the first attempt with no fallback needed.
observer_independence_disclosedstringrequiredA plain-language disclosure of the observer set's actual independence at issue time (ADR 0062 §3's honesty requirement) -- e.g. 'single_party: one operator-run process' for VOA v1, or a description of distinct legal entities / ASNs / fetch-client implementations once independent observers exist (ADR 0062 §2.1's diversity checks).
statusenumrequiredprovisional · finalADR 0062 §2.1's message flow: a certificate is issued `provisional`, then either becomes `final` after its challenge window closes with no upheld challenge, or is superseded by a wholly NEW certificate (`revision.supersedes`) -- a settled certificate is never edited in place, so there is no third 'corrected' status on this same `cert_id`.
timesobjectrequiredanchored_atOutcomeCertificate_instantrequiredWhen the evidence batch digest was anchored to the open record and Bitcoin -- ADR 0062 §2.1's `ANCHOR_EVIDENCE` step, which happens BEFORE the extracted value is published.
issued_atOutcomeCertificate_instantrequiredWhen this certificate was issued (provisional).
challenge_window_closes_atOutcomeCertificate_instantrequiredThe end of the bonded challenge window (ADR 0062 §2.1) -- `finalized_at` is null before this instant.
finalized_atobjectrequiredWhen `status` became `final`. Null while `status` is `provisional` -- never absent, per `03` §1.4's no-optional-field rule.
revisionobjectrequiredauthority_statusenumrequiredprovisional · final · unknownThe EXTERNAL authority's own publication status for the observed value at the time of observation (ADR 0062 §2.1) -- distinct from this certificate's own `status` field above, which tracks VOA's own challenge-window lifecycle, not the authority's.
supersedesOutcomeCertificate_digestrequiredThe `cert_id` this certificate replaces, or the all-zero digest (64 '0' hex characters) if this certificate supersedes nothing -- ADR 0062 §2.1's `CORRECT` step issues a NEW certificate carrying this reference, never an edit to a settled one. A genuine zero value on the same 'chain-sentinel, not JSON null' convention `ticket_batch_v1.prev_cohort_root` uses, chosen here (rather than a nullable digest) because `supersedes` is compared on-chain in a future relay path exactly the way `prevCohortRoot` is, where only a concrete bytes32 sentinel, not a JSON null, is representable.
trust_statementstringrequiredADR 0062 §2.2's mandatory plain-language disclosure: what this certificate honestly does and does not claim (a committed, evidenced, threshold-signed attestation with disclosed provenance -- never a cryptographic proof of truth or a consensus guarantee).
signaturesarray<object>requiredThe certificate signer set's threshold signatures over this certificate's content digest (`0x03` domain, `packages/kernel/src/domain-digests.ts`'s `certDigest`) -- Phase 0's reference signer carries 3 test keys (ADR 0063 §3), not the production n>=5 set (ADR 0065 §2.2). The on-chain `IOutcomeVerifier.verifyOutcome` relay path encodes each signer's membership proof against the epoch's Merkle `setRoot` separately; this off-chain record carries the raw signer/signature pairs the relay is built from.
ParticipationPartitionReport
Per participation, per `03` §7.3 rule 3 and ADR 0015 §6, same rule — 'Per participation, only `partition_rule_digest` is published, openable by the holder — because publishing the applied `(product, jurisdiction)` pair would publish the participant's jurisdiction.' The shape `04` W4-E10's own design artefact specifies (docs/ops/foundation-principle-reporting-dimension.md:105-114).
Per participation, per `03` §7.3 rule 3 and ADR 0015 §6, same rule — 'Per participation, only `partition_rule_digest` is published, openable by the holder — because publishing the applied `(product, jurisdiction)` pair would publish the participant's jurisdiction.' The shape `04` W4-E10's own design artefact specifies (docs/ops/foundation-principle-reporting-dimension.md:105-114). Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ParticipationPartitionReportPageA page of participationpartitionreports.
Per participation, per `03` §7.3 rule 3 and ADR 0015 §6, same rule — 'Per participation, only `partition_rule_digest` is published, openable by the holder — because publishing the applied `(product, jurisdiction)` pair would publish the participant's jurisdiction.' The shape `04` W4-E10's own design artefact specifies (docs/ops/foundation-principle-reporting-dimension.md:105-114).
Parameters
idpath · requiredThe participationpartitionreport id.
Responses
200ParticipationPartitionReportThe participationpartitionreport.404
ParticipationPartitionReport
Per participation, per `03` §7.3 rule 3 and ADR 0015 §6, same rule — 'Per participation, only `partition_rule_digest` is published, openable by the holder — because publishing the applied `(product, jurisdiction)` pair would publish the participant's jurisdiction.' The shape `04` W4-E10's own design artefact specifies (docs/ops/foundation-principle-reporting-dimension.md:105-114).
participation_idstringrequiredThe participation this partition-rule digest is published for. NO PATTERN — participation.schema.json's own `id` carries none either. NON-EMPTY: an empty string is not an identity, and a report naming no participation belongs to no participation's report. NOT a `participant_id`: `03` §7.3 rule 3 makes jurisdiction-linked reporting a property of the PARTICIPATION, never of the PARTICIPANT — see this schema's own top-level description.
partition_rule_digestParticipationPartitionReport_digestrequiredThe digest of the published, versioned partition rule applied to this participation (ADR 0015 §6: 'a required member of the Product manifest… digest-bound into `Container.terms_digest`'), openable by the holder. THIS IS THE ONLY MEMBER of this schema — the applied `(product, jurisdiction)` pair is never published beside it, because doing so would publish the participant's jurisdiction (`03` §7.3 rule 3, quoted verbatim in this schema's top-level description). `additionalProperties: false` plus a two-member `required` list is what makes that non-publication a fact this schema cannot violate, rather than a sentence a future author could work around by adding a member.
PayoutRail
A discriminated payout-rail taxonomy.
A discriminated payout-rail taxonomy. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200PayoutRailPageA page of payoutrails.
A discriminated payout-rail taxonomy.
Parameters
idpath · requiredThe payoutrail id.
Responses
200PayoutRailThe payoutrail.404
PayoutRail
A discriminated payout-rail taxonomy.
BankIbanRail
kindobjectrequiredibanstringrequiredISO 13616 structure: two-letter country code, two check digits, 11-30 alphanumeric BBAN characters — the real range across every current IBAN country, from Norway's 11-character BBAN (15 total) to the longest at 30 (34 total). A structural check only — no mod-97 checksum arithmetic, matching this schema's other patterns (e.g. record-envelope-v1.md's instant pattern), which fix shape and defer deeper arithmetic to the validating application.
CryptoAddressRail
kindobjectrequiredaddressstringrequiredA 20-byte hex address, 0x-prefixed — the exact shape `01` §4.3 change 3 names as one of the three mixed-in rails today. SCOPE: this branch admits EVM-shaped addresses only. `01` §4.3 change 3 names only `0x` addresses for this field; it does not name base58 chains (e.g. Bitcoin, Solana). A non-EVM crypto payout rail is a new branch this schema does not yet declare, not a value this branch should be widened to accept.
EscrowHandleRail
kindobjectrequiredhandlestringrequiredDeliberately opaque, matching `cause.schema.json`'s existing description of the field this taxonomy discriminates — a third-party escrow reference, not validated beyond non-empty.
PolicyBinding
`04` W4-E06 — `03` §3 binding 6, verbatim: 'eligibility, jurisdiction, age, limits.' `02` §4: 'Policy: `.io` executes, `.org` binds via `PolicyBinding`' — this is that binding, real for the first time (`02` §4 previously filed governance binding as 'currently mis-filed as a future E1 plugin').
`04` W4-E06 — `03` §3 binding 6, verbatim: 'eligibility, jurisdiction, age, limits.' `02` §4: 'Policy: `.io` executes, `.org` binds via `PolicyBinding`' — this is that binding, real for the first time (`02` §4 previously filed governance binding as 'currently mis-filed as a future E1 plugin'). Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200PolicyBindingPageA page of policybindings.
`04` W4-E06 — `03` §3 binding 6, verbatim: 'eligibility, jurisdiction, age, limits.' `02` §4: 'Policy: `.io` executes, `.org` binds via `PolicyBinding`' — this is that binding, real for the first time (`02` §4 previously filed governance binding as 'currently mis-filed as a future E1 plugin').
Parameters
idpath · requiredThe policybinding id.
Responses
200PolicyBindingThe policybinding.404
PolicyBinding
`04` W4-E06 — `03` §3 binding 6, verbatim: 'eligibility, jurisdiction, age, limits.' `02` §4: 'Policy: `.io` executes, `.org` binds via `PolicyBinding`' — this is that binding, real for the first time (`02` §4 previously filed governance binding as 'currently mis-filed as a future E1 plugin').
policy_binding_idstringrequiredIdentity — the value a product manifest's binding 6 names as `policy_binding_ref` (`packages/product-registry/src/manifest.ts`'s `PolicyBindingInput.policy_binding_ref`, `04` W4-E06 criterion 1). NO PATTERN, on `fund.schema.json`'s own `id` reasoning: no document fixes an id space for this record, and inventing one would freeze a byte before its gate. NON-EMPTY: an empty string is not an identity.
marketstringrequiredISO 3166-1 alpha-2 — the SAME shape `fund.schema.json`'s `source_jurisdiction` already fixes for a jurisdiction value, reused rather than reinvented. Unlike that field's own fixtures (which deliberately use the reserved `ZZ` code because `G-jurisdictions` named no real market when that schema was authored), THIS schema's own fixtures use `GB` for real: `04` W4-E06's own 2026-08-18 unblocking note states `G-jurisdictions` is now 'partially answered, UK named, which is sufficient to build and test the per-market age-floor machinery' — this field's real first value. Renamed from `03` §3's own table header 'jurisdiction' to `market` to match this epic's own accept-criteria language ('the age floor is per-market') — the identical fact under the vocabulary this epic actually uses, not a second one.
eligibilityobjectrequired`03` §3 binding 6's `eligibility` member. Open shape, presence-only — `packages/product-registry/src/manifest.ts`'s own `PolicyBindingInput` gives every binding-6 member this same presence-only treatment ('no epic in this catalogue owns their shape yet'); this epic's own four accept criteria do not name an eligibility shape either, so none is invented here.
age_floorintegerrequired`03` §3 binding 6's `age` member, as a plain non-negative integer — the number of years. `04` W4-E06 criterion 3: read from `apps/org`'s own per-market adapter (`governance/market-age-floor.ts`) at PROPOSE time, never asserted independently of it and never hardcoded anywhere this schema's own validation runs. This schema fixes only the STORED SHAPE of the number the adapter already resolved — it cannot itself call the adapter (a JSON Schema has no access to a market table), so 'never hardcoded into domain logic' is enforced one layer up, in code, not here.
limitsobjectrequired`03` §3 binding 6's `limits` member. Open shape, presence-only — same reasoning as `eligibility` above.
statusenumrequiredproposed · in_force · withdrawnThis record's own lifecycle position. `proposed`: recorded, awaiting a second, distinct principal's approval. `in_force`: approved by a principal DISTINCT from the proposer (`04` W4-E06 criterion 2) — the ONLY status a product manifest's `policy_binding_ref` may resolve to and still be admitted (`04` W4-E06 criterion 1: 'a manifest whose binding 6 references no in-force PolicyBinding is rejected at admission'). `withdrawn`: no longer governs anything; retained, never deleted, on `apps/org`'s own oversight-trail 'superseded, never amended in place' convention (`04` W4-E08 acceptance 4).
proposed_bystringrequiredThe identity that proposed this PolicyBinding — opaque, on `apps/console/src/lib/operator/identity-port.ts`'s own 'opaque Verdify-issued reference' convention. `04` W4-E06 criterion 2's whole subject: `approved_by` below must never equal this value once `status` is `in_force`.
approved_bystring | nullrequiredThe identity that approved this PolicyBinding, or `null` while `status` is `proposed` (no approval has happened yet). `04` W4-E06 criterion 2, direct template of `apps/console/src/lib/operator/actions.ts`'s `approveAction`: an approval whose identity equals `proposed_by` is refused by the WORKFLOW that would otherwise write this field (`E_SELF_APPROVAL_FORBIDDEN`, ADR 0015 §11.6) — never by this schema, which sees only the already-accepted result of that check, on `container.schema.json`'s own 'schema-blind to the distinction' precedent. Present-but-null rather than absent while unresolved, on `attestation.schema.json`'s and `fund.schema.json`'s own shared convention (`03` §1.4: no optional field in an anchored shape).
effective_fromstring | nullrequiredThe instant this PolicyBinding became `in_force`, or `null` before that has happened. `apps/org/src/governance/policy-binding-registry.ts` sets this at the moment `approvePolicyBinding` succeeds — the same 'effective-dated, not merely stored inertly' discipline `apps/console/src/lib/operator/controls/declared-deficiency-register.ts`'s own `effectiveFrom` and `apps/org/src/oversight/supersession.ts`'s own `effectiveFrom` already establish for an unrelated record.
withdrawn_atstring | nullrequiredThe instant this PolicyBinding was withdrawn, or `null` while it has not been. Present-but-null, same reasoning as `approved_by` and `effective_from` above.
mechanism_profile_refobjectADR 0071 §7.1: the mechanism profile this binding applies in its market — a REFERENCE into the content-addressed profile registry (`packages/mechanism-profiles`), never the profile's values, which live there once; the profile carries no market because this binding does. Proposed and approved with the rest of this record through the four-eyed `policy-binding-proposal` control. Resolved one layer up, where a reference whose `digest` is not the registry's own for (`profile_id`, `version`) is refused — a schema cannot read the registry. OPTIONAL, unlike every other member: it is additive, and a binding recorded before it existed is re-validated when it is approved or withdrawn, so requiring it would refuse those acts. `03` §1.4's no-optional-field rule binds an anchored proof format, which this governance record is not. Absent is the one spelling of "no profile"; `null` is refused. ADR 0071 §1.1 snapshots the reference into a container's `terms` at creation, so a later change here cannot reach an open container.
profile_idstringrequiredThe profile's id in the registry. Lowercase ASCII kebab-case: ADR 0071 §7.1 stores a profile at `profiles/<profile_id>.v<version>.json`, so the id is a file-name segment and may carry no separator, dot or traversal sequence.
versionintegerrequiredThe profile's version, a positive integer within Rule N1's range. A changed profile is a new version, never an edit.
digeststringrequiredSHA-256 of the profile file, as the registry's `index.json` pins it, rendered per canonical-form-v1.md Rule D3: lowercase, unprefixed hexadecimal.
PublicResultObservation
Veraq Phase 1 'Evidence Bridge' (docs/ops/11-veraq-phase1-scope-decision.md §6 item 2) -- the `result_observation_v1` entry_kind payload apps/net's public, permanent open record actually stores for an `official-result` container's observed outcome.
Veraq Phase 1 'Evidence Bridge' (docs/ops/11-veraq-phase1-scope-decision.md §6 item 2) -- the `result_observation_v1` entry_kind payload apps/net's public, permanent open record actually stores for an `official-result` container's observed outcome. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200PublicResultObservationPageA page of publicresultobservations.
Veraq Phase 1 'Evidence Bridge' (docs/ops/11-veraq-phase1-scope-decision.md §6 item 2) -- the `result_observation_v1` entry_kind payload apps/net's public, permanent open record actually stores for an `official-result` container's observed outcome.
Parameters
idpath · requiredThe publicresultobservation id.
Responses
200PublicResultObservationThe publicresultobservation.404
PublicResultObservation
Veraq Phase 1 'Evidence Bridge' (docs/ops/11-veraq-phase1-scope-decision.md §6 item 2) -- the `result_observation_v1` entry_kind payload apps/net's public, permanent open record actually stores for an `official-result` container's observed outcome.
sourceobjectrequiredThe pinned, already-public description of WHAT WAS OBSERVED -- the same four-member pin (`source_authority`/`publication_url`/`field`/`format`) `result-source.schema.json` carries, plus `revision_policy`, so a third party can independently re-fetch the named field from the named public URL and compare it against `observed_value`. Deliberately EXCLUDES `result-source.schema.json`'s own `quantity_declaration` (an internal, commitment-time self-attestation with no bearing on independent verification) and carries no `container_id`/`outcome_id`/any apps/io-internal identifier -- this object is a copy of already-public information about a public authority's own publication, never a reference to a Veraq-internal record.
source_authoritystringrequiredWHICH independent authority was observed -- e.g. "National Meteorological Office". Self-declared and unverifiable by the protocol alone, the same posture `result-source.schema.json` documents. `maxLength` (adversarial-review fix): a short technical identifier, not free prose -- a public, permanent, append-only record is not the place for an unbounded string a caller could otherwise use to smuggle arbitrary content past `additionalProperties: false`'s own key-level protection.
publication_urlstringrequiredWHERE the authority publishes the figure -- the exact URL a third party re-fetches to check `observed_value` independently.
fieldstringrequiredThe EXACT field, inside the publication, that was observed. `maxLength` (adversarial-review fix): see `source_authority`'s own note -- a field name is a short technical identifier, never a place for arbitrary smuggled content.
formatstringrequiredThe shape the pinned field is published in -- e.g. "json:number". Free text, matching `result-source.schema.json`'s own v1 scope. `maxLength` (adversarial-review fix): see `source_authority`'s own note.
revision_policyenumrequiredfirst_published · final_only · latest_as_of_window_closeWHICH revision counts, committed in advance -- `result-source.schema.json`'s own enum, restated here so a third party checking a since-revised authority page knows which revision this observation is bound to.
observed_valueinteger | nullrequiredThe observed figure, at v1 scope an integer (`apps/io/src/observations/capture.ts`'s `json:number` scope), or `null` if no capture landed inside the observation window (the `substitute_none` fallback's legitimate value, never an absent member).
observed_digestPublicResultObservation_publicResultObservationDigestADDITIVE (ADR 0071 S24 part A, the referential Game 2): the observed fact when it is a 256-bit digest rather than an integer -- the Bitcoin block hash at a height the terms fixed before open, which at least two independent observers reported identically. OPTIONAL and ABSENT from every entry recorded before it, so every existing `result_observation_v1` entry still verifies unchanged (a verifier that predates this member sees an entry it must refuse only because `additionalProperties` is false: `.net` and its readers upgrade together, and the first entry carrying it is recorded only after both do). EXCLUSIVE with an integer `observed_value` (which must then be `null`). Like an integer value it requires a present `evidence_digest` (the SHA-256 of the source publication: for a block hash, of the proof: the concatenated 80-byte headers from the pinned anchor through the confirmations). Public, and carrying nothing participant-correlating: a block hash is a public fact.
evidence_digeststring | nullrequiredThe successful capture's evidence digest (SHA-256 over the raw captured response bytes, `evidence_digest_algorithm` fixed to `sha256` at v1) -- ATOMIC with `observed_value` (the root `if`/`then`/`else` above): null exactly when `observed_value` is null, a real digest exactly when a value was observed. Lets a third party who separately obtains the raw capture bytes (e.g. from an evidence archive) confirm they are the exact bytes this observation was computed from.
fetched_fromstringrequiredWHERE the observation was actually fetched from -- ordinarily identical to `source.publication_url`, but may name an archived capture reached in its place. Public by construction: it names a location on the public authority's own infrastructure (or a public archive), never a Veraq-internal path. `format: "uri"`/`maxLength` (adversarial-review fix): this field is ordinarily identical to `publication_url`, which already carries both constraints -- leaving this one unconstrained was an inconsistency, not a deliberate looser rule, and an unconstrained free-text field here could otherwise smuggle arbitrary content past `additionalProperties: false`'s own key-level protection.
fetched_atPublicResultObservation_instantrequiredWHEN the published observation was fetched.
observer_independenceenumrequiredsingle_party · multi_party`result-observation.schema.json`'s own enum, restated here so a third party can see, without trusting Veraq's own narration, whether more than one independent observer corroborated this value.
batch_digestPublicResultObservation_publicResultObservationDigestrequiredThe digest of the WHOLE capture batch this observation belongs to (every attempt, failures included) -- `result-observation.schema.json`'s own `batch_digest`, restated here so the observe-dislike-reobserve defence is enforceable by anyone reading the public record, not only by apps/io's own private database triggers.
batch_digest_published_atPublicResultObservation_instantrequiredWHEN `batch_digest` was published to this same public record. `veraqStrictlyBefore` below requires this to be STRICTLY EARLIER than `value_published_at` -- the observe-dislike-reobserve defence: an operator who captured a value, disliked it, and wanted to quietly re-observe cannot do so once the batch digest is itself a permanent, third-party-visible fact that predates the value.
value_published_atPublicResultObservation_instantrequiredWHEN `observed_value` was published to this same public record.
ReferenceDrawResultEntry
Game 2 (C-EVD-03c): the `reference_draw_result_v1` entry_kind payload -- the published RESULT of one REFERENTIAL number-match round (mechanism `reference-digits-v1`, docs/ops/specs/reference-digits-v1.md section 4), whose numbers come from the Bitcoin block hash at a height H the round's terms fixed before any sale, AND the proof P that fact rests on, so the round can be replayed from public evidence.
Game 2 (C-EVD-03c): the `reference_draw_result_v1` entry_kind payload -- the published RESULT of one REFERENTIAL number-match round (mechanism `reference-digits-v1`, docs/ops/specs/reference-digits-v1.md section 4), whose numbers come from the Bitcoin block hash at a height H the round's terms fixed before any sale, AND the proof P that fact rests on, so the round can be replayed from public evidence. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ReferenceDrawResultEntryPageA page of referencedrawresultentries.
Game 2 (C-EVD-03c): the `reference_draw_result_v1` entry_kind payload -- the published RESULT of one REFERENTIAL number-match round (mechanism `reference-digits-v1`, docs/ops/specs/reference-digits-v1.md section 4), whose numbers come from the Bitcoin block hash at a height H the round's terms fixed before any sale, AND the proof P that fact rests on, so the round can be replayed from public evidence.
Parameters
idpath · requiredThe referencedrawresultentry id.
Responses
200ReferenceDrawResultEntryThe referencedrawresultentry.404
ReferenceDrawResultEntry
Game 2 (C-EVD-03c): the `reference_draw_result_v1` entry_kind payload -- the published RESULT of one REFERENTIAL number-match round (mechanism `reference-digits-v1`, docs/ops/specs/reference-digits-v1.md section 4), whose numbers come from the Bitcoin block hash at a height H the round's terms fixed before any sale, AND the proof P that fact rests on, so the round can be replayed from public evidence.
container_idstringrequiredThe container (round) this result is for.
anchor_heightintegerrequiredT: the binding's anchor height (the round's terms, `reference.anchor_height`). `headers[0]` is the anchor's own header.
reference_heightintegerrequiredH: the height whose block hash is the round's fact (the round's terms, `reference.height`), fixed before any sale. Greater than `anchor_height`.
block_hashReferenceDrawResultEntry_drawResultDigestrequiredThe fact: the block hash at H as explorers print it (SHA-256 twice over the header `headers[reference_height - anchor_height]`, byte-reversed, lowercase hexadecimal). The same value as the round's `result_observation_v1` `observed_digest`.
evidence_digestReferenceDrawResultEntry_drawResultDigestrequiredSHA-256 over the concatenated 80-byte headers of `headers`, in order: the digest of the EXACT proof. The same value as the round's `result_observation_v1` `evidence_digest`.
headersarray<string>requiredP: every block header from the anchor T (its own header, first) through H+confirmations, in height order, each 80 bytes as 160 lowercase hexadecimal digits. Exactly the proof `evidence_digest` commits to, `(H - T) + confirmations + 1` headers, with no extension header. The bound, 1153, is protocol-ref's `MAX_ANCHOR_DISTANCE` (1008) plus 144 confirmations (PROVISIONAL: protocol-ref bounds the confirmations from below only; 144 is its `MAX_PROOF_EXTENSION`, one day of blocks) plus the anchor's own header.
winning_selectionobjectrequiredThe winning numbers per pool id, as `reference-digits-v1` derives them from `block_hash` and the cohort root.
tiersarray<ReferenceDrawResultEntry_drawResultTier>requiredOne row per award tier of the container's award structure, in the structure's order.
pool_total_minorReferenceDrawResultEntry_drawResultMinorrequiredThe pool of exactly the issued, not-returned orders.
carry_in_minorReferenceDrawResultEntry_drawResultMinorrequiredCarried into this round: always '0', since a referential round takes no carry-in (D-PND-30 (a)); `.net` refuses any other value at admission, by `draw_result_v1`'s own rule for a result that names no previous draw.
carry_out_minorReferenceDrawResultEntry_drawResultMinorrequiredThe unwon amount, routed `carry_forward`, that leaves this round's pool, as in `draw_result_v1`. This record names no round that takes it.
breakage_minorReferenceDrawResultEntry_drawResultMinorrequiredThe rounding remainder no line can be credited; it leaves this round's pool with `carry_out_minor`, as in `draw_result_v1`.
line_countintegerrequiredThe number of lines of the bound cohort: the SIZE of the `awards_root` tree (one leaf per line). A proof is valid only at this tree size.
ledger_currencystringrequiredThe ledger currency every amount in this payload is in.
awards_rootReferenceDrawResultEntry_drawResultDigestrequiredThe Merkle root over every line's `(ticket_digest, line_no, tier_id, amount_minor)`, by the rule `draw-result-entry.schema.json` states once (one leaf per line, EVERY line).
ReserveObligation
The per-class record for a jurisdiction's public-obligation classes — `01-platform-architecture.md` §4.3 change 6, RETAINED under ADR 0015 §11.1's amended point 1 and its own text: 'it remains the per-class record for the public-obligation classes; the partition rule decides what enters it.' THIS IS A RECORD SHAPE, NOT A COMPUTATION — the same distinction allocation.schema.json draws against ADR 0015's crossing authorities: a record shape at level 6 versus an authority over a money crossing.
The per-class record for a jurisdiction's public-obligation classes — `01-platform-architecture.md` §4.3 change 6, RETAINED under ADR 0015 §11.1's amended point 1 and its own text: 'it remains the per-class record for the public-obligation classes; the partition rule decides what enters it.' THIS IS A RECORD SHAPE, NOT A COMPUTATION — the same distinction allocation.schema.json draws against ADR 0015's crossing authorities: a record shape at level 6 versus an authority over a money crossing. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ReserveObligationPageA page of reserveobligations.
The per-class record for a jurisdiction's public-obligation classes — `01-platform-architecture.md` §4.3 change 6, RETAINED under ADR 0015 §11.1's amended point 1 and its own text: 'it remains the per-class record for the public-obligation classes; the partition rule decides what enters it.' THIS IS A RECORD SHAPE, NOT A COMPUTATION — the same distinction allocation.schema.json draws against ADR 0015's crossing authorities: a record shape at level 6 versus an authority over a money crossing.
Parameters
idpath · requiredThe reserveobligation id.
Responses
200ReserveObligationThe reserveobligation.404
ReserveObligation
The per-class record for a jurisdiction's public-obligation classes — `01-platform-architecture.md` §4.3 change 6, RETAINED under ADR 0015 §11.1's amended point 1 and its own text: 'it remains the per-class record for the public-obligation classes; the partition rule decides what enters it.' THIS IS A RECORD SHAPE, NOT A COMPUTATION — the same distinction allocation.schema.json draws against ADR 0015's crossing authorities: a record shape at level 6 versus an authority over a money crossing.
idstringrequiredIdentity. NO PATTERN, on container.schema.json's and funding.schema.json's shared precedent: no document fixes an id space for this record, and inventing one would freeze a byte before its gate. NON-EMPTY: an empty string is not an identity.
source_jurisdictionstringrequiredADR 0013 Decision 3: 'The jurisdiction on a reserved amount is snapshotted, not referenced. Re-domiciling a Fund never rewrites the classification of amounts already calculated.' This is a COPY taken at recognition, never a live pointer through `source_fund_id` — which is exactly why it is a distinct field here rather than something a reader derives by following the Fund reference. ISO 3166-1 alpha-2, the SAME shape `fund.schema.json`'s own `source_jurisdiction` carries (proven structurally in this schema's test suite), because a snapshot of a fact and the fact itself must be the same fact, byte for byte. `G-jurisdictions` is open; every fixture uses an ISO 3166-1 user-assigned code, never a real market.
source_fund_idstringrequiredThe Fund this amount was recognised into (ADR 0013 Decision 1). A REFERENCE ONLY: fund.schema.json owns `creation_tier` and `governance_reason_digest`, and this record does not restate them — on allocation.schema.json's own precedent for `recipient_participation_id` ('participation.schema.json owns that id space'). NO PATTERN: fund.schema.json's own `id` fixes none, so repeating one here would put one piece of knowledge in two places. NON-EMPTY, because a reserved amount naming no Fund is unclassifiable by jurisdiction at all.
currencystringrequiredThe SAME spelling contribution.schema.json already established for a currency field (ISO-4217 alphabetic code, or a supported crypto ticker) — reused rather than reinvented, proven structurally in this schema's test suite. ADR 0015 §11.1 amended point 5: 'No implicit FX. Held and remitted in the currency it arose in. Conversion is a policy decision with counsel input, never an operational convenience' — so this is the ONE currency field on the record, never a pair, and there is no conversion-rate member anywhere in this schema.
calc_rule_versionstringrequiredThe versioned calculation rule this amount was recognised under (ADR 0013 Decision 4: 'The reserve is calculated from the first day, under a versioned calculation rule'). ADR 0015 §11.1 amended point 1 makes `calc_rule_version` a REQUIRED POSTING-LEVEL DIMENSION — 'which is what makes per-obligation balances derived rather than stored.' NO PATTERN: the versioning SCHEME belongs to whichever registry eventually publishes calculation rules, not to this record shape, and inventing one here would freeze a byte that registry has not yet fixed.
partition_rule_versionstringrequiredThe versioned partition rule under which this amount's obligation class was assigned at receipt (ADR 0015 §1 and §6: 'a published, versioned partition rule keyed on (product, jurisdiction)'). A COMPANION to `calc_rule_version`, not a substitute for it — ADR 0013's own amended Consequences: 'calc_rule_version gains a companion partition_rule_version.' Distinct from `partition_rule_digest` (`03` §7.3 rule 3; ADR 0015 §6): the digest is what is PUBLISHED per participation, openable by the holder; the version is the ledger-side posting dimension this record carries. NO PATTERN, for the same reason `calc_rule_version` carries none: `04` W5-E05 (the partition-rule registry) owns that versioning scheme, and this epic does not pre-empt it.
principalReserveObligation_positiveQuantityrequiredThe reserved amount itself, before income or fees. A SEPARATE ACCOUNT from `income` and `fees` from day one (ADR 0013 Consequences), never their sum folded into one figure. STRICTLY POSITIVE, unlike `income`/`fees`: no document states principal is ever expected to be zero — a `ReserveObligation` records that a jurisdiction's obligation class received something, so a principal of zero is not this record's normal case the way a zero income or fee is.
incomeReserveObligation_nonNegativeQuantityrequiredIncome attributable to this obligation, tracked separately even though 'expected to be zero' (ADR 0013 Consequences: 'A retroactive determination that income belongs to the obligee is unanswerable if income was never tracked separately'). ADR 0015 §11.1 amended point 4: 'Income is separately classified and unavailable, attributed by a versioned rule, rounded against Veraq, under the SAME RESTRICTIONS AS PRINCIPAL' — which is why this shares `principal`'s exact `nonNegativeQuantity` $defs rather than a looser spelling of its own.
feesReserveObligation_nonNegativeQuantityrequiredFees attributable to this obligation (e.g. a rule-declared, capped `cost-of-acceptance` class — ADR 0015 §8), tracked as a separate account from day one, 'even though income and fees are expected to be zero' (ADR 0013 Consequences).
legal_statusobjectrequiredADR 0013 Decision 5: 'The legal classification is an explicit field defaulting to PROVISIONAL, effective-dated and evidence-referenced. It is never inferred from any other state in the system.' ONE FIELD bundling the three facts Decision 5 names together, on container.schema.json's own precedent for `closes_on` (one field, several required members) — never three top-level members whose pairing could drift apart. CLOSED TO `PROVISIONAL` TODAY: ADR 0015's Deferred table restates ADR 0013 unchanged — 'PROVISIONAL until counsel classifies' — and no document names a second value; that value is blocked on counsel (`G-memo`), and inventing one here would answer a counsel-gated question by implication.
valueobjectrequiredDefaults to `PROVISIONAL` (ADR 0013 Decision 5). Closed to this one value because it is the only legal classification any document names; widening this to a second, counsel-classified value is a future, counsel-gated schema change, not a decision this epic may make.
effective_atReserveObligation_instantrequiredEffective-dated, per Decision 5. 'Reclassification never rewrites history. It is a new effective-dated event; balances as at a past date remain what they were' (ADR 0013 Consequences).
evidence_digestReserveObligation_digestrequiredEvidence-referenced, per Decision 5 — by digest, never inline, matching commitment.schema.json's and fund.schema.json's own governance-evidence field. NEVER INFERRED: the classification stays independent of `lifecycle_status` and of every other field on this record, which is why it is required rather than filled in silently from something else.
lifecycle_statusstringrequiredADR 0013 Decision 5: 'lifecycle status is a separate axis from legal status.' ITS VALUE SET IS DELIBERATELY UNCONSTRAINED HERE — the same recorded gap container.schema.json's own `status` field states rather than hides: 'no document fixes a member set' for this record's lifecycle today. Recognition is atomic at receipt (ADR 0015 §2); what happens after — accrual, partial or full disposition, closure — is a transition machine `04` W5-E04's crossing authorities and `04` W5-E07's reconciliation harness are positioned to own, on `04` W3-E09's precedent for `Container.status`. REQUIRED, never optional: `03` §1.4 rules out an optional field in a record shape, so a ReserveObligation with no lifecycle state at all is not a valid record even before that transition machine lands.
disposition_historyarray<object>requiredThe append-only history of amounts discharged from this obligation via ADR 0015 §5's crossing authorities (`Disposition`, `Release`, `Return`, `ContinuityRelease`) — the field `01` §4.3 change 6 names directly. EMPTY BY DEFAULT AT RECOGNITION: ADR 0015's own 'What's needed to execute' blocks 'any Release or ContinuityRelease execution' and 'all rule evaluation' on counsel, so a freshly recognised obligation has discharged nothing yet, and this schema must not require a first entry that cannot yet exist. Each entry references the discharging event BY ID rather than embedding the crossing authority's own mechanics — `04` W5-E04's `packages/obligation-*` owns those authorities' shape, not this schema.
ResultObservation
What was RECORDED AT RESOLUTION for an `external`-form container — `03` §5.1, verbatim: "observed value, provenance, source-publication digest, and every failed capture attempt"; `02` §7 unpacks provenance as "where fetched, when, by whom".
What was RECORDED AT RESOLUTION for an `external`-form container — `03` §5.1, verbatim: "observed value, provenance, source-publication digest, and every failed capture attempt"; `02` §7 unpacks provenance as "where fetched, when, by whom". Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ResultObservationPageA page of resultobservations.
What was RECORDED AT RESOLUTION for an `external`-form container — `03` §5.1, verbatim: "observed value, provenance, source-publication digest, and every failed capture attempt"; `02` §7 unpacks provenance as "where fetched, when, by whom".
Parameters
idpath · requiredThe resultobservation id.
Responses
200ResultObservationThe resultobservation.404
ResultObservation
What was RECORDED AT RESOLUTION for an `external`-form container — `03` §5.1, verbatim: "observed value, provenance, source-publication digest, and every failed capture attempt"; `02` §7 unpacks provenance as "where fetched, when, by whom".
idstringrequiredIdentity. NO PATTERN, on `container.schema.json`'s precedent, applied here as `allocation.schema.json` already applies it to a level-6-shaped leaf: no document fixes an id space for this class, and inventing one would freeze a byte before its gate.
outcome_idstringrequiredThe outcome this observation was recorded for — `official-result-reference-v1.md` "Outcome integrity": "the `observed_value` recorded in `Outcome.verification`'s `ResultObservation`". NO PATTERN, DELIBERATELY, on `allocation.schema.json`'s own precedent and its own citation of `03` §1.4: a pattern here would repeat the leak that made `contribution.schema.json` wave-shaped in its frozen bytes.
observed_valueobjectrequired`official-result-reference-v1.md` "Inputs" §4, verbatim: "an integer at `parameters.value_scale`, or `null` if no capture landed inside `parameters.observation_window_seconds`" — the `substitute_none` fallback's legitimate value, never an absent member (`03` §1.4: a verifier reads a present null rather than guessing at an absence). The declared scale itself is `Mechanism.parameters`', not this schema's — `canonical-form-v1.md` §2.1 places scale enforcement at the schema that declares a decimal-with-scale field, and this one carries no per-container scale to enforce against.
observed_digestResultObservation_resultDigestADDITIVE (ADR 0071 S24 part A, the referential Game 2): the observed fact when it is a 256-bit digest rather than an integer — today the Bitcoin block hash at a height the terms fixed before open, agreed by at least two independent observers. OPTIONAL and ABSENT from every entry that predates it, so every existing document still validates byte for byte. EXCLUSIVE with an integer `observed_value` (which must then be `null`): a document carries one observed fact, never two. Counts as a recorded success for `veraqAttemptCountConsistent`, and, like an integer value, requires a present `evidence_digest` (the SHA-256 of the source publication — for a block hash, of the proof: the concatenated 80-byte headers from the pinned anchor through the confirmations) — see the root `if`/`then`/`else`.
provenanceobjectrequired`02` §7's own unpacking of `03` §5.1's "provenance": "where fetched, when, by whom". Required as a whole, whether or not the capture ultimately succeeded — even a `substitute_none` resolution names the observation process and the moment its window closed, not only a successful fetch.
fetched_fromstringrequiredWHERE — the location actually read (the pinned `ResultSource.publication_url`, or the archived capture reached in its place).
fetched_atResultObservation_instantrequiredWHEN — the moment of the capture this provenance describes.
fetched_bystringrequiredBY WHOM — an observer identifier, drawn from the committed `Mechanism.parameters.observer_set` this schema does not duplicate.
evidence_digestobjectrequired`03` §5.1's "source-publication digest" / `02` §7's "an evidence digest of the source publication" — computed under `Mechanism.parameters.evidence_digest_algorithm` (fixed to `sha256` at v1). ATOMIC WITH `observed_value` (the root `if`/`then`/`else` above, on `attestation.schema.json`'s `RevealIsAtomic`-shaped precedent): null exactly when `observed_value` is null — there is no evidence to digest for a capture that never landed — and a real digest exactly when a value was observed.
attempt_countintegerrequiredThe total number of capture attempts this document claims were made. `04` `W1-E07` acceptance 1: must equal `failed_capture_attempts.length` plus one more if `observed_value` is not `null` — enforced by `veraqAttemptCountConsistent`, not merely declared here.
failed_capture_attemptsarray<object>requiredEVERY FAILED CAPTURE ATTEMPT — `03` §5.1's own phrase, verbatim, and the member that makes mis-observation (THREAT_MODEL.md adversary 2) inspectable rather than asserted: a `ResultObservation` claiming a success is not permitted to omit the failures `attempt_count` says preceded it (`veraqAttemptCountConsistent`). MAY be empty — a capture that succeeded on its first attempt records zero failures, and `attempt_count` reflects that.
observer_independenceenumrequiredsingle_party · multi_party`03` §5.1, verbatim: `Outcome.verification.observer_independence ∈ {single_party, multi_party}` — "recorded and rendered, never asserted beyond what it states." `04` `W1-E07` acceptance 2: required, exactly these two members, no default — omission rejects precisely because `required` above names it and this is a `type: string` `enum`, never a member with a fallback value.
batch_digestResultObservation_resultDigestrequired`03` §5.1 "Relationship to `.net`", verbatim: "the observation batch digest" — the digest of the WHOLE capture batch (every attempt, failures included), anchored on the open record before `value_published_at`. Never null: a batch digest exists once observation begins, independent of whether any attempt inside it succeeds.
batch_digest_published_atResultObservation_instantrequiredWHEN `batch_digest` was anchored to the open record. `04` `W1-E07` acceptance 3: must be STRICTLY EARLIER than `value_published_at` — the observe-dislike-reobserve defence, enforced by `veraqStrictlyBefore` below, not left to the write path alone. This is an INTRA-document comparison (both timestamps live on this one entity), unlike `commitment.schema.json`'s `published_at` vs. a DIFFERENT document's `Container.opens_at`, which is genuinely cross-entity and stays `04` `W3-E09`'s.
value_published_atResultObservation_instantrequiredWHEN the extracted value — `observed_value`, including the `substitute_none` sentinel — was published to the open record. Always present, even under `substitute_none`: `official-result-reference-v1.md` "Fallback handling" states `ALG` **is** invoked and returns a legitimate verdict in that case, so a value (the `none` verdict) is still published.
ResultSource
The pinned definition of WHAT TO OBSERVE for an `external`-form product — `03` §5.1's committed "source authority, publication URL, exact field, format, revision policy".
The pinned definition of WHAT TO OBSERVE for an `external`-form product — `03` §5.1's committed "source authority, publication URL, exact field, format, revision policy". Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200ResultSourcePageA page of resultsources.
The pinned definition of WHAT TO OBSERVE for an `external`-form product — `03` §5.1's committed "source authority, publication URL, exact field, format, revision policy".
Parameters
idpath · requiredThe resultsource id.
Responses
200ResultSourceThe resultsource.404
ResultSource
The pinned definition of WHAT TO OBSERVE for an `external`-form product — `03` §5.1's committed "source authority, publication URL, exact field, format, revision policy".
source_authoritystringrequiredWHICH independent authority is observed — `official-result-reference-v1.md`'s worked example: "National Meteorological Office". Self-declared and unverifiable by the protocol alone, the same posture `revision_policy` has (the spec's own "Known limitation").
publication_urlstringrequiredWHERE the authority publishes the figure. Part of the four-member pin (`source_authority`, `publication_url`, `field`, `format`) `03` §5.1 names verbatim as committed before opening, and THREAT_MODEL.md adversary 4's mitigation: "the field is ambiguous" is exactly what an honestly-pinned source without this member would leave open.
fieldstringrequiredThe EXACT field, inside the publication, the observers watch — `official-result-reference-v1.md`'s worked example: "mean_temperature_c". A publication with several figures on one page is not enough; this pins which one.
formatstringrequiredThe shape the pinned field is published in — `official-result-reference-v1.md`'s worked example: "json:number". Free text at v1: the spec fixes no closed vocabulary for this member, so this schema fixes none either rather than inventing a stricter contract the spec itself does not commit to.
revision_policyenumrequiredfirst_published · final_only · latest_as_of_window_closeWHICH revision counts, committed in advance, for an authority that later revises a preliminary figure — `official-result-reference-v1.md` "Inputs" §1, verbatim: `first_published` binds the earliest published figure regardless of later revision; `final_only` binds observers to wait for the authority's own "final" marking (the observation stays absent if none arrives inside the window); `latest_as_of_window_close` binds whatever revision was current when `observation_window_seconds` elapses. EXACTLY these three members, spelled exactly as the spec spells them — a fourth or a renamed member would silently stop being a superset of what `veraq-protocol` already fixed.
quantity_declarationobjectrequiredFive booleans, one per disjunct of `03` §5.1's source-exclusion clause, required because the exclusion is drawn "by object referenced rather than by publisher" (`03` §5.1) — the predicate needs something to check that is not a heuristic over `publication_url` or `field` text. `official-result-reference-v1.md` "Source exclusion": a `ResultSource` with any flag `true` MUST NOT be committed — checked once, at commitment time, by `veraq-protocol`'s `is_excluded`, not by this schema.
is_macroeconomic_indicatorbooleanrequired`03` §5.1's first excluded disjunct — CPI, unemployment, GDP and energy-output figures are the spec's own canonical underliers of this disjunct.
is_pricebooleanrequired`03` §5.1's second excluded disjunct.
is_ratebooleanrequired`03` §5.1's third excluded disjunct — an FX rate is `official-result-reference-v1.md`'s own worked counter-example.
is_index_levelbooleanrequired`03` §5.1's fourth excluded disjunct — an equity-index level is `official-result-reference-v1.md`'s own worked counter-example.
has_listed_or_otc_derivativebooleanrequired`03` §5.1's fifth excluded disjunct: "any quantity on which a listed or OTC derivative exists", checked by object referenced, never by publisher.
SealedCommitmentEntry
ADR 0071 §2.1's `sealed_commitment_v1` entry_kind payload -- the `.net` carrier of a beacon-bound container's SealedCommitment.
ADR 0071 §2.1's `sealed_commitment_v1` entry_kind payload -- the `.net` carrier of a beacon-bound container's SealedCommitment. Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200SealedCommitmentEntryPageA page of sealedcommitmententries.
ADR 0071 §2.1's `sealed_commitment_v1` entry_kind payload -- the `.net` carrier of a beacon-bound container's SealedCommitment.
Parameters
idpath · requiredThe sealedcommitmententry id.
Responses
200SealedCommitmentEntryThe sealedcommitmententry.404
SealedCommitmentEntry
ADR 0071 §2.1's `sealed_commitment_v1` entry_kind payload -- the `.net` carrier of a beacon-bound container's SealedCommitment.
container_idstringrequiredThe container this SealedCommitment binds.
terms_digestSealedCommitmentEntry_sealedCommitmentDigestrequiredThe digest of the container's terms (`terms.randomness` carries B's fields, so the published terms recompute `seed_commitment`).
seed_commitmentSealedCommitmentEntry_sealedCommitmentDigestrequiredSHA-256 of the canonical pre-open binding B (`number-match-v1`'s binding digest): the SealedCommitment's own `seed_commitment`, published strictly before `opens_at` (03 §1.3).
Selection
A single participant's ACTUAL CHOSEN ANSWER for one participation — the canonical, real (never sandbox-only) representation of "what the customer selected/predicted," replacing `apps/io`'s own `sandbox_participation_selections` sidecar as the source of truth (that sidecar existed only because this schema did not — see its own header).
A single participant's ACTUAL CHOSEN ANSWER for one participation — the canonical, real (never sandbox-only) representation of "what the customer selected/predicted," replacing `apps/io`'s own `sandbox_participation_selections` sidecar as the source of truth (that sidecar existed only because this schema did not — see its own header). Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200SelectionPageA page of selections.
A single participant's ACTUAL CHOSEN ANSWER for one participation — the canonical, real (never sandbox-only) representation of "what the customer selected/predicted," replacing `apps/io`'s own `sandbox_participation_selections` sidecar as the source of truth (that sidecar existed only because this schema did not — see its own header).
Parameters
idpath · requiredThe selection id.
Responses
200SelectionThe selection.404
Selection
A single participant's ACTUAL CHOSEN ANSWER for one participation — the canonical, real (never sandbox-only) representation of "what the customer selected/predicted," replacing `apps/io`'s own `sandbox_participation_selections` sidecar as the source of truth (that sidecar existed only because this schema did not — see its own header).
RangeSelection
A numeric guess, e.g. "guess the mean temperature to the nearest half-degree" or "guess this repository's star count." A WHOLE number is a plain JSON integer; a FRACTIONAL guess must be sent as its Rule-N4-normal-form decimal string (see the `quantity` $def above) — never a raw JSON float, which `@veraq/kernel`'s `digestHex` cannot canonicalise at all. Not integer-CONSTRAINED, only integer-OR-decimal-string-shaped: that is a digest-safety requirement on this schema's own `value` member, distinct from `apps/io/src/observations/capture.ts`'s own, separate v1 `json:number` scope on the OBSERVATION side (which this schema does not inherit).
schema_versionobjectrequiredkindobjectrequiredvalueSelection_quantityrequiredBandSelection
An enumerated choice from a closed, short list of options — `PredictionBandSelection`'s own shape. `option_id` is a STABLE REFERENCE, matching `PredictionBandOption.id`'s own documented role ('referenced by `PredictionResolution.observedValue` once resolved') — the option's own label/definition lives on the container's offered selection specification (not yet live-wired, same `09` §8 follow-up as `range`'s bounds), never carried inline here, so this record never goes stale if that definition's display text changes.
schema_versionobjectrequiredkindobjectrequiredoption_idstringrequiredOpaque, non-empty — no pattern fixed here for the identical reason `fund.schema.json`'s own `id` fixes none: no corpus document fixes this id space yet, and inventing one would freeze a byte before its gate.
DateSelection
A calendar-date guess, e.g. "guess the date the reservoir will first overflow" — `PredictionDateSelection`'s own shape.
schema_versionobjectrequiredkindobjectrequiredvalueSelection_isoDaterequiredNumberSetSelection
Whole numbers chosen from the numbered pools a container's `NumberSetOffer` declares, keyed by pool id, e.g. `{"main": [4, 11, 19, 23, 36], "bonus": [7]}` (ADR 0071 §1.1). This schema decides what one document can show: each pool id is well-formed, each pool lists at least one number, no number repeats within a pool, and every number is whole, non-negative and within Rule N1's range. It cannot decide what needs the offer — which pools, how many numbers per pool, each number's bounds — because a selection does not carry its offer; that is the offer-aware validation's (ADR 0071 §3.3 step 5). Numbers are kept in the order given, so where the offer's `order_matters` is `false` the writer MUST store each pool's numbers in ascending order, or one set would carry two digests; the offer-aware validation refuses a pool that is not.
schema_versionobjectrequiredkindobjectrequiredpicksobjectrequiredThe chosen numbers, per pool id: at least one pool, each with at least one number and no number twice.
TicketBatch
ADR 0063 §2.1's `ticket_batch_v1` entry_kind payload -- the frozen participation cohort for one container, one batch (ADR 0062's ticket/commitment design, `10` §4.3.1).
ADR 0063 §2.1's `ticket_batch_v1` entry_kind payload -- the frozen participation cohort for one container, one batch (ADR 0062's ticket/commitment design, `10` §4.3.1). Cursor-paginated; every record carries its open-record reference so the reader can cross-check it in the explorer. [OWNER TO CONFIRM]: authentication and rate limits are defined by the live API backend (not in this repo).
Parameters
cursorqueryOpaque pagination cursor returned as `next_cursor` by a prior response.limitqueryMaximum records to return (1–100, default 20).
Responses
200TicketBatchPageA page of ticketbatches.
ADR 0063 §2.1's `ticket_batch_v1` entry_kind payload -- the frozen participation cohort for one container, one batch (ADR 0062's ticket/commitment design, `10` §4.3.1).
Parameters
idpath · requiredThe ticketbatch id.
Responses
200TicketBatchThe ticketbatch.404
TicketBatch
ADR 0063 §2.1's `ticket_batch_v1` entry_kind payload -- the frozen participation cohort for one container, one batch (ADR 0062's ticket/commitment design, `10` §4.3.1).
container_idstringrequiredThe container this batch belongs to.
terms_digestTicketBatch_digestrequiredDigest of the partition rule / terms this batch's tickets were sold under -- ADR 0062's Ticket.terms_digest, carried up to batch granularity so a batch can be checked against the exact terms in force when its tickets were accepted.
batch_seqintegerrequiredDense, monotonically increasing per container, starting at 0 -- the same 'no gap to explain' discipline `IMechanismRegistry`'s spec versions use (ADR 0063 §3 / `packages/contracts-evm/src/interfaces/IMechanismRegistry.sol`).
tree_sizeintegerrequiredThe number of ticket leaves committed in THIS batch's own per-batch RFC 6962 tree (`10` §4.3.1) -- not a running total across batches, which `batch_seq`'s hash chain already makes derivable.
cohort_rootTicketBatch_digestrequiredThis batch's own RFC 6962 Merkle root over its ticket leaves (SHA-256 domain-separated per `packages/kernel/src/merkle.ts`'s Rule M1). Identical bytes to `IParticipationLedger.CohortRootCommitted`'s `cohortRoot` for the same `(container_id, batch_seq)` -- ADR 0062 §2.1's naming resolution: one concept, one name, everywhere.
prev_cohort_rootTicketBatch_digestrequiredThe immediately preceding batch's `cohort_root` for the SAME container -- an explicit hash chain a verifier can walk without trusting `batch_seq` alone to be gapless. For `batch_seq: 0` (the first batch) this is the all-zero digest (64 '0' hex characters), matching `IParticipationLedger`'s own on-chain sentinel for 'no previous batch' (`bytes32(0)`) -- a genuine zero value, not a null, because Solidity's event has no null to carry and this kernel record deliberately mirrors that sentinel rather than inventing a second convention for the identical fact.
reference_tipobjectADR 0071 S24 part A2 (commit-before-knowable), a REFERENTIAL (reference-digits-v1) round's cohort entry only: the chain tip the commit step saw when it committed this cohort -- the height, and the 80-byte block header (160 lowercase hex digits) two independent readers returned for it. A verifier checks the header is an ANCESTOR inside the round's proof P (the header at index `height - anchor.height` of P): the proof of work alone then shows the cohort was committed AFTER that block existed. That it was committed BEFORE block H existed rests on this entry's `.net`-attested `recorded_at`, not on anything here. OPTIONAL, and absent from a beacon round's entry and from every entry recorded before this member existed (so each stays valid byte for byte); closed, and it holds a height and a header and nothing that could name a participant.
heightintegerrequiredThe block height of the tip the commit step recorded.
headerstringrequiredThat block's 80-byte header, lowercase hexadecimal, unprefixed.
zk_rootTicketBatch_nullableDigestrequiredADR 0063 §2.2-2.3: the parallel Poseidon-family root (matching `circomlib`/`poseidon-lite`, the libraries Semaphore v4 and zk-kit use) over the SAME ticket leaves as `cohort_root`, reserved for a future ZK circuit stack. REQUIRED, NULLABLE: null until a producer computes one, never absent -- ADR 0063 §2.1's own text. On-chain, `IParticipationLedger.commitCohortRoot`'s `zkRoot` parameter uses `bytes32(0)` as the same 'not yet computed' sentinel (its own doc comment); this kernel record uses JSON `null` for the identical fact because, unlike the chain event, this format CAN express null and `03` §1.4's no-optional-field rule prefers an explicit null over a chain-style zero-value sentinel wherever the encoding allows it.