Schemas

The six H2A schemas are JSON Schema Draft 2020-12. Every $id resolves under https://h2a-protocol.org/schemas/v0/, so a validator can fetch them directly. Each object below lists its fields — type, whether it is required, and what it means — followed by a real example taken straight from the repository.

Every example shown is checked in CI by scripts/validate-schemas.py: the validated ones must pass their schema, and the two counter-examples (decision-record.INVALID, memory.derived.INVALID) must be rejected. The tables and examples on this page are generated from the schema files at build time, so they cannot drift from the schemas they describe.

Grant h2a-core.grant raw ↗

Authority for a grantee (operator) to use a subject within a bounded scope, revocable at point of use. Central H2A-Core object. iss MUST resolve under a rights-holder or fiduciary namespace, MUST NOT resolve under the operator's domain, and SHOULD NOT resolve under the implementer's domain (ADR-001).

FieldTypeReqDescription
h2a_version0.1 const
grant_idstring · UUIDUnique grant identifier; also serves as the jti for replay protection (ADR-004).
issstring · uriIssuer identity URI under a rights-holder / fiduciary namespace. Not operator; not implementer.
subject_refstring · subject URNKey-bound URN of the governed subject (digital actor / likeness / memory principal).
grantee_refstring · grantee URNAuthenticated operator identity the grant is issued to (ADR-004).
scopeobject
profilesarray of h2a-media h2a-memory h2a-commercialWhich profiles apply to this grant. 'h2a-commercial' (SPEC-COMMERCIAL) is optional and never a Core conformance requirement (ADR-012).
leaseobjectBudget Authority — cross-provider spend cap enforced as a lease, not a counter.
statusobject
revocation_horizonstring · ISO 8601 durationDeclared maximum time from revocation to non-conformant-transmission cutoff. The single conformance dial. ISO 8601 duration.
delegationobjectAttenuation-only delegation chain (ADR-004). A child grant may only narrow scope.
exposureobjectOptional commercial-profile extension (SPEC-COMMERCIAL / h2a-commercial). Opaque to Core: its shape is constrained by h2a-commercial.profile.schema.json only when this grant lists 'h2a-commercial' in profiles. Not a Core conformance requirement (ADR-012). A verifier that does not implement the commercial profile MUST ignore this field and MUST NOT refuse the grant because it is present.
algES256 ES384 EdDSA · default ES256Signature algorithm. ES256 (P-256) is mandatory-to-implement; curve-agnostic via this header.
signaturesarray of objectTwo detached signatures (ADR-004): consent (by subject/custodian) and issuance (by issuer). Kept separate so consent and issuance never collapse into one act. Exactly one of each role, enforced below — minItems/maxItems alone admitted two consent signatures and no issuance, which is the collapse this separation exists to prevent.
iatstring · date-time
nbfstring · date-timeNot-before. REQUIRED: without it a verifier cannot decide whether the grant is yet in force, so a grant lacking nbf is schema-valid and un-evaluable. Implementations already reject its absence (bridle packages/core/src/verify.ts) — the schema was the one permitting it.
expstring · date-time

scope

FieldTypeReqDescription
purposesarray of string
media_typesarray of string
territoriesarray of stringISO 3166-1 alpha-2 or 'GLOBAL'.
channelsarray of string
exclusionsarray of stringHard denials, e.g. political, adult, defamatory.

lease

FieldTypeReqDescription
capnumber · > 0
unitstringe.g. 'usd', 'render-seconds', 'tokens'.
provider_agnosticboolean · default true
nbfstring · date-time
expstring · date-time

status

FieldTypeReqDescription
uristring · uriPrimary status-list URI. MUST resolve under the issuer's own endpoint, never the Foundation's.
mirrorsarray of string · uriAdditional CDN mirror URIs of the same signed list.
indexinteger · ≥ 0This grant's bit position in the status list.

delegation

FieldTypeReqDescription
parentstring | nullgrant_id of the parent, or null at chain root.
depthinteger · ≥ 0
effective_chain_horizonstringRealised horizon of the whole chain = max of all links (a chain is only as revocable as its slowest link).
max_chain_horizonstringCeiling the chain may not exceed.

signatures[] — each item

