Skip to content
veraq

API Reference

The Open Record REST API.

Read the open record — the 32 entities behind every wave, outcome, and contribution.

Provisional

Component schemas are generated verbatim from @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 is commit_window_closed.

Error

A request error, named as a state (e.g. record_mismatch, commit_window_closed, not_found) — never a failure-of-luck.

codestringrequired

Machine-readable state.

messagestringrequired

Human-readable, exact, never alarmist.

open_record_refstring | null

Where applicable, the open-record entry the reader can cross-check.

Example response — every verifiable field (✓) is checkable against the open record

GET /waves/{id} — shape✓ verifiable
{
  "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.

GET/waves

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

GET/waves/{id}

A round of participation. Runs one mechanism; contains many participations; resolves to outcomes.

Parameters

  • idpath · requiredThe wave id.

Responses

Wave

A round of participation. Runs one mechanism; contains many participations; resolves to outcomes.

idstringrequired

Sequential wave identifier, zero-padded.

opens_atstringrequired

When participants may begin seating.

closes_atstringrequired

Last moment to seat a participation. Must be ≥ opens_at.

resolves_atstringrequired

When the mechanism seed is revealed and the outcome resolves. Must be ≥ closes_at.

mechanism_idstringrequired

ULID reference to the published mechanism for this wave. The mechanism is published — including its seed commitment — before the wave opens.

seatsobjectrequired
totalintegerrequired
takenintegerrequired
charitable_sharenumberrequired

Fraction of the wave's outcome that flows to the beneficiary cause. Expressed in [0, 1], e.g. 0.12 == 12%.

beneficiary_cause_idstringrequired

Slug of the verified cause receiving the charitable share.

statusenumrequiredannounced · open · resolving · settled · cancelled

Wave 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.

GET/mechanisms

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

GET/mechanisms/{id}

The published selection rule (commit-reveal-v1), committed to the open record before a wave runs.

Parameters

  • idpath · requiredThe mechanism id.

Responses

Mechanism

The published selection rule (commit-reveal-v1), committed to the open record before a wave runs.

idstringrequired

ULID of this mechanism document.

algorithmstringrequired

Identifier of the algorithm spec in the veraq-protocol repository.

parametersobject

Algorithm-specific parameters. Shape is determined by the algorithm field and validated by the spec in veraq-protocol/algorithms/<algorithm>.md.

seed_commitmentstringrequired

Lowercase hex SHA-256 of (seed || parameters_canonical_json). Binding commitment published before the wave opens.

seed_revealedstring | null

Lowercase 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_atstringrequired

When the commitment was published. Must be < the linked wave's opens_at.

revealed_atstring | null

When seed_revealed was published. Null while undisclosed; ≥ wave.resolves_at when set.

verifying_transcript_urlstring | null

Optional URL to a verifying transcript (re-run output) for additional inspectability.

Participant

A person taking part. Makes participations; chooses a cause.

GET/participants

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

GET/participants/{id}

A person taking part. Makes participations; chooses a cause.

Parameters

  • idpath · requiredThe participant id.

Responses

Participant

A person taking part. Makes participations; chooses a cause.

idstringrequired

Stable participant identifier (ULID).

verdify_identity_idstringrequired

Foreign 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 | null

Optional public-facing handle. May be null for participants who choose not to display one.

created_atstringrequired

When the participant first seated.

verified_atstring | null

When identity verification was completed, if applicable. Null if unverified.

Participation

One participant's entry into a wave; written to the open record.

GET/participations

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

GET/participations/{id}

One participant's entry into a wave; written to the open record.

Parameters

  • idpath · requiredThe participation id.

Responses

Participation

One participant's entry into a wave; written to the open record.

idstringrequired

Wave-scoped participation id. Format: wave_id, hyphen, 4-character suffix.

wave_idstringrequired
participant_pseudonymstringrequired

Replaces `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_atstringrequired
weightnumber

Optional weighting used by weighted-selection mechanisms. Omitted means weight = 1.

kindenumcontributor · recipient

ADR 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 | null

Optional 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.

GET/outcomes

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

GET/outcomes/{id}

What a wave resolves to. A defined share routes to a contribution.

Parameters

  • idpath · requiredThe outcome id.

Responses

Outcome

What a wave resolves to. A defined share routes to a contribution.

idstringrequired

Wave-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_idstringrequired
recipient_participation_idstringrequired

The participation selected by the mechanism. The participant behind it can be looked up via the participation record.

mechanismobjectrequired

Snapshot 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_idstringrequired
algorithmstringrequired
seed_revealedstringrequired
verifying_transcript_sha256string | null

Optional content hash of the verifying transcript, if one was published.

verifiedbooleanrequired

Whether at least one independent verifier has replayed the mechanism and matched the recipient. Outcomes are not considered fully settled until verified == true.

settled_atstringrequired

Contribution

The defined share routed to a cause, derived from an outcome.

GET/contributions

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

GET/contributions/{id}

The defined share routed to a cause, derived from an outcome.

Parameters

  • idpath · requiredThe contribution id.

Responses

Contribution

The defined share routed to a cause, derived from an outcome.

idstringrequired
outcome_idstringrequired

The 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_idstringrequired
amountobjectrequired
valuestringrequired

Decimal string. Stored as string to avoid floating-point precision loss.

currencystringrequired

ISO-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 | null

When the transfer was confirmed. Null while pending.

proof_urlstring | null

Optional URL to a third-party transfer proof — bank receipt, on-chain transaction, etc.

Cause

A verified public-good recipient of contributions chosen by participants.

GET/causes

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

GET/causes/{id}

A verified public-good recipient of contributions chosen by participants.

Parameters

  • idpath · requiredThe cause id.

Responses

Cause

A verified public-good recipient of contributions chosen by participants.

idstringrequired

Stable slug. Used wherever a cause is referenced.

namestringrequired
descriptionstringrequired
verificationobjectrequired

How this cause was verified as eligible to receive charitable share. The brand promise requires this to be inspectable.

methodenumrequiredregistry · manual-review · third-party-attestation

How verification was performed.

registrystring | null

When method == 'registry', the registry identifier (e.g., 'gs1-charities-uk:1148231').

verified_atstringrequired
verifierstringrequired

Name or identifier of the verifying party.

evidence_urlstring | null
payout_addressobject

Where 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_jurisdictionstringrequired

ADR 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').

GET/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'). 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

GET/allocations/{id}

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

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').

idstringrequired

Identity. 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_idstringrequired

The 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_idstringrequired

The 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_positiveQuantityrequired

The 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_instantrequired

When 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.

GET/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. 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

GET/attestations/{id}

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

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.

idstringrequired

Identity. 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_idstringrequired

The 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.

attesterstringrequired

WHO 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 · mismatch

What 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_digestobjectrequired

The 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_instantrequired

When 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.

GET/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. 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

GET/challenges/{id}

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

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.

idstringrequired

Identity. 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_idstringrequired

The 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 | null

The 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_instantrequired

When 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.

GET/commitments

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

GET/commitments/{id}

What was pinned before a container opened, per container, discriminated on verification form.

Parameters

  • idpath · requiredThe commitment id.

Responses

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.

idstringrequired

Identity.

container_idstringrequired

The container this commitment belongs to. 03 §1.2: a PER-CONTAINER Commitment.

formobjectrequired
published_atCommitment_instantrequired

When 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_digestrequired

The 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 | nullrequired

Lowercase hex of the revealed seed. NULL until the reveal, present after — never absent, per 03 §1.4.

revealed_atobjectrequired

When the seed was revealed. Null until then.

transcript_digestCommitment_nullableDigestrequired

Digest 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.

idstringrequired

Identity.

container_idstringrequired

The container this commitment belongs to. 03 §1.2: a PER-CONTAINER Commitment.

formobjectrequired
published_atCommitment_instantrequired

When 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_digestrequired

Digest 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_nullableDigestrequired

Digest 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.

GET/containers

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

GET/containers/{id}

A cohort with a freeze predicate.

Parameters

  • idpath · requiredThe container id.

Responses

Container

A cohort with a freeze predicate.

idstringrequired

Identity. 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_idstringrequired

Provenance: 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_instantrequired

The 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_onobjectrequired

The 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 · cancelled

The 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.

termsobjectrequired

A 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_bearingbooleanrequired

True 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_windowstring

The 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_offerobject

WHAT 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_digeststringrequired

canonical-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_idstringrequired

The 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.

GET/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. 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

GET/containerclasstotals/{id}

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

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_idstringrequired

The 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_idstringrequired

One 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_nonNegativeAmountrequired

The 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).

currencystringrequired

ISO-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.

GET/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. 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

GET/drawarchives/{id}

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

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_idstringrequired

The container this draw resolves.

spec_digestDrawArchive_drawArchiveDigestrequired

Digest of the mechanism spec this draw was performed under.

cohort_rootDrawArchive_drawArchiveDigestrequired

The 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_roundintegerrequired

The 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_hexBytesrequired

The beacon round's own BLS12-381 (drand `quicknet`) or BN254 (`evmnet` fallback) signature, exactly as submitted to `IRandomnessSource.fulfil`.

beacon_public_keyDrawArchive_hexBytesrequired

The 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>required

Known-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.

GET/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. 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

GET/drawresultcorrectionentries/{id}

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

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_idstringrequired

The container (draw) this result is for.

draw_archive_digestDrawResultCorrectionEntry_drawResultDigestrequired

The digest of the container's `draw_archive_v1` payload: the result is the one the archive determines.

winning_selectionobjectrequired

The winning numbers per pool id, as the archive's derivation determines them.

tiersarray<DrawResultCorrectionEntry_drawResultTier>required

One row per award tier of the container's award structure, in the structure's order.

pool_total_minorDrawResultCorrectionEntry_drawResultMinorrequired

The pool of exactly the issued, not-returned orders.

beacon_roundintegerrequired

The 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 | nullrequired

The 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_drawResultMinorrequired

Carried 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_drawResultMinorrequired

The 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_drawResultMinorrequired

The 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_countintegerrequired

The 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_currencystringrequired

The ledger currency every amount in this payload is in.

awards_rootDrawResultCorrectionEntry_drawResultDigestrequired

The Merkle root over every line's `(ticket_digest, line_no, tier_id, amount_minor)`, by the rule in this schema's own description.

supersedesstringrequired

The 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_refstringrequired

The 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.

GET/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. 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

GET/drawresultentries/{id}

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

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_idstringrequired

The container (draw) this result is for.

draw_archive_digestDrawResultEntry_drawResultDigestrequired

The digest of the container's `draw_archive_v1` payload: the result is the one the archive determines.

winning_selectionobjectrequired

The winning numbers per pool id, as the archive's derivation determines them.

tiersarray<DrawResultEntry_drawResultTier>required

One row per award tier of the container's award structure, in the structure's order.

pool_total_minorDrawResultEntry_drawResultMinorrequired

The pool of exactly the issued, not-returned orders.

beacon_roundintegerrequired

The 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 | nullrequired

The 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_drawResultMinorrequired

Carried 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_drawResultMinorrequired

The 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_drawResultMinorrequired

The 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_countintegerrequired

The 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_currencystringrequired

The ledger currency every amount in this payload is in.

awards_rootDrawResultEntry_drawResultDigestrequired

The 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.

GET/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. 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

GET/drawvoidentries/{id}

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

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_idstringrequired

The voided draw (container).

commit_line_atDrawVoidEntry_drawVoidInstantrequired

The 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).

GET/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). 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

GET/funds/{id}

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

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).

idstringrequired

Identity. 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_jurisdictionstringrequired

ISO 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 · additional

Which 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 | nullrequired

The 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.

GET/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. 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

GET/fundings/{id}

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

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.

idstringrequired

Identity. 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_idstringrequired

The 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_positiveQuantityrequired

The 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_instantrequired

When 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).

GET/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). 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

GET/jurisdictionbalancecommitments/{id}

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

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_idstringrequired

The 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_idstringrequired

The 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_digestrequired

SHA-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.

GET/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. 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

GET/outcomecertificates/{id}

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

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_digestrequired

A 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 · counted

Which 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_digestrequired

Digest of the `OutcomeSpec` this certificate resolves under (ADR 0062 §2.1), registered into `IMechanismRegistry` before the container's `opens_at`.

container_idstringrequired

The container this certificate settles.

cohort_rootOutcomeCertificate_digestrequired

The 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.

sourcestringrequired

The 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.

observationobjectrequired
valuestringrequired

The 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).

unitstringrequired

The value's unit, or an empty string for a dimensionless/enumerated outcome.

as_ofOutcomeCertificate_instantrequired

The authority's own as-of time for the observed value, per the spec's `as_of` rule.

etagstring | nullrequired

The 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 | nullrequired

The source response's Last-Modified header, if any.

http_statusintegerrequired

The source response's HTTP status code at capture time.

evidencearray<OutcomeCertificate_evidenceCore>required

One 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>required

The 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.

policyobjectrequired
nintegerrequired

The observer committee size this certificate was resolved under.

tintegerrequired

The agreement threshold -- ADR 0062 §2.1: t >= floor(n/2)+1, t >= 2, n odd, once n > 1.

agreement_ruleobjectrequired

ADR 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_disclosedstringrequired

A 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 · final

ADR 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`.

timesobjectrequired
anchored_atOutcomeCertificate_instantrequired

When 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_instantrequired

When this certificate was issued (provisional).

challenge_window_closes_atOutcomeCertificate_instantrequired

The end of the bonded challenge window (ADR 0062 §2.1) -- `finalized_at` is null before this instant.

finalized_atobjectrequired

When `status` became `final`. Null while `status` is `provisional` -- never absent, per `03` §1.4's no-optional-field rule.

revisionobjectrequired
authority_statusenumrequiredprovisional · final · unknown

The 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_digestrequired

The `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_statementstringrequired

ADR 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>required

The 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).

GET/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). 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

GET/participationpartitionreports/{id}

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

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_idstringrequired

The 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_digestrequired

The 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.

GET/payoutrails

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

GET/payoutrails/{id}

A discriminated payout-rail taxonomy.

Parameters

  • idpath · requiredThe payoutrail id.

Responses

PayoutRail

A discriminated payout-rail taxonomy.

BankIbanRail

kindobjectrequired
ibanstringrequired

ISO 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

kindobjectrequired
addressstringrequired

A 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

kindobjectrequired
handlestringrequired

Deliberately 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').

GET/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'). 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

GET/policybindings/{id}

`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

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_idstringrequired

Identity — 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.

marketstringrequired

ISO 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 · withdrawn

This 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_bystringrequired

The 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 | nullrequired

The 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 | nullrequired

The 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 | nullrequired

The 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_refobject

ADR 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_idstringrequired

The 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.

versionintegerrequired

The profile's version, a positive integer within Rule N1's range. A changed profile is a new version, never an edit.

digeststringrequired

SHA-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.

GET/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. 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

GET/publicresultobservations/{id}

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

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.

sourceobjectrequired

The 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_authoritystringrequired

WHICH 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_urlstringrequired

WHERE the authority publishes the figure -- the exact URL a third party re-fetches to check `observed_value` independently.

fieldstringrequired

The 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.

formatstringrequired

The 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_close

WHICH 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 | nullrequired

The 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_publicResultObservationDigest

ADDITIVE (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 | nullrequired

The 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_fromstringrequired

WHERE 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_instantrequired

WHEN 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_publicResultObservationDigestrequired

The 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_instantrequired

WHEN `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_instantrequired

WHEN `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.

GET/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. 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

GET/referencedrawresultentries/{id}

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

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_idstringrequired

The container (round) this result is for.

anchor_heightintegerrequired

T: the binding's anchor height (the round's terms, `reference.anchor_height`). `headers[0]` is the anchor's own header.

reference_heightintegerrequired

H: 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_drawResultDigestrequired

The 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_drawResultDigestrequired

SHA-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>required

P: 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_selectionobjectrequired

The winning numbers per pool id, as `reference-digits-v1` derives them from `block_hash` and the cohort root.

tiersarray<ReferenceDrawResultEntry_drawResultTier>required

One row per award tier of the container's award structure, in the structure's order.

pool_total_minorReferenceDrawResultEntry_drawResultMinorrequired

The pool of exactly the issued, not-returned orders.

carry_in_minorReferenceDrawResultEntry_drawResultMinorrequired

Carried 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_drawResultMinorrequired

The 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_drawResultMinorrequired

The rounding remainder no line can be credited; it leaves this round's pool with `carry_out_minor`, as in `draw_result_v1`.

line_countintegerrequired

The 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_currencystringrequired

The ledger currency every amount in this payload is in.

awards_rootReferenceDrawResultEntry_drawResultDigestrequired

The 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.

GET/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. 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

GET/reserveobligations/{id}

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

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.

idstringrequired

Identity. 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_jurisdictionstringrequired

ADR 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_idstringrequired

The 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.

currencystringrequired

The 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_versionstringrequired

The 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_versionstringrequired

The 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_positiveQuantityrequired

The 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_nonNegativeQuantityrequired

Income 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_nonNegativeQuantityrequired

Fees 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_statusobjectrequired

ADR 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.

valueobjectrequired

Defaults 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_instantrequired

Effective-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_digestrequired

Evidence-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_statusstringrequired

ADR 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>required

The 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".

GET/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". 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

GET/resultobservations/{id}

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

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".

idstringrequired

Identity. 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_idstringrequired

The 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_resultDigest

ADDITIVE (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_fromstringrequired

WHERE — the location actually read (the pinned `ResultSource.publication_url`, or the archived capture reached in its place).

fetched_atResultObservation_instantrequired

WHEN — the moment of the capture this provenance describes.

fetched_bystringrequired

BY 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_countintegerrequired

The 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>required

EVERY 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_instantrequired

WHEN `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_instantrequired

WHEN 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".

GET/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". 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

GET/resultsources/{id}

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

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_authoritystringrequired

WHICH 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_urlstringrequired

WHERE 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.

fieldstringrequired

The 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.

formatstringrequired

The 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_close

WHICH 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_declarationobjectrequired

Five 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.

GET/sealedcommitmententries

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

GET/sealedcommitmententries/{id}

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

SealedCommitmentEntry

ADR 0071 §2.1's `sealed_commitment_v1` entry_kind payload -- the `.net` carrier of a beacon-bound container's SealedCommitment.

container_idstringrequired

The container this SealedCommitment binds.

terms_digestSealedCommitmentEntry_sealedCommitmentDigestrequired

The digest of the container's terms (`terms.randomness` carries B's fields, so the published terms recompute `seed_commitment`).

seed_commitmentSealedCommitmentEntry_sealedCommitmentDigestrequired

SHA-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).

GET/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). 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

GET/selections/{id}

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

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_versionobjectrequired
kindobjectrequired
valueSelection_quantityrequired

BandSelection

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_versionobjectrequired
kindobjectrequired
option_idstringrequired

Opaque, 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_versionobjectrequired
kindobjectrequired
valueSelection_isoDaterequired

NumberSetSelection

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_versionobjectrequired
kindobjectrequired
picksobjectrequired

The 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).

GET/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). 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

GET/ticketbatches/{id}

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

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_idstringrequired

The container this batch belongs to.

terms_digestTicketBatch_digestrequired

Digest 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_seqintegerrequired

Dense, 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_sizeintegerrequired

The 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_digestrequired

This 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_digestrequired

The 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_tipobject

ADR 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.

heightintegerrequired

The block height of the tip the commit step recorded.

headerstringrequired

That block's 80-byte header, lowercase hexadecimal, unprefixed.

zk_rootTicketBatch_nullableDigestrequired

ADR 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.