VetoVetoDocs
Guides

Self-host vs hosted

The two ways to run Veto Checkout — mount the zero-dependency SDK on your own domain, or use the hosted control plane. What each owns, what's identical across both, and how to choose.

There are two ways to run Veto Checkout, and they speak the same wire protocol. An agent that can buy from a self-hosted merchant can buy from a hosted one with no change — discovery, the self-describing payment instruction, the acceptance gate, and the signed receipt are identical. The difference is who runs the moving parts.

What's identical across both

Whichever you pick, these never change — they're the protocol, not the deployment:

  • The endpoints. GET /.well-known/agentic-checkout.json, GET /agent/catalog, POST /agent/checkout, POST /agent/checkout/{id}/settle, GET /agent/checkout/{id}.
  • The acceptance gate. Verify mandate → replay check → reputation → policy verdict → capture → receipt. Same ordering, same reason codes.
  • Non-custodial settlement. Funds move agent → your receiving address. Veto never holds money in either mode.
  • The receipt. An Ed25519-signed merchant receipt that anyone can verify offline.

Self-hosted: mount the SDK

You import @veto-protocol/checkout, call createCheckout(config), and mount the handle on your domain with one of the HTTP adapters. It has zero runtime dependencies and runs on Node ≥ 22.6.

server.ts
import { createCheckout, BALANCED } from '@veto-protocol/checkout';
import { createNodeServer } from '@veto-protocol/checkout/node';

const checkout = createCheckout({
  merchant: { id: 'acme', name: 'Acme', domain: 'shop.acme.example' },
  catalog: [{ sku: 'rpt-001', name: 'Market Report', price: { amount: '5.00', currency: 'USD' }, available: true }],
  receiving: { x402: { chain: 'base', address: process.env.VETO_X402_ADDRESS!, asset: 'USDC' } },
  policy: BALANCED(),
  receiptSigningKeySeedB64: process.env.VETO_RECEIPT_SEED,
});

createNodeServer(checkout).listen(8787);

You own:

ConcernWhat you do
StorageThe default MemoryStore is single-process. Swap in a SessionStore over Redis/Postgres for durability and scale — see going to production.
KeysYou hold the receipt-signing seed (receiptSigningKeySeedB64) and publish the public JWK at /.well-known/jwks.json.
SettlementFor real on-chain capture you inject an x402 facilitator. The core stays zero-dependency; the facilitator owns the viem/CDP code.
Reputation (optional)Point reputation.baseUrl at the hosted reputation service, or run fully local (every agent reads as standard).
Reporting (optional)Wire onEvent to mirror terminal outcomes anywhere — including the hosted ingest API.

Choose self-hosted when you want full control, data residency, no third-party in the request path, or you're embedding checkout inside an existing service.

Hosted: the control plane

You create your merchant, catalog, receiving, and policy through the REST API (or the dashboard), and Veto serves the protocol for you under a <slug>.veto-checkout.com subdomain (or a /m/<id> path). The same SDK runs server-side; you just don't operate it.

create a hosted merchant
curl -X POST https://api.veto-checkout.com/v1/merchants \
  -H "Authorization: Bearer veto_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "acme",
    "name": "Acme",
    "domain": "shop.acme.example",
    "receiving": { "x402": { "chain": "base-sepolia", "address": "0xYourAddr…", "asset": "USDC" } }
  }'

The control plane owns:

ConcernWhat it does
Manifest + JWKS servingBuilds and caches /.well-known/agentic-checkout.json and serves your receipt JWKS (R4).
Config storageCatalog, receiving, and immutable, versioned policies, with a validate + publish gate.
KeysMints your Ed25519 receipt key, stores the seed AES-GCM-encrypted at rest, and never returns it.
Live settlementInjects the real CDP x402 facilitator for veto_live_ keys; veto_test_ keys settle on a deterministic mock — see test mode.
ReputationHosted agent scoring updated on every terminal outcome.
WebhooksSigned, retried event delivery to your endpoints — see webhooks.
OrdersA queryable record of every accepted order for the dashboard's Activity view.

Choose hosted when you want to ship fast, skip running storage and key management, and get webhooks, reputation, and the dashboard out of the box.

A spectrum, not a wall

These aren't mutually exclusive. The clean seam is CheckoutConfig.onEvent (and the matching reputation config): a self-hosted SDK can post terminal outcomes to the hosted ingest API to get hosted reputation and orders while still owning its own request path and storage.

createCheckout({
  // … your self-hosted config …
  reputation: { baseUrl: 'https://api.veto-checkout.com', apiKey: process.env.VETO_API_KEY },
  onEvent: (event) => reportToHostedIngest(event), // best-effort; never blocks settle
});

The protocol is the contract; everything else is a dial you can turn from "all mine" to "all managed."

Choosing