Aira

Compliance Bundles (EU AI Act Art 12)

Cryptographic snapshot of every receipt in a period — what an auditor verifies offline. Merkle-rooted, signed, framework-mapped, self-contained JSON.

Bundle vs Report. A bundle is a machine-readable JSON file an auditor verifies offline. A Compliance Report is the human-readable PDF derived from the same data. Most teams produce both. See The Five Aira Sub-Products for the full taxonomy.

What it is

A compliance bundle is a sealed snapshot of every action receipt in a date range, organized to satisfy a specific regulatory framework's audit log requirements. Each bundle:

  • Lists every receipt in the period in deterministic order.
  • Builds a SHA-256 Merkle root over the receipts' payload hashes (RFC 6962 domain separation).
  • Signs the bundle metadata with the active Aira signing backend (Ed25519 today).
  • Optionally attaches an RFC 3161 timestamp token from an independent timestamping authority.
  • Embeds the JWKS URL so the recipient can verify the bundle offline against the published public key.

The exported document is self-contained: an auditor downloads one JSON file and can re-run every verification step with OpenSSL. They never have to call Aira again.

Supported frameworks

FrameworkIdentifierWhat it maps
EU AI Act, Article 12eu_ai_act_art12Period of use, input/output hashes, system identifier, instruction hash, natural persons in the loop, policy decision chain, tamper-evidence
ISO/IEC 42001:2023iso_42001A.6.2.6 documentation, A.6.2.7 logging, A.7.4 performance management, A.9.4 stakeholder accountability
AIUC-1aiuc_1Tamper-evident audit log, cryptographic proof of human approval, independently verifiable signatures
SOC 2 Common Criteria 7soc_2_cc7CC7.1 logging, CC7.2 detection, CC7.3 response
Raw bundlerawNo framework mapping; every receipt verbatim

If you need a framework that isn't on the list, use raw and apply your own mapping post-hoc — every receipt's signed payload is included.


Create a bundle

Dashboard

Dashboard → Compliance → Seal new bundle. Pick a framework, a date range, optional title, and (optionally) an agent filter. The bundle is sealed immediately and you land on the detail page where you can download the JSON.

API

curl -X POST https://api.airaproof.com/api/v1/compliance/bundles \
  -H "Authorization: Bearer aira_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "framework": "eu_ai_act_art12",
    "period_start": "2026-01-01T00:00:00Z",
    "period_end": "2026-04-01T00:00:00Z",
    "title": "Q1 2026 evidence packet",
    "agent_filter": ["payments-agent", "support-agent"]
  }'

The response includes the bundle id, Merkle root, signature, framework summary, and signing key id.


Download the self-contained JSON

curl https://api.airaproof.com/api/v1/compliance/bundles/<bundle_uuid>/export \
  -H "Authorization: Bearer aira_live_xxx" \
  -o aira-compliance.json

The exported document inlines every receipt's signed_payload and signature, plus the Merkle root, the bundle signature, the public key, the JWKS URL, and a verification recipe. This is the artifact you ship to a regulator.


Verify the bundle offline

import json
import hashlib
import base64
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

LEAF_PREFIX = b"\x00"
NODE_PREFIX = b"\x01"

def merkle_root(payload_hashes: list[str]) -> str:
    """RFC 6962-style Merkle root over receipt payload hashes."""
    if not payload_hashes:
        return hashlib.sha256(b"").hexdigest()

    level = [hashlib.sha256(LEAF_PREFIX + ph.encode()).digest() for ph in payload_hashes]
    while len(level) > 1:
        if len(level) % 2 == 1:
            level.append(level[-1])
        level = [
            hashlib.sha256(NODE_PREFIX + level[i] + level[i + 1]).digest()
            for i in range(0, len(level), 2)
        ]
    return level[0].hex()


with open("aira-compliance.json") as f:
    bundle = json.load(f)

# 1. Recompute the Merkle root
recomputed = merkle_root([r["payload_hash"] for r in bundle["receipts"]])
assert recomputed == bundle["merkle_root"], "Merkle root does not match — bundle tampered"
print("Merkle root verified:", recomputed)

# 2. Verify the bundle signature
pub_bytes = base64.b64decode(bundle["signing"]["public_key"])
pub_key = Ed25519PublicKey.from_public_bytes(pub_bytes)

bundle_metadata = {
    "org_uuid": bundle["org_uuid"],
    "framework": bundle["framework"],
    "period_start": bundle["period_start"],
    "period_end": bundle["period_end"],
    "receipt_count": bundle["receipt_count"],
    "merkle_root": bundle["merkle_root"],
    "agent_filter": bundle["agent_filter"],
    "sealed_at": bundle["sealed_at"],
    "alg": bundle["signing"]["algorithm"],
}
canonical = json.dumps(bundle_metadata, sort_keys=True, separators=(",", ":"))

sig_b64 = bundle["signature"].removeprefix("ed25519:")
sig_bytes = base64.urlsafe_b64decode(sig_b64)
pub_key.verify(sig_bytes, canonical.encode())
print("Bundle signature verified")

# 3. Verify each receipt
for r in bundle["receipts"]:
    receipt_canonical = json.dumps(r["signed_payload"], sort_keys=True, separators=(",", ":"))
    expected_hash = "sha256:" + hashlib.sha256(receipt_canonical.encode()).hexdigest()
    assert expected_hash == r["payload_hash"], f"Receipt {r['receipt_uuid']} payload mismatch"

    sig = base64.urlsafe_b64decode(r["signature"].removeprefix("ed25519:"))
    pub_key.verify(sig, receipt_canonical.encode())

print(f"All {bundle['receipt_count']} receipts verified")

If every assertion passes, the bundle is genuine. If any fails, you have proof of tampering.


Inclusion proofs

If you only want to prove that a single receipt was included in a bundle without holding the whole list, request a Merkle inclusion proof:

curl https://api.airaproof.com/api/v1/compliance/bundles/<bundle_uuid>/inclusion-proof/<receipt_uuid> \
  -H "Authorization: Bearer aira_live_xxx"
{
  "bundle_uuid": "...",
  "receipt_uuid": "...",
  "leaf_hash": "abc123...",
  "index": 42,
  "leaf_count": 1000,
  "siblings": ["...", "...", "..."],
  "merkle_root": "..."
}

A standalone verifier walks the siblings from the leaf to the root in O(log n) and confirms that the receipt was sealed into the bundle. This is useful when an auditor only cares about one specific event.


What gets verified

The bundle proves four things, end to end:

  1. Each receipt's signature is valid — the agent action it describes really happened with the data it describes.
  2. The Merkle root is consistent with the receipt list — no receipt was added or removed after sealing.
  3. The bundle metadata signature is valid — the framework, period, and agent filter were not tampered with.
  4. The RFC 3161 timestamp token (if attached) — Aira saw the bundle at a specific moment, witnessed by an independent timestamping authority.

Aira does not need to be online for verification. The recipient does not need an Aira account. Every verification step uses standard primitives (SHA-256, Ed25519, RFC 6962, RFC 3161, RFC 8037 JWKS) that any auditor's existing tooling already understands.

On this page