FieldTypeReqDescription
roleconsent issuance
kidstring
valuestringbase64url detached signature over the canonicalised grant.
✓ validated · example · grant.valid.json
{
  "h2a_version": "0.1",
  "grant_id": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f",
  "iss": "https://issuer.example.org/h2a/issuer",
  "subject_ref": "urn:h2a:subject:jane-actor-001",
  "grantee_ref": "urn:h2a:grantee:example-operator",
  "scope": {
    "purposes": ["promotional-video"],
    "media_types": ["video"],
    "territories": ["GB", "US"],
    "channels": ["social", "web"],
    "exclusions": ["political", "adult", "defamatory"]
  },
  "profiles": ["h2a-media"],
  "lease": { "cap": 500, "unit": "usd", "provider_agnostic": true, "nbf": "2026-07-16T00:00:00Z", "exp": "2026-10-16T00:00:00Z" },
  "status": {
    "uri": "https://issuer.example.org/h2a/status/2026-q3.json",
    "mirrors": ["https://cdn.example.net/h2a/status/2026-q3.json"],
    "index": 42
  },
  "revocation_horizon": "PT30M",
  "delegation": { "parent": null, "depth": 0, "effective_chain_horizon": "PT30M", "max_chain_horizon": "PT1H" },
  "alg": "ES256",
  "signatures": [
    { "role": "consent", "kid": "subject-key-1", "value": "BASE64URL_CONSENT_SIG" },
    { "role": "issuance", "kid": "issuer-key-1", "value": "BASE64URL_ISSUANCE_SIG" }
  ],
  "iat": "2026-07-16T00:00:00Z",
  "nbf": "2026-07-16T00:00:00Z",
  "exp": "2026-10-16T00:00:00Z"
}

Attestation h2a-core.attestation raw ↗

Signed receipt of a single act of use, binding the committed output to the grant and to the point-of-use status check that authorised it.

FieldTypeReqDescription
h2a_version0.1 const
attestation_idstring · UUID
grant_idstring · UUID
subject_refstring · subject URN
grantee_refstring · grantee URN
output_hashstring · sha256SHA-256 of the committed output.
useobjectThe use this attestation actually attests: what was checked at the moment of the act, not what the grant permits in general. Optional so objects written before this field existed stay valid, but SHOULD be present — an attestation that does not say what use it attests records only that something happened, which is a decoration rather than evidence (Bridle defect B6). A verifier comparing this against the grant's scope is what makes the attestation checkable offline.
decision_record_refstringrecord_id of the Decision Record this attestation was emitted under. Optional for backwards compatibility, but without it the attestation and the decision that authorised it cannot be tied together by a third party — which is the join a stranger needs to verify the act offline.
generatorobjectWhat produced the output. The operator governs, never generates — generation is outsourced to a third-party generation provider via an implementer's adapter.
status_checkobjectThe check performed at the point of use. Never cached; always live.
algES256 ES384 EdDSA · default ES256
signaturestringbase64url signature over the canonicalised attestation.
created_atstring · date-time

use

FieldTypeReqDescription
purposestringThe single purpose checked, drawn from the grant's scope.purposes.
territorystringISO 3166-1 alpha-2 or 'GLOBAL'.
spendobjectWhat this act drew against the grant's lease, in the lease's own unit.

use.spend

FieldTypeReqDescription
amountnumber · ≥ 0
unitstringMUST match the grant's lease.unit; a spend in a different unit is not comparable to the cap.

generator

FieldTypeReqDescription
adapterstring
providerstring
modelstring

status_check

FieldTypeReqDescription
resultvalid refused
reason_codestringe.g. asset-revoked, out-of-scope, lease-exhausted.
checked_atstring · date-time
status_uristring · uri
witness_beaconstringReference to the external timestamp/beacon the check was bracketed against (ADR-005).
✓ validated · example · attestation.valid.json
{
  "h2a_version": "0.1",
  "attestation_id": "7c9e6a10-1111-4b2a-9c33-8a1b2c3d4e5f",
  "grant_id": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f",
  "subject_ref": "urn:h2a:subject:jane-actor-001",
  "grantee_ref": "urn:h2a:grantee:example-operator",
  "output_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "generator": { "adapter": "example-adapter", "provider": "example-provider", "model": "avatar-v3" },
  "status_check": {
    "result": "valid",
    "checked_at": "2026-07-20T14:03:00Z",
    "status_uri": "https://issuer.example.org/h2a/status/2026-q3.json",
    "witness_beacon": "beacon:2026-07-20T14:02:59Z:ab12"
  },
  "alg": "ES256",
  "signature": "BASE64URL_SIG",
  "created_at": "2026-07-20T14:03:01Z"
}

Decision Record h2a-core.decision-record raw ↗

The signed record of a conformant-vs-non-conformant transmission decision. First-class schema object (ADR-006): H2A evidences, it does not enforce. This is the most commercially significant artefact for union / CMO procurement leverage — a non-conformant downstream transmission is recorded here explicitly.

Conditional.
  • non_conformant_transmission is required when decision = TRANSMITTED_NON_CONFORMANT
FieldTypeReqDescription
h2a_version0.1 const
record_idstring · UUID
grant_idstring · UUID
decisionPERMITTED_CONFORMANT REFUSED_REVOKED REFUSED_OUT_OF_SCOPE REFUSED_LEASE_EXHAUSTED TRANSMITTED_NON_CONFORMANT
reason_codestring
output_hashstring · sha256
measured_latency_msinteger · ≥ 0Revocation-to-cutoff latency, measured at the issuer endpoint (not the operator), cross-checked against committed work.
effective_chain_horizonstringRealised horizon of the chain = max of all links.
max_chain_horizonstring
horizon_committed_msinteger · ≥ 0Committed revocation horizon in force for this act, in milliseconds. What was promised. Core evidence field; when the commercial profile applies it is the horizon of the grant's assurance_level.
horizon_measured_msinteger · ≥ 0Measured self-executor halt latency in milliseconds (ADR-006 as amended; ADR-013). What was delivered. Feeds the loss table. MAY be absent where a deployment does not yet instrument halt latency (see measured_latency_ms, which it supersedes for the SLA).
horizon_breachbooleanDerived: true when horizon_measured_ms > horizon_committed_ms. The SLA trigger. Absent when horizon_measured_ms is not populated.
chain_conformanceconformant non_conformant_downstream unknownTyped chain-conformance outcome for this act (formerly implicit in non_conformant_transmission).
exposure_snapshotobjectOptional commercial-profile extension (SPEC-COMMERCIAL / h2a-commercial): per-act limit, aggregate limit, aggregate consumed, and assurance_level at the time of the act. Opaque to Core; constrained by the commercial profile. Not a Core conformance requirement (ADR-012); verifiers that do not implement the commercial profile MUST ignore it.
non_conformant_transmissionobject | nullPresent and non-null ONLY when decision is TRANSMITTED_NON_CONFORMANT. Records a transmission that occurred outside conformance so it becomes admissible evidence.
witnessobjectExternal anchoring (ADR-005): RFC 3161 eIDAS-qualified TSA token + independent witness co-signature on the chain head. No blockchain.
created_atstring · date-time
algES256 ES384 EdDSA · default ES256
signaturestring

non_conformant_transmission

FieldTypeReqDescription
downstream_refstringIdentifier of the downstream executor / channel that transmitted non-conformantly.
whyhorizon_exceeded downstream_not_conformant check_bypassed
horizon_exceeded_by_msinteger · ≥ 0

witness

FieldTypeReqDescription
tsa_token_refstring
witness_cosign_refstring
✓ validated · example · decision-record.conformant.json
{
  "h2a_version": "0.1",
  "record_id": "9d1f2b30-2222-4b2a-9c33-8a1b2c3d4e5f",
  "grant_id": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f",
  "decision": "PERMITTED_CONFORMANT",
  "reason_code": "in-scope",
  "output_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "measured_latency_ms": 0,
  "effective_chain_horizon": "PT30M",
  "max_chain_horizon": "PT1H",
  "non_conformant_transmission": null,
  "witness": { "tsa_token_ref": "tsa:rfc3161:abc", "witness_cosign_ref": "witness:example:def" },
  "created_at": "2026-07-20T14:03:01Z",
  "alg": "ES256",
  "signature": "BASE64URL_SIG"
}
✓ validated · example · decision-record.non-conformant.json
{
  "h2a_version": "0.1",
  "record_id": "9d1f2b30-3333-4b2a-9c33-8a1b2c3d4e5f",
  "grant_id": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f",
  "decision": "TRANSMITTED_NON_CONFORMANT",
  "reason_code": "downstream-exceeded-horizon",
  "measured_latency_ms": 5200,
  "effective_chain_horizon": "PT30M",
  "max_chain_horizon": "PT1H",
  "non_conformant_transmission": {
    "downstream_ref": "channel:partner-cdn-eu",
    "why": "horizon_exceeded",
    "horizon_exceeded_by_ms": 3400
  },
  "witness": { "tsa_token_ref": "tsa:rfc3161:xyz", "witness_cosign_ref": "witness:example:uvw" },
  "created_at": "2026-07-20T14:35:00Z",
  "alg": "ES256",
  "signature": "BASE64URL_SIG"
}
✗ rejected · counter-example · decision-record.INVALID.json — TRANSMITTED_NON_CONFORMANT with no non_conformant_transmission block
{
  "h2a_version": "0.1",
  "record_id": "9d1f2b30-5555-4b2a-9c33-8a1b2c3d4e5f",
  "grant_id": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f",
  "decision": "TRANSMITTED_NON_CONFORMANT",
  "created_at": "2026-07-20T14:35:00Z",
  "alg": "ES256",
  "signature": "BASE64URL_SIG"
}

