Verify · free · no signup

Verify a receipt

Paste any VerityLayer verdict receipt below. We check its Ed25519 signature against our public key and tell you whether it's genuinely ours, unaltered. We've pre-filled a live signed receipt so you can try it in one click — then change a single character and watch it fail.

Loading a live receipt to try…

Under the hood this is a free POST https://api.veritylayer.dev/receipt/verify — the same check anyone, anywhere can run against our public key at /.well-known/verity-pubkey.json. No account. No payment. Prefer the terminal? curl https://api.veritylayer.dev/receipt/selftest

Or verify it without us entirely

The box above is convenient, but be clear about what it is: it POSTs to /receipt/verify, which is the issuer vouching for its own signature. If that is the only way to check a receipt, you are still trusting us. So it isn't.

Two standalone verifiers ship in the open-source repo. They import nothing from VerityLayer, make no network call at verification time, and deliberately share no code with the service that signs — if they agreed because they were the same code, that would prove nothing.

# fetch the key once, then check receipts forever, offline
curl -o pubkey.json https://api.veritylayer.dev/.well-known/verity-pubkey.json

python verify_receipt.py receipt.json pubkey.json   # stdlib + cryptography
node   verify_receipt.js receipt.json pubkey.json   # zero dependencies

The exact bytes that get signed are specified in RECEIPTS.md, including the two places it deliberately diverges from RFC 8785 — named, rather than left for you to hit.

New

A receipt that can refuse

Checking a signature and calling that “verified” is the mistake. A valid signature proves we signed something. It never proves the receipt permits what you are about to do. Every row below is a real signature that must not open a gate:

A genuine receipt that…why it must still be refused
is about a different claimyou verified the wrong thing
says unsupportedwe checked, and it was false
says uncertainwe checked, and we do not know
is six weeks oldtrue then; the world moved
is a test self-testproves signing works, vouches for nothing
already authorized an actionreplayed

require_receipt refuses all six, in Python and TypeScript, with identical behaviour verified against a shared cross-language fixture:

pip install "verity-guard[offline]"      npm install @veritylayer/guard

require_receipt(receipt, PUBKEY, claim="Invoice 4417 is unpaid")
send_payment()   # unreachable unless the receipt vouches for THAT claim

Strict by default — only supported passes, receipts older than 15 minutes are stale, self-tests are refused — and loosening any of it is explicit, so it always shows up in a diff. This is the difference between a receipt you can check and a receipt that can stop you: an agent cannot claim it verified something it did not.