AOTrust
Prove that a document, email, contract, AI output, source code file, or any other digital artifact existed at a specific time. Public cryptographic timestamping infrastructure for developers and AI agents: a verifiable receipt (PDR) for $0.01 via HTTP API or MCP.
What can be notarized?
The artifact itself is never uploaded - only its SHA-256 hash.
Developer quickstart
AOTrust exposes notarization through the HTTP API and MCP. A consumer web product exists as FreelanceShield (PDF certificate, $0.10/file).
- Compute hash -
hashlib.sha256(artifact).hexdigest(). Examples by artifact type: SKILL.md. - Pay & notarize - $0.01 USDC via x402 on Base (HTTP) or Base/Solana (MCP). Call
notary_notarize_paid(MCP) orPOST /notarize(HTTP). Free tier first:notary_free/POST /v1/shield/free(5 per 24 h per IP). - Track by job_id - keep the returned
job_id(UUID). Status:GET /v1/status/{job_id}; PDR:GET /v1/pdr/{job_id}orresult.pdr_b64. Verify at verify.aotrust.link.
# HTTP, x402 on Base
curl -si -X POST https://api.aotrust.link/notarize \
-H 'Content-Type: application/json' -d '{"work_hash":"<sha256 hex>"}'
# → 402 (amount=10000) → sign EIP-3009 → resend with x-payment → 200 {"pdr_b64":"…"}
Python SDK (free tier, no signup)
pip install aotrust-protocol
import asyncio, hashlib
from agent_notary import NotaryClient # base_url WITHOUT /v1 - SDK adds it
client = NotaryClient(base_url="https://api.aotrust.link")
r = await client.shield_free(hashlib.sha256(b"my artifact").hexdigest())
print(r["job_id"]) # keep this UUID - your handle
print((await client.get_status(r["job_id"])).status)
5 free receipts / 24 h per IP. Full example: aotrust_sdk_free.py.
Evidence bundle - $0.02 (audit-grade pack)
curl -si -X POST https://api.aotrust.link/v1/attestation/bundle \
-H 'Content-Type: application/json' -d '{"work_hash":"<sha256 hex>"}'
# → 402 (amount=20000) → pay → 200: pdr_b64 + anchor{mode, anchor_seq, size, root, near_tx, index, path[]}
# read-only: no new PDR is created
Payment rails
x402 - Base
$0.01 USDC · live
HTTP 402 + EIP-3009. Discovery: /.well-known/x402. No account, no API key.
x402 - Solana
$0.01 USDC · live (MCP)
SVM exact scheme, spl-token transferChecked + memo. Anchor type 0x0A X402_SOLANA.
NEAR_DIRECT
dynamic ~$0.01 · frozen
Rail kept for compatibility; tool available, no mainnet usage. 0x01 NEAR_DIRECT.
Free tier
$0 · 5 / 24 h
POST /v1/shield/free or MCP notary_free. No wallet, mainnet cryptography, the same hourly cumulative NEAR anchor as a paid receipt - the paid tier only removes the quota.
Buy an evidence bundle in 3 steps
An evidence bundle is a paid, read-only receipt pack for a hash we already notarized: we return the earliest issuance, the anchor that covers it, an RFC 9162 inclusion path and a step-by-step recipe to check it yourself. $0.02 USDC on Base, no account or API key.
Optional: pass seq to pin a specific issuance - we reject the request before any payment with 400 INVALID_SEQ or 400 SEQ_HASH_MISMATCH. Unknown hash → 404, nothing charged.
No wallet yet? The free tier (POST /v1/shield/free, 5 per 24 h) issues a real mainnet PDR without payment; the bundle adds the anchor proof and the earliest-issuance guarantee.
Current status (October 2026)
Production
PDR issuance · public verification · x402 on Base + Solana · hourly cumulative NEAR anchoring · anchor proof/consistency API · evidence bundle ($0.02) · signed time attestations ($0.002) · transparency log
Developer access
HTTP API · MCP (streamable-http) · agent integrations · SDK aotrust-protocol · JWKS / did:web
In development
Consumer UX polish · more catalog listings · Solana settlement checks
What is a PDR?
A PDR (Provenance Data Record) is a 239-byte cryptographic receipt that proves a specific digital artifact existed at a specific point in time. It is signed with Ed25519 (AOTrust signed message) and is a leaf in an append-only Merkle log anchored hourly to the NEAR blockchain.
MCP tools
MCP is fully operational: connect any MCP-compatible agent to https://api.aotrust.link/mcp, or use the HTTP API above.
| Tool | Description | Inputs | Returns |
|---|---|---|---|
| notary_quote | Get dynamic price quote | (none) | cost_usd_cents, cost_near_human, near_usd_rate, quote_id, quote_valid_until |
| notary_free | Free UNPAID PDR (no payment, no wallet; 5/day/IP) | work_hash | pdr_b64, job_id |
| notary_notarize | NEAR_DIRECT notarization (rail frozen) | work_hash, tx_hash, agent_pubkey | pdr_b64, job_id |
| notary_notarize_paid | x402 USDC on Base or Solana (live; HTTP /notarize is Base-only) | work_hash, agent_pubkey | pdr_b64, tx_hash, payment_anchor_type |
| notary_verify | Verify an existing PDR | pdr_b64 or work_hash | status, issuer, timestamp, signature_valid |
Complete current list: MCP tools/list or SKILL.md.
PDR format v2.3 / v2.4 (technical reference)
| Field | Size | Description |
|---|---|---|
| version | 1 | 0x03 (v2.3) or 0x04 (v2.4 bilateral) |
| sig_scheme | 1 | 0x01 = Ed25519 / AOTrust signed message |
| payment_anchor_type | 1 | Payment rail enum (0x00 unpaid, 0x01 NEAR_DIRECT, 0x05 X402_BASE, 0x0A X402_SOLANA, …) |
| timestamp | 8 | UNIX seconds, uint64 LE |
| issuer_id | 36 | Notary account, NUL-padded UTF-8 |
| subject_hash | 32 | Agent public key bytes (bilateral) / account hash |
| payload_hash | 32 | work_hash (v0x03) or binding hash (v0x04) |
| merkle_root | 32 | Segment root at issuance (anchored in the cumulative log) |
| payment_hash | 32 | On-chain payment reference |
| signature | 64 | Ed25519 over AOTrust signature frame of the 175-byte payload |
| TOTAL | 239 | bytes |
Bilateral (v0x04) details, binding-hash formula and a live test vector: specification.
Disclaimer: PDRs are cryptographic evidence of hash existence at a point in time. They are NOT legally recognized notarization, electronic signatures, or qualified timestamps under EU eIDAS or any national notary law.
How a PDR relates to the IETF leg-record model
Since October 2026 the IETF SCITT work includes individual Internet-Drafts that describe a two-party settlement as up to four signed leg records - terms, payer-observed, payee-observed, delivered - each sealed by the party that observed that fact, with the settlement state (one-sided, agreed, mismatch) derived by a verifier. These are drafts, not an RFC and not an adopted standard; the vocabulary is becoming the common one for agent-payment evidence, so here is the exact mapping.
| IETF leg | What it records | Where it lives in a PDR |
|---|---|---|
| terms | Price and deliverable, sealed by the party that set them | Outside the record: the published price and the x402 offer. A PDR carries only the rail in payment_anchor_type |
| payer-observed | What the payer's system sent, signed by the payer | Cited, not signed by the payer: payment_hash (32 bytes) plus GET /v1/pdr/by-tx/{tx} |
| payee-observed | What the payee's system received, signed by the payee | This is the notary's own signature: issuer_id + signature over the 175-byte payload |
| delivered | Digest of what was delivered | payload_hash = work_hash; in v0x04 the binding SHA256(work_hash ‖ sig_A ‖ pub_A) |
| transparency receipt | Proof the record was registered in a log | merkle_root + the NEAR anchor and RFC 9162 inclusion/consistency proofs |
In short: a PDR is the payee-observed + delivered pair, sealed by the notary acting as the receiving party, citing the payer's transaction by hash. Two deliberate differences remain. First, the trust root is a public chain (NEAR), not an operator's transparency log: the verifier trusts the chain, not us. Second, a PDR does not derive an agreed state - in v0x03 the payer's observation is not counter-signed, and there is no refusal record. A PDR → Capsule compatibility adapter is not shipped; ask if you need one.
NEAR anchoring & independent verification
Every PDR carries the notary's Ed25519 signature. Beyond that, every work hash becomes a leaf in an append-only Merkle log (RFC 9162, Certificate Transparency model); when new receipts exist, the current root of the whole log is committed hourly to the NEAR contract notary-node.near. Your receipt stays verifiable even if this website disappears - the root lives on-chain, and consistency proofs show the log was never rewritten.
Online verification (no trust in us)
Any NEAR RPC node can read the contract: get_root({"seq": N}) returns the committed root. Compare it with your inclusion proof root (or the merkle_root inside the PDR for legacy receipts). The on-chain sequence counter counts anchor() calls; use the recorded anchor_seq as the source of truth.
Offline verification (when our servers are gone)
You keep three things, and one lives on-chain - no AOTrust server required:
- Your PDR, plus the verify JSON saved when the receipt was fresh (
merkle_proof,merkle_index,merkle_leaf,merkle_tree_size). - The on-chain root: any public NEAR RPC,
get_root({"seq": N})onnotary-node.near. - The standalone verifier verify_merkle_inclusion.py (zero dependencies, RFC 9162 §2.1.3):
python3 verify_merkle_inclusion.py --leaf <merkle_leaf> --proof <comma-joined> \
--index <merkle_index> --root <merkle_root> --tree-size <merkle_tree_size>
# → VALID
Trust model: signature = who attested and when (offline, instantly). Merkle anchor = durability - no one, including us, can erase or forge the record. For bilateral receipts (v0x04) the verify API re-derives the work hash by the binding check sha256(work_hash + sig_A + agent_pubkey) == payload_hash.
Anchoring is cumulative: each anchor commits a single root over all receipts in append-only order. Anyone can verify the log only grew via RFC 9162 §2.1.4 consistency proofs - see the public transparency log.
First registration & reaffirmation
One fingerprint - one canonical first record. The first time a SHA-256 is registered it becomes the first registration for that file. Every later submission of the same bytes is a reaffirmation: a new signed record with its own timestamp, marked as such, and exempt from the per-IP free quota. A reaffirmation never replaces or outranks the first record, so an earlier proof cannot be overwritten or re-issued to someone else.
The canonical state is derived from the append-only ledger (first date, first record id, number of registrations, whether the first record is already covered by an anchor) - it is never stored as a second source of truth.
POST /v1/verify/hash
Ask the registry what it knows about a file you hold, without a receipt and without uploading anything:
curl -s -X POST https://api.aotrust.link/v1/verify/hash \
-H 'Content-Type: application/json' \
-d '{"work_hash":"<sha256 hex>"}'
# 200 {"registered":true,"first_seen_at_iso":"2026-09-06T11:19:10Z",
# "first_pdr_id":"1e2f1f30","registrations":7,"anchored":true,
# "verify_url":"https://verify.aotrust.link/s/1e2f1f30","previous_version":null}
# 200 {"registered":false} - this exact file was never registered, by anyone
POST /v1/verify/file
Same check for raw bytes: send the file as application/octet-stream (up to 32 MB); the server hashes it as it streams and answers with the same fields. On verify.aotrust.link the file never leaves the device - the browser computes SHA-256 locally.
Both endpoints return registration facts only: no keys, no payer, no file names, no personal data. Rate limit 30 requests/hour and 3/minute per IP. What it proves: the artifact existed at a known time and holds the earliest registration position in the AOTrust registry. What it does not prove: authorship, ownership or legal title.
Verification API
All verification endpoints are public and require no authentication; they return HTTP 200 JSON.
Web verifier (no code)
Paste any PDR bundle (Base64) and verify in the browser: https://verify.aotrust.link/?pdr={pdr_b64}
No receipt? Drop a file or a SHA-256 on the same page, or call POST /v1/verify/hash - see First registration above.
GET /v1/pdr/verify/{pdr_b64}
curl -s https://api.aotrust.link/v1/pdr/verify/<base64url PDR>
GET /v1/pdr/settled?superseded_by_hash={hash}
Lookup the final SETTLED PDR for a PROVISIONAL work_hash (two-phase escrow flows).
Anchor API (cumulative log)
GET /v1/anchor/status # latest anchor + size/root/near_tx
GET /v1/anchor/proof/{seq} # RFC 9162 inclusion path for a ledger seq
GET /v1/anchor/consistency?from=&to= # RFC 9162 consistency proof between anchors
Offline verification without a server: pdr_parser.py. Documentation source: aotrust-skills.