Your agent just produced a $4,200 trading signal. It referenced three on-chain oracles, scored a counterparty at 78, and recommended proceed_with_escrow. Two hours later the counterparty denies the conversation ever happened. You pull your server logs — and realize the agent's response was streamed, not stored, and the JSON you did save can be edited in your own database by anyone with shell access.
This is the problem AI output notarization solves.
In 2026, "the model said so" is not evidence. We need receipts. EVIDIQ Notary is the receipt layer. Every inference, every capability claim, every trust report leaves a tamper-evident fingerprint anchored on 0G Storage — verifiable by anyone holding the tx hash, recoverable for as long as the chain exists.
What 0G Storage Anchoring Means for AI Outputs
AI output notarization is the practice of stamping an AI inference — prompt, response, model id, and tool calls — and anchoring that stamp on decentralized storage so it cannot be silently edited or deleted. EVIDIQ Notary performs this on 0G Storage Aristotle (chain 16661) using keccak256 hashes, the @0gfoundation/0g-ts-sdk, and an on-chain root transaction.
Most teams we talk to in 2026 conflate "logging" with "notarizing." They are different beasts. A log line in PostgreSQL can be UPDATE'd; an S3 object can be versioned, but the bucket owner controls the keys. When that log is the only proof that an AI agent made a specific decision at a specific time, the defense collapses the first time an opposing party asks "show me the bytes."
Honest answer: we've shipped logging systems that we ourselves would not trust as evidence in a $4,200 dispute. That's the gap 0G Storage closes — not by being fancier, but by removing your admin keys from the trust equation.
The Upload Flow: ZgFile to 0G Mainnet
Here's the actual receipt shape before it leaves the EVIDIQ side:
{
"report_id": "0x9f3c…",
"agent_id": "0x8004…",
"trust_score": 78,
"model": "anthropic/claude-3.5-sonnet",
"prompt_hash": "0xab12…",
"response_hash": "0xcd34…",
"verdict": "proceed_with_escrow",
"ts": "2026-03-14T09:22:11Z"
}
We canonicalize that object with a deterministic key order, compute its keccak256, and serialize to a temp file. Then the upload runs in four steps:
ZgFile.fromFilePath(tempPath)— wraps the bytes into the 0G chunked file format.indexer.upload(zgFile, { turbo: true })— pushes to 0G Storage via the indexer node. We hold a 30-second timeout budget because notary calls sit inline in agent hot paths.- On success, the indexer returns
{ root: "0x…", tx: "0x…" }— the storageRoot is the merkle root of the chunk tree, and storageTx is the on-chain transaction that committed it. - The receipt is then signed with the EVIDIQ EIP-191 key and the storageTx is recorded alongside the signed payload.
If the indexer errors or stalls past 30s, we fall back to the non-turbo path (turbo: false), which is roughly 2x slower on the median upload but doesn't drop on rate limits. The turbo indexer is the fast lane; the non-turbo path is the safety net. We've never lost a receipt in production — but the fallback exists because inference workloads don't tolerate 504s gracefully.
Two things worth flagging:
- The hash is canonical, not the JSON. If a verifier rebuilds the JSON with different whitespace, the keccak won't match. We pin the canonicalization rule in our verifier — same key order, no trailing newline, UTF-8 NFC.
- The storageRoot is the merkle root of the chunks, not the hash of the file. Anyone holding
storageTxcan re-fetch the chunks, recompute the root, and confirm it matches the on-chain event log. That's what makes AI output notarization auditable rather than merely timestamped.

Why Decentralized Storage Beats a Database for Audit Trails
A traditional audit log — Postgres, Mongo, even an immutable S3 bucket with Object Lock — has a structural weakness: a single party holds the keys.
If you're the one defending the decision, your own log is "self-serving evidence." If you're the one challenging it, the defense is "you could have edited it." Both arguments are technically possible, and that's the point — plausible editability is enough to kill a dispute.
A 0G Storage anchor flips this:
- The data lives on a decentralized network run by independent node operators. No single admin can rewrite it.
- The merkle root and storageTx are recorded on-chain — public, queryable by anyone with a block explorer.
- Any third party can re-fetch the chunks, recompute the keccak256, and verify the EVIDIQ signature in isolation.
We think of it as the difference between "I have a screenshot of my dashboard" and "here's the block explorer link." The first requires trust in the screenshotter; the second requires only a chain explorer.
For AI agent audit trails specifically, this matters for three reasons:
- Inference logs are evidentiary. They prove what the agent decided and why, which becomes legally material the moment money or rights move.
- The agent's operator may be a different party from the verifier — so the verifier needs an anchor they don't control, which is the whole point of AI output notarization.
- Regulatory direction is clear. By 2026, EU AI Act enforcement is actively probing high-risk systems, and a notarized trail is the cheapest defense that survives cross-examination.
If you're already running EVIDIQ Sentinel for live trust scoring, the notarization layer is a one-line flag — same endpoint, same payload, persistent receipt. Full pipeline details live in the EVIDIQ Sentinel docs.
Six Tools, Four Free — the Notary MCP Surface
The Notary ships as an MCP server with six tools. Four are free, two are gated behind x402 micropayments. Here's the breakdown:
notarize_inference(free) — canonicalize a single inference, upload to 0G Storage, return the storageTx.notarize_batch(free) — same, but up to 100 receipts in one call. We use this internally to backfill historical agent runs.verify_attestation(free) — given a storageTx + canonical JSON, re-fetch chunks, recompute the merkle root, verify the EIP-191 signature.get_receipt(free) — read a previously stored receipt by report_id.notary_stats(paid, x402) — aggregate metrics: total receipts, last 24h volume, per-model breakdown. $0.002 per call.notary_pubkey(paid, x402) — returns the current EVIDIQ notary signing key plus its on-chain attestation. $0.002 per call.
The x402 flow uses the standard 402 Payment Required challenge with accepts[].amount per the x402 v2 spec, settled in USDT0 on X Layer. An agent calling notary_stats receives a 402, signs an EIP-3009 transferWithAuthorization, retries with the X-PAYMENT header, and gets the data. Two round-trips, no human in the loop.
For full schema details and the canonical JSON recipe, see the EVIDIQ Notary docs. If you're orchestrating notarization inside an agent runtime alongside Sentinel probes and Operator workflows, the EVIDIQ Operator docs show how the three layers compose.
Why paywall only those two? Because they reveal aggregate volume and the active signing key respectively — useful signals for an attacker probing the trust graph. Everything that anchors or verifies a specific receipt stays open. That's the design principle: writes and reads of individual evidence are public; bulk telemetry and key metadata carry a price.