Status List h2a-core.status-list raw ↗

A static, signed revocation artefact served from the issuer's own endpoint (and optional CDN mirrors). Short-TTL and re-signed. The Foundation is never in this fetch path.

FieldTypeReqDescription
h2a_version0.1 const
status_list_idstring · UUID
issstring · uriIssuer namespace — same root as the grants it covers.
purposerevocation const
encodingbase64url-bitstring const
liststringbase64url-encoded, gzip-compressed bitstring. Bit set = revoked.
mirrorsarray of string · uri
valid_fromstring · date-time
valid_untilstring · date-timeShort TTL. A verifier treats an expired list as fail-closed.
algES256 ES384 EdDSA · default ES256
signaturestring
✓ validated · example · status-list.valid.json
{
  "h2a_version": "0.1",
  "status_list_id": "5a6b7c80-4444-4b2a-9c33-8a1b2c3d4e5f",
  "iss": "https://issuer.example.org/h2a/issuer",
  "purpose": "revocation",
  "encoding": "base64url-bitstring",
  "list": "eJzTBQAAMAAw",
  "mirrors": ["https://cdn.example.net/h2a/status/2026-q3.json"],
  "valid_from": "2026-07-20T00:00:00Z",
  "valid_until": "2026-07-20T01:00:00Z",
  "alg": "ES256",
  "signature": "BASE64URL_SIG"
}

Media Profile h2a-media.profile raw ↗

Asset-bound media profile. Not a Core requirement — applies only when a grant lists 'h2a-media'. C2PA composition lives here for multi-part supply chains.

FieldTypeReqDescription
h2a_version0.1 const
profileh2a-media const
grant_idstring · UUID
likeness_refstring · subject URN
assetobject
compositionarray of objectParent asset references for multi-part supply chains. Effective revocability of the composite = max horizon of all parts.
constraintsobjectModality-specific limits (e.g. no singing voice, no minors' likeness).

asset

FieldTypeReqDescription
asset_idstring
media_typeaudio video image 3d
content_hashstring · sha256
c2pa_manifest_refstringPointer to the C2PA manifest, if present.

composition[] — each item

FieldTypeReqDescription
asset_refstring
grant_refstring · UUID

constraints — open object (modality-specific keys)

✓ validated · example · media.valid.json
{
  "h2a_version": "0.1",
  "profile": "h2a-media",
  "grant_id": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f",
  "likeness_ref": "urn:h2a:subject:jane-actor-001",
  "asset": {
    "asset_id": "asset-991",
    "media_type": "video",
    "content_hash": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
    "c2pa_manifest_ref": "c2pa:urn:manifest:991"
  },
  "composition": [
    { "asset_ref": "asset-880", "grant_ref": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f" }
  ],
  "constraints": { "no_singing_voice": true }
}

Memory Profile h2a-memory.profile raw ↗

Memory-record profile. Applies only when a grant lists 'h2a-memory'. Enforces the negative test: a DERIVED memory record MUST carry non-empty provenance, or it is rejected.

Conditional.
  • provenance is required when record.memory_type = derived
FieldTypeReqDescription
h2a_version0.1 const
profileh2a-memory const
grant_idstring · UUID
subject_refstring · subject URN
recordobject
provenanceobject
retentionobject

record

FieldTypeReqDescription
record_idstring
memory_typeraw derived
content_hashstring · sha256

provenance

FieldTypeReqDescription
sourcesarray of object

provenance.sources[] — each item

FieldTypeReqDescription
source_refstring
methodstring

retention

FieldTypeReqDescription
retention_horizonstringISO 8601 duration.
deletion_on_revokeboolean · default true
✓ validated · example · memory.derived.valid.json
{
  "h2a_version": "0.1",
  "profile": "h2a-memory",
  "grant_id": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f",
  "subject_ref": "urn:h2a:subject:jane-actor-001",
  "record": { "record_id": "mem-1", "memory_type": "derived", "content_hash": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" },
  "provenance": { "sources": [ { "source_ref": "transcript:call-7", "method": "summarise" } ] },
  "retention": { "retention_horizon": "P90D", "deletion_on_revoke": true }
}
✗ rejected · counter-example · memory.derived.INVALID.json — derived record carrying no provenance
{
  "h2a_version": "0.1",
  "profile": "h2a-memory",
  "grant_id": "3f2a1c40-0d1e-4b2a-9c33-8a1b2c3d4e5f",
  "subject_ref": "urn:h2a:subject:jane-actor-001",
  "record": { "record_id": "mem-2", "memory_type": "derived", "content_hash": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" }
}