Agent Payment Attestation

Which agent, on what inputs, decided what. Check it yourself.

An agent decision ends up as one hash in one message on a public ledger. That hash means nothing unless you can rebuild it from the decision itself — the agent, the mandate it acted under, the parameters it was given. Below is a verifier, a real proof package and a real decision record. No account, no API key, no code of ours in the trust path.

What gets proven

Four hops, each recomputed from the record, not from our word.

Hop 0 · decision → commitment → leaf
The decision record and its payload key rebuild the commitment carried in the signed leaf message, and that message rebuilds the leaf hash. This is what ties a specific decision — agent, mandate, intent, inputs — to everything below it.
Hop 1 · leaf → batch root
The leaf hash and its sibling path rebuild the batch root. SHA-256 with an RFC 6962 internal-node tag.
Hop 2 · batch root → aggregate root
The batch roots are rebuilt into the aggregate root by an implementation written from the spec, sharing no code with the node that produced it.
Hop 3 · aggregate root → Hedera
That aggregate is read from Hedera's public mirror node and compared. A match means the decision existed before the consensus timestamp and has not changed since.
Run it

Four files, one command. Read the verifier first — it is short.

# Python 3, no dependencies
curl -sO https://rubric-protocol.com/docs/verify-apa.py
curl -sO https://rubric-protocol.com/docs/sample-proof.json
curl -sO https://rubric-protocol.com/docs/sample-record.json
curl -sO https://rubric-protocol.com/docs/sample-payload-key.txt

python3 verify-apa.py sample-proof.json sample-record.json \
  "$(cat sample-payload-key.txt)"
PASS hop0 leafMessage -> leafHash attestation_id: e3119e98-1c36-4e9b-a6a7-2379e7e14178 issued_at : 2026-07-31T00:30:34.670Z (issuer us) PASS hop0 your record -> payload_commitment agent : invoice-agent-07 intent : Pay supplier invoice INV-4419 amount : 250.00 USDC params : 3354d209319a4e2c90275987f29d79e131a232702ea334065d2408f176f8e9f1 PASS hop1 leaf -> batchRoot (1 step(s)) PASS hop2 batchRoot -> aggregateRoot (recomputed) PASS hop2 our batchRoot is among the anchored flushes PASS hop3 on-chain aggregateRoot matches package PASS hop3 on-chain aggregateRoot matches OUR recomputation consensus timestamp: 1785457894.978922104 topic / sequence : 0.0.10416909 / 282686 VERIFIED: leaf -> batch -> aggregate -> Hedera consensus.

That is a payment agent, acting under mandate mandate-acme-q3-2026, deciding to pay invoice INV-4419 for 250.00 USDC — bound to Hedera sequence 282686. Open sample-record.json and you will find the parameters the agent was actually given: destination, asset, invoice number, memo. The ledger holds none of that. It holds a commitment to it.

Read the verifier source →
The part that matters

It can fail. Here is it failing.

A verifier that always returns green proves nothing. On 30 July 2026 we found that anchors written under tree version 2 committed to the number of batches rather than their contents — logged as RUBRIC-SEC-2026-001, found by writing this script and refusing to make it agree with our own server. Anchors since carry a corrected construction. The verifier tells them apart:

curl -sO https://rubric-protocol.com/docs/sample-proof-weak.json
python3 verify-apa.py sample-proof-weak.json
PASS hop0 leafMessage -> leafHash attestation_id: 00930ea8-69d9-48ca-bcef-a2a767077ef7 issued_at : 2026-07-30T18:38:36.029Z (issuer us) PASS hop1 leaf -> batchRoot (1 step(s)) WARN treeVersion 2: this aggregate binds flush COUNT only, not content (RUBRIC-SEC-2026-001). Hop 2 cannot be verified. PASS hop3 on-chain aggregateRoot matches package consensus timestamp: 1785436745.796543249 topic / sequence : 0.0.10416909 / 282571 PARTIAL: hop 1 and the ledger anchor verify; hop 2 is not cryptographically bound for treeVersion 2 anchors.

Exit code 1. The signature, the leaf inclusion and the consensus timestamp still hold for those records — but the batch-to-aggregate step is our assertion rather than a proof, and the tool says so instead of showing a checkmark.

Read the specification →
Your own records

Same command, your agent's decisions.

# proof package — hashes and structure only
curl -H "x-api-key: $KEY" \
  .../verify/v1/proof/ATTESTATION_ID > proof.json

# the record itself — only the payload key opens it
curl -H "x-api-key: $KEY" -X POST \
  -d '{"attestationId":"...","payloadKey":"..."}' \
  .../verify/v1/payload-decrypt

python3 verify-apa.py proof.json record.json "$KEY_HEX"

The payload key is generated per attestation, returned to you once, and never retained by us. We cannot read your decision records; nor can anyone reading the ledger. You can hand the proof package to an auditor and prove an anchor exists, or hand them the record and key as well and prove exactly what your agent decided and on what inputs. The disclosure is yours to control, and the verification does not involve us either way.