Receipts
On accept, the merchant issues an Ed25519-signed receipt that links back to the buyer's mandate. Two signed artifacts pointing at each other are your dispute evidence — verifiable offline, by anyone.
On accepted, the merchant issues an Ed25519-signed compact
JWS receipt. Its mandateRef points back at the buyer's mandate subject. The buyer
holds a mandate; the merchant holds a receipt that references it — two signed artifacts
that point at each other are your non-repudiation / anti-chargeback evidence.
The claims
interface MerchantReceiptClaims {
iss: 'veto-checkout';
sub: string; // receipt id
sessionId: string;
iat: number;
merchantId: string;
agentId: string;
decision: 'accept' | 'reject' | 'hold';
total: CartTotal;
reasonCodes: string[];
mandateType: 'veto' | 'ap2' | 'acp' | 'none';
mandateRef?: string; // ← the buyer mandate subject
policyHash: string; // names the exact policy version that decided
inputFingerprint: string;
}The policyHash is a canonical-JSON SHA-256 of the active policy, so a receipt provably
names the policy version that produced it.
Verify offline, by anyone
Receipts verify against the merchant's public key — no call back to Veto required:
// From your own handle:
const result = checkout.verifyReceipt(receiptJws);
// → { valid, claims, reasonCodes }
// Or from the published key, anywhere:
import { verifyMerchantReceipt } from '@veto-protocol/checkout';
const jwks = await fetch('https://shop.acme.example/.well-known/jwks.json').then(r => r.json());
verifyMerchantReceipt(receiptJws, jwks);Publish your verifying key so buyers can check receipts independently:
checkout.receiptJwks(); // { keys: [Ed25519Jwk] } — serve at /.well-known/jwks.jsonNon-custodial by design.
The only key Veto holds signs receipts, not value. Funds settle directly to your own receiving address via the rail.
See the receipt verification guide for the failure modes
(RECEIPT_INVALID_SIGNATURE, RECEIPT_WRONG_ISSUER,
…).
Rails
The pluggable settlement interface — x402 (HTTP-402 + stablecoin), mock (offline tests), and the card stub. Bring your own receiving destination per rail; Veto never holds funds.
Guides
Task-focused walkthroughs — choose a deployment model, connect your store, run in sandbox, go live on-chain, set policy, and harden for production.