# How AI agents budget x402 API calls

A practical agent-first guide to enforcing spend policy before signing an x402 payment: validating 402 accepts[], comparing network, asset, payee, and amount against an allowlist, and recording debits only from successful payment receipts.

Before an autonomous agent signs any x402 payment, it should price-check the HTTP 402 `accepts[]` payload, compare every field against an internal allowlist and a per-task spending cap, and only sign when scheme, network, asset, payee, and amount all pass.

This article shows a concrete policy object and decision algorithm you can run inside an agent runtime before it attaches an `X-PAYMENT` header to a request. The examples use this marketplace, but the same logic applies to any x402 endpoint your agent might call.

This marketplace offers a global free tier of 3 successful calls total across all endpoints per IP + User-Agent identity. Successful free responses include an `X-Free-Calls-Remaining` header, but production budgeting must not rely on those calls being available; always plan for the paid path after the first request.

## What the 402 challenge tells you

When the free tier is exhausted, an unpaid request to this marketplace returns HTTP 402 with a machine-readable `accepts[]` array. Each entry is a contract: sign this exactly, or do not sign at all.

| Field | Verified production value | Why it matters for budget |
| --- | --- | --- |
| scheme | exact | Only exact-scheme pricing is accepted; no auctions or ranges. |
| network | base | Mainnet settlement on Base. Sepolia is only for sandbox testing. |
| asset | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | USDC contract on Base mainnet. |
| payTo | 0x05e82e03753c7bc99fb24d10a876cce53f24b7b7 | The only approved merchant address. |
| maxAmountRequired | 5000 | Atomic USDC units; equals $0.005 per call. |
| resource | https://marketplaceforaiagents.com/api/public/v1/{slug} | Scope the signed authorization to this endpoint. |

Agents should never trust a hard-coded price. Always read the live requirement from `https://marketplaceforaiagents.com/.well-known/x402` or the 402 response itself before signing.

## Build an allowlist policy object

Store policy as integer atomic units, never floating-point dollars. A task budget is a reservation, not a guaranteed debit, because a failed upstream call should not cost the agent anything.

```ts
const POLICY = {
  // Only these settlement terms are permitted.
  allowedSchemes: new Set(["exact"]),
  allowedNetworks: new Set(["base"]),
  allowedAssets: new Set([
    "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", // Base USDC mainnet (lowercase)
  ]),
  allowedPayees: new Set([
    "0x05e82e03753c7bc99fb24d10a876cce53f24b7b7", // lowercase
  ]),

  // Per-task cap in atomic USDC units (1 USDC = 1_000_000n).
  taskBudgetAtomic: 50_000n, // $0.05 total for this task
  maxPerCallAtomic: 5_000n,  // $0.005 per call
  maxCallsPerTask: 10,

  // Track committed reservations and confirmed debits separately.
  reservedAtomic: 0n,
  spentAtomic: 0n,
};
```

The policy also separates `reservedAtomic` from `spentAtomic`. A reservation is the amount you set aside when you plan to make a call; `spentAtomic` is updated only after a successful `X-PAYMENT-RESPONSE` receipt is decoded.

## The budget algorithm before signing

Run this check on every `accepts[]` entry before producing an EIP-3009 signature. If any check fails, stop and surface a clear reason to the agent's planner.

```ts
function canAffordCall(policy, acceptsEntry, plannedCalls = 1) {
  const {
    scheme, network, asset, payTo, maxAmountRequired,
  } = acceptsEntry;

  const amount = BigInt(maxAmountRequired);

  // 1. Structural validation
  if (!policy.allowedSchemes.has(scheme)) return { ok: false, reason: "scheme_not_allowed" };
  if (!policy.allowedNetworks.has(network)) return { ok: false, reason: "network_not_allowed" };
  if (!policy.allowedAssets.has(asset.toLowerCase())) return { ok: false, reason: "asset_not_allowed" };
  if (!policy.allowedPayees.has(payTo.toLowerCase())) return { ok: false, reason: "payee_not_allowed" };

  // 2. Amount validation (integer atomic units only)
  if (amount <= 0n) return { ok: false, reason: "amount_non_positive" };
  if (amount > policy.maxPerCallAtomic) return { ok: false, reason: "per_call_over_cap" };

  // 3. Budget reservation (estimate, not a debit)
  const projectedSpend = policy.spentAtomic + (amount * BigInt(plannedCalls));
  if (projectedSpend > policy.taskBudgetAtomic) {
    return { ok: false, reason: "task_budget_exceeded" };
  }
  if (plannedCalls > policy.maxCallsPerTask) {
    return { ok: false, reason: "call_count_over_cap" };
  }

  return { ok: true, amountAtomic: amount };
}
```

This function returns the atomic amount only when every guard passes. The agent then reserves that amount, signs the authorization, attaches it as `X-PAYMENT`, and waits for the receipt before marking the spend as real.

## When to stop and fall back

A disciplined agent treats the 402 as untrusted input. Any deviation from policy is a stop condition. Here is the decision matrix an agent runtime should implement.

| Situation | Decision | Fallback action |
| --- | --- | --- |
| 402 has no accepts[] | Stop | Log malformed response; try another provider. |
| accepts[] has multiple entries | Evaluate each | Choose the first entry that matches the policy; stop if none match. |
| maxAmountRequired > per-call cap | Stop | Reject; do not sign a larger amount. |
| network/asset/payee mismatch | Stop | Do not sign; report policy violation. |
| scheme is not exact | Stop | Only exact pricing is supported here. |
| Upstream returns 5xx after payment | Hold reservation | Reconcile the receipt or on-chain transaction before recording or releasing it. |
| No X-PAYMENT-RESPONSE header | Hold reservation | Treat as unsettled; do not record spend or release the reservation. |
| Receipt decodes but tx status is unknown | Hold (optional agent policy) | Agent may apply its own confirmation rule before debiting or releasing. |

The key rule: a charge is only recorded when a successful paid response provides a base64 `X-PAYMENT-RESPONSE` that decodes to a transaction hash, network, and payer address. Until then, the amount remains a reservation.

## Recording actual debits from receipts

After the agent sends `X-PAYMENT`, a successful response carries `X-PAYMENT-RESPONSE`. Decode it, extract the transaction hash, and only then move the reserved amount into `spentAtomic`.

```ts
async function recordPaidCall(policy, response, expectedAmountAtomic) {
  const receiptHeader = response.headers.get("X-PAYMENT-RESPONSE");
  if (!receiptHeader) {
    return { settled: false, reason: "missing_receipt" };
  }

  const receipt = JSON.parse(atob(receiptHeader));
  if (!receipt.transaction || !receipt.network) {
    return { settled: false, reason: "incomplete_receipt" };
  }

  policy.spentAtomic += expectedAmountAtomic;
  const newReserved = policy.reservedAtomic - expectedAmountAtomic;
  policy.reservedAtomic = newReserved > 0n ? newReserved : 0n;

  return {
    settled: true,
    transaction: receipt.transaction,
    network: receipt.network,
    payer: receipt.payer,
    amountAtomic: expectedAmountAtomic,
  };
}
```

If the response is ambiguous — for example, a 5xx, a missing receipt, or a decoded receipt whose transaction status you cannot confirm — hold the reservation and reconcile the receipt or on-chain transaction before recording a debit or releasing the funds. Do not assume a failed HTTP response means no charge occurred, and do not assume an unconfirmed transaction is final unless your own policy defines that threshold.

## Test the policy in Base Sepolia sandbox

Use the sandbox to exercise the budget algorithm without spending real USDC. Append `?network=base-sepolia` to any endpoint. The sandbox uses testnet USDC at `0x036CbD53842c5426634e7929541eC2318f3dCF7e` and returns mock data in the documented shape.

```bash
# 1. Discover current prices and endpoints
curl -s https://marketplaceforaiagents.com/.well-known/x402

# 2. Exhaust the free tier or skip straight to the paid path
curl -s "https://marketplaceforaiagents.com/api/public/v1/google-search?q=x402+protocol&network=base-sepolia" -v

# 3. When you see HTTP/1.1 402, inspect accepts[] and run your policy checks
# 4. Sign against testnet USDC, attach X-PAYMENT, and verify the mock receipt
```

In sandbox mode the 402 still returns `accepts[]`, but the amount is the same $0.005 in testnet USDC. This lets you validate your allowlist, budget algorithm, and receipt decoding before touching mainnet.

## Where this marketplace fits

This marketplace hosts 38 live endpoints — search, news, images, commerce, maps, travel, jobs, academic, app stores, and video — all priced at $0.005 USDC per call on Base mainnet. There are no accounts, no API keys, and no monthly billing. Agents pay per call through x402.

- Browse human-readable listings at https://marketplaceforaiagents.com/marketplace
- Read the full discovery index at https://marketplaceforaiagents.com/llms.txt
- Read prose docs at https://marketplaceforaiagents.com/docs and the Markdown twin at https://marketplaceforaiagents.com/agent/docs.md
- Fetch the live catalog at https://marketplaceforaiagents.com/api/public/v1/catalog.json or the short path https://marketplaceforaiagents.com/catalog.json
- Inspect the OpenAPI spec at https://marketplaceforaiagents.com/api/public/v1/openapi.json
- See a concrete listing at https://marketplaceforaiagents.com/listings/google-search

Every agent should read live discovery before each task. Prices are uniform today, but hard-coding them is a future bug. Let the 402 response and `/.well-known/x402` be the source of truth, and let your policy object be the guardrail.

Canonical HTML: https://marketplaceforaiagents.com/learn/budget-x402-api-calls