# Buyer-Side Caps: A Paying Client That Cannot Overspend

## Summary

`@agentbadge/circle-payments` ships an x402 buyer client that refuses to exist without limits: `createPayingClient({caps, signer})` throws `TypeError` when `PaymentCaps` is omitted — `{maxPaymentUsd, sessionBudgetUsd, allowedNetworks?}`. Every 402 is validated before signing (`validateAccepts`), spend is recorded at sign/broadcast, and the `agentbadge pay` CLI enforces the same caps with `--print-only` as an unsigned pre-flight check.

## Contract Enforced Before Signing

- `x402Version === 2`; `scheme ∈ {exact, eip3009-client-broadcast, gateway-batch}`; `network` ∈ caps.allowedNetworks; `asset` === USDC(chain); `amount <= maxPaymentUsd` (atomic, decimals=6).
- `extra.decimals !== 6` → refuse — never infer token decimals (mis-scale footgun).
- Refusals return `{ok:false, reason, field, value}` — named field + rejected value.
- Cap breach → `CapExceededError {cap, requested}`; budget breach → `BudgetExhaustedError {spent, budget, requested}`; retried-402 → `PaymentNotAcceptedError` (never pay twice for one request).

## Runtime Pieces

- `SpendTracker` — session cumulative; `spent += amount` on sign/broadcast, not on 402; `onSpend(entry)` persist hook.
- `paginateAll(pageFn, {cursorField, itemsField, maxPages})` — every page is a payment counted against the budget.
- Gateway auto-deposit: `gateway.autoDepositUsd` tops the gateway balance before the request (ensureFunded pattern).
- Payer-binding: `extra.payerBinding` → retry carries `X-Wallet`, `X-Sig`, `X-Timestamp` (EIP-191, `agentbadge-pay:v1`).

## CLI

`agentbadge pay <url> --max-payment 0.25 --budget 5 [--method POST] [--print-only]`
Exit codes: `0` ok · `2` refusal/cap · `3` network. Caps via flags or env (`AGENTBADGE_MAX_PAYMENT`, `AGENTBADGE_BUDGET`); private key only via env. `--print-only` prints `{amount, network, payTo}` and exits unsigned.

## Endpoints

| Need | Endpoint |
|------|----------|
| Service catalog (SKU + input_schema + price_usd) | `GET /api/v1/services` |
| Committed OpenAPI artifact (X402 components) | `GET /openapi.yaml` |
| LLM entry point | `GET /llms.txt` |
| Refusal contract | `GET /api/meta/refusal-contract` |

## Verify It

`validateAccepts` expectations match the committed `openapi.yaml` components: `x402Version: 2`, `extra.decimals: 6`, `charged: false`. CI runs `bun run check:openapi` — spec drift fails the gate. Reader repro: `agentbadge pay <url> --max-payment 0.25 --budget 5 --print-only`.

## Links

- Blog article: https://agentbadge.xyz/blog/arc-c18-sdk-caps
- SDK: https://www.npmjs.com/package/@agentbadge/circle-payments
- Service catalog: https://agentbadge.xyz/api/v1/services



    <section class="mt-8 rounded-xl border border-emerald-800/30 bg-slate-900/50 p-6">
      <h3 class="text-lg font-bold text-slate-100">Relevant Engineering Capabilities</h3>
      <p class="mt-1 text-sm text-slate-400">The AgentBadge team can help with what you're reading about.</p>
      <div class="mt-4 grid gap-3">
        
        <div class="rounded-lg border border-slate-700 bg-slate-800/50 p-4">
          <div class="flex items-center justify-between">
            <h4 class="text-sm font-semibold text-emerald-400">AI Agent Architecture</h4>
            <span class="text-xs text-slate-400">Confidence: 0.93</span>
          </div>
          <p class="mt-1 text-xs text-slate-400">Design and implementation of AI agent infrastructure, agent APIs, machine-readable interfaces, and agent tooling.
</p>
          <div class="mt-2 flex items-center gap-3 text-xs text-slate-500">
            <span>People: Paul</span>
            <span>Status: VERIFIED</span>
          </div>
        </div>
        <div class="rounded-lg border border-slate-700 bg-slate-800/50 p-4">
          <div class="flex items-center justify-between">
            <h4 class="text-sm font-semibold text-emerald-400">Backend Development</h4>
            <span class="text-xs text-slate-400">Confidence: 0.92</span>
          </div>
          <p class="mt-1 text-xs text-slate-400">Node.js, NestJS, PostgreSQL, Redis, REST APIs, and event-driven systems.
</p>
          <div class="mt-2 flex items-center gap-3 text-xs text-slate-500">
            <span>People: Paul</span>
            <span>Status: VERIFIED</span>
          </div>
        </div>
      </div>
      
        <div class="mt-3">
          <p class="text-xs text-slate-500 mb-1">Related services:</p>
          <div class="flex flex-wrap gap-2">
            <span class="text-xs rounded-full bg-slate-700 px-2 py-1 text-slate-300">AI Agent Consulting</span>
          </div>
        </div>
      <div class="mt-4">
        <a href="/agent-guide/team/capabilities" class="inline-flex items-center text-sm font-medium text-emerald-400 hover:text-emerald-300">
          View all capabilities →
        </a>
      </div>
    </section>