VetoVetoDocs
Hosted REST API

Merchants

Create and manage merchants. Creating a merchant mints its Ed25519 receipt-signing key; the public JWKS is served for offline receipt verification.

A merchant is the top-level resource. Creating one mints an Ed25519 receipt-signing identity: the private seed is generated server-side, AES-GCM encrypted at rest, and never returned; the public JWK and its kid are published so any buyer can verify a receipt offline. A project may host several merchants.

The receipt key is the only key Veto holds.

The signing seed never leaves the server and is never in any response. The public half is served at /v1/merchants/:id/jwks and the canonical /.well-known/jwks.json.

The merchant object

{
  "id": "mrch_01J…",
  "slug": "acme",
  "name": "Acme Corp",
  "domain": "shop.acme.example",
  "receiving": { "x402": { "chain": "base", "address": "0x…", "asset": "USDC" } },
  "rails": ["x402", "mock"],
  "receipt_kid": "mrch_01J…-receipts-v1",
  "receipt_pub_jwk": { "kty": "OKP", "crv": "Ed25519", "x": "…", "kid": "mrch_01J…-receipts-v1" },
  "trusted_veto_jwks_url": null,
  "livemode": false,
  "created_at": "2026-06-24T12:00:00.000Z",
  "updated_at": "2026-06-24T12:00:00.000Z"
}

POST /v1/merchants

Create a merchant. livemode is inherited from the resolving key — a test key creates a test merchant, a live key a live merchant.

AuthAPI key · scope merchants:write

Request

{
  "slug": "acme",
  "name": "Acme Corp",
  "domain": "shop.acme.example",
  "receiving": { "x402": { "chain": "base", "address": "0x…", "asset": "USDC" } },
  "rails": ["x402", "mock"],
  "trusted_veto_jwks_url": "https://veto-ai.com/.well-known/jwks.json"
}
FieldRequiredNotes
slugUnique within (slug, livemode).
nameDisplay name.
domainThe merchant's storefront domain.
receivingValidated at write time — see Receiving.
railsoptionalSubset of x402, card, mock. Defaults to ["x402","mock"].
trusted_veto_jwks_urloptionalThe Veto issuer JWKS used to verify buyer mandates.

Status codes

StatusReason codeMeaning
201Created; returns the merchant object.
400VALIDATION_FAILEDMissing slug/name/domain, or bad rails.
400RECEIVING_ADDRESS_INVALID · RECEIVING_CHAIN_UNSUPPORTED · RECEIVING_MOCK_IN_LIVEReceiving failed validation.
409MERCHANT_SLUG_TAKENSlug already used in this mode.
create a merchant
curl -X POST https://api.veto-ai.com/v1/merchants \
  -H "Authorization: Bearer veto_test_8f2c…" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "acme",
    "name": "Acme Corp",
    "domain": "shop.acme.example",
    "receiving": { "x402": { "chain": "base-sepolia", "address": "0x1111111111111111111111111111111111111111", "asset": "USDC" } }
  }'

GET /v1/merchants

List merchants in the project (current mode), newest first.

AuthAPI key · scope merchants:read
Querylimit (1–100, default 20)
200
{ "data": [ /* merchant objects */ ], "has_more": false, "next_cursor": null }
curl "https://api.veto-ai.com/v1/merchants?limit=20" \
  -H "Authorization: Bearer veto_test_8f2c…"

GET /v1/merchants/:id

Fetch one merchant the caller's project owns (in the caller's mode).

AuthAPI key · scope merchants:read
StatusMeaning
200The merchant object.
404NOT_FOUND — unknown id, or it belongs to another project/mode.

PATCH /v1/merchants/:id

Update name, domain, receiving, rails, or trusted_veto_jwks_url. Only the fields present are changed. slug, livemode, and the receipt key are immutable.

AuthAPI key · scope merchants:write
request
{ "name": "Acme Inc.", "rails": ["x402"] }
StatusReason codeMeaning
200Updated merchant object.
400VALIDATION_FAILED / receiving codesBad rails or receiving.
404NOT_FOUNDNot found in this project/mode.

GET /v1/merchants/:id/jwks

Public. The merchant's receipt-verification JWKS — the hosted twin of the self-hosted /.well-known/jwks.json. Any buyer can fetch it to verify a receipt offline. Not mode-guarded (a public key reveals nothing); resolved by id only.

AuthPublic
HeadersAccess-Control-Allow-Origin: *, Cache-Control: public, max-age=300
200
{ "keys": [ { "kty": "OKP", "crv": "Ed25519", "x": "…", "kid": "mrch_01J…-receipts-v1" } ] }
curl https://api.veto-ai.com/v1/merchants/mrch_01J…/jwks

See Verify receipts for the verification recipe.