Skip to content

HTTP API

Public

Method Path Notes
GET /api/health Liveness (no rate limit)
GET /api/ready DB ready (no rate limit)
POST /api/invoices Create (rate limited — create bucket)
GET /api/invoices/:id Status + events
GET /api/invoices?to=0x… Merchant list (signed)
GET /api/public/pay-in/config MetaMask pay-in capability (Base USDC)
GET /api/public/pay-in/countries Quote regions
GET /api/public/pay-in/geo Payer country from CDN IP headers
GET /api/public/pay-in/quotes Card/bank quotes (Pay-in API)
GET /api/public/pay-in/widget Provider checkout URL (new tab)

Invoice type field shapes and worked examples: Invoice types.

Admin (x-api-key: ADMIN_API_KEY)

Method Path
GET /api/admin/stats
POST /api/admin/sweepers
POST /api/admin/bundlers

Admin and /api/internal/* routes are not rate-limited (API-key gated).

Sweeper (wallet-signed)

Method Path
GET /api/sweeper/me
GET /api/sweeper/invoices
POST /api/sweeper/heartbeat
POST /api/sweeper/claim
POST /api/sweeper/track

Headers: x-sweeper-address, x-sweeper-timestamp, x-sweeper-nonce, x-sweeper-body-hash, x-sweeper-signature.

Track/claim use optimistic expectedVersion; conflicts return 409.

Bundler (wallet-signed)

Method Path
GET /api/bundler/userops
POST /api/bundler/claim
POST /api/bundler/track

Same header pattern as sweeper (x-bundler-*). Register via POST /api/admin/bundlers then ./register-onchain-invoice-bundler.sh.

Wallet UserOps: POST /api/wallet/userops (public submit). Rejected/failed hashes may be requeued with a fresh signature; pending/included hashes return 409 duplicate_user_op_hash.

Hosted wallet recovery (public + guardian)

User-facing recovery for the hosted /wallet product (not the HMAC partner API). See Security.

Method Path Auth
GET/POST /api/wallet/email Passkey + captcha (POST); public masked GET
POST /api/wallet/email/verify OTP + captcha
POST /api/wallet/recovery/email/start Email + captcha. Always 200 (no enumeration). OTP only if wallets exist
POST /api/wallet/recovery/email/verify OTP + captcha → emailSession
GET /api/wallet/recovery/email/wallets Bearer emailSession — all wallets for that email
POST /api/wallet/recovery/challenges Public
GET /api/wallet/recovery Public (active request + pendingOwner)
POST /api/wallet/recovery/requests New key (WebAuthn, YubiKey, or EOA) + captcha. Email optional. walletAddresses[] + emailSession for email-first
POST /api/wallet/recovery/requests/:id/verify-email OTP + captcha
POST /api/wallet/recovery/requests/:id/cancel Owner passkey + captcha
GET /api/guardian/nonce Guardian address query
POST /api/guardian/login EIP-191 signature
GET /api/guardian/me Guardian session
GET /api/guardian/recovery-requests Guardian session
POST /api/guardian/recovery-requests/:id/approve Guardian session → queue initiate job
POST /api/guardian/recovery-requests/:id/reject Guardian session

Wallet client API (HMAC)

Partner backends embedding passkey wallets on their WebAuthn domain. Full contract: Wallet client API. Hosted recovery above is a different path (OTP email, MetaMask guardian UI).

Method Path Auth
POST/GET/PATCH /api/admin/wallet-clients… ADMIN_API_KEY
POST/GET /api/client/wallets… HMAC (x-client-*)
GET/POST /api/internal/wallet-recovery/* SWEEPER_API_KEY

Headers: x-client-id, x-client-timestamp, x-client-nonce, x-client-body-hash, x-client-signature. Path in the canonical message is pathname only.

Rate limiting

Central table-driven limiter (IP + bucket). New public routes are limited by default.

Bucket Default Env Used for
create 1/s RATE_LIMIT_CREATE_PER_SECOND POST /api/invoices (+ aliases, faucet capped)
public 20/s RATE_LIMIT_PUBLIC_PER_SECOND Public GETs, hosted wallet APIs
quote 2/s, burst 20 RATE_LIMIT_QUOTE_PER_SECOND, RATE_LIMIT_QUOTE_BURST /api/public/pay-in/
sweeper 50/s RATE_LIMIT_SWEEPER_PER_SECOND Sweeper + bundler signed APIs
wallet_client 50/s RATE_LIMIT_WALLET_CLIENT_PER_SECOND /api/client/wallets*

Exempt: /api/health, /api/ready, /api/admin/*, /api/internal/*, wallet deployer routes.

Exceeding a limit returns 429 { "error": "Rate limit exceeded" } with:

  • Retry-After (seconds)
  • RateLimit-Remaining
  • RateLimit-Reset

Agents should back off and retry after Retry-After. Public create and quote are unauthenticated (spam risk accepted at launch; captcha optional via Turnstile).

Platform integrations

Ecommerce and creator platform adapters (WooCommerce, Shopify, Kajabi, Teachable) build on the same contract: