Offline verification

The whole point: anyone with a verify URL can prove a receipt is real without trusting Marturia, without an account, and without a network call to us at verify time.

What "verified" means

The verifier checks four things:

  1. Signature. The Ed25519 signature on receipt_hash validates against the published public key.
  2. Hash integrity. Recomputing the canonical-JSON SHA-256 of the payload + metadata produces exactly receipt_hash.
  3. Sequence. The receipt_seq is monotonic and the prev_receipt_hash matches the chain.
  4. Witness cosigning (when present). At least one independent operator node has cosigned the Merkle root that anchors this receipt.

The verifier — for your auditors

marturia-verify is a small open-source Python tool. It does no network calls; everything runs offline against the JSON you give it.

pip install marturia-verify

The whole flow your auditor would run:

# 1. Pull the receipt from the verify URL (one-time network call).
curl -s https://marturia.dev/v1/verify/2/98 > receipt.json

# 2. Extract the public key (already inside the receipt response).
jq -r .public_key receipt.json > pubkey.hex

# 3. Verify offline. No network. Auditable source.
marturia-verify --receipt receipt.json --pubkey pubkey.hex

Successful verification looks like:

VALID: signature valid; receipt_hash matches; sequence 54 of tenant 2

Tampered receipt looks like:

INVALID: receipt_hash mismatch — payload was modified

What the URL returns

GET https://marturia.dev/v1/verify/{tenant_id}/{receipt_id} returns a JSON envelope your auditor can save and re-verify any time:

{
  "tenant_id": 2,
  "receipt_seq": 54,
  "agent_name": "purchase_approver",
  "agent_run_id": "run_demo_001",
  "created_at": "2026-05-09T18:42:11.337Z",
  "signing_kid": "t2-v1",
  "receipt_hash": "803e993d40faef9071dd0d458d6b5382...",
  "prev_hash":    "a609ed8ce163599bd7c076eda757d2b7...",
  "signature":    "5fd2e0a14a6d5c9c...",
  "public_key":   "9fc982fe34745307f97bdf9c...",
  "payload_canonical_bytes": "<base64 of canonical JSON>"
}

What an auditor doesn't have to trust

What an auditor still trusts

Sharing a verify URL

Open the dashboard's Receipts tab → click any receipt → "Cryptographic verification" panel has the verify URL with a one-click copy. Paste into Slack, email, a PDF, whatever. The recipient doesn't need an account.

Building your own verifier

The verifier is intentionally tiny — under 300 lines of Python. The design goal is "an auditor can read it in an afternoon." If your audit team needs to implement it in another language, the canonical-JSON + Ed25519 contract is documented in the marturia-verify README, and the source is reference enough.

Listing the chain

To verify the chain in bulk (every receipt for a tenant, in order), marturia-verify also accepts a directory of receipt JSON files and walks them sequentially:

marturia-verify --chain ./receipts/ --tenant-pubkey pubkey.hex