> ## Documentation Index
> Fetch the complete documentation index at: https://docs.atum.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Agentic sends

> Run a working x402 payment client locally — the same flow an autonomous agent follows to pay for a gated resource.

<Card title="x402-make-payments" icon="github" href="https://github.com/Atum-Labs/examples/tree/main/x402-make-payments">
  Example payment client — wraps fetch to pay for HTTP-gated resources automatically, the way an autonomous agent would.
</Card>

This walks through an example client that behaves like an agent: it requests an [x402-gated resource](/payment-protocols/x402/overview), receives a `402`, and pays for it automatically with no human in the loop.

<Note>
  The client holds its own signing key, so it pays **as** the participant that key belongs to. That is how the 402 flow works — it checks the signature, not who is behind the software. Establishing who is answerable when software spends for someone else is [Know Your Agent](/get-started/identity/know-your-agent), a separate question.
</Note>

## Prerequisites

<AccordionGroup>
  <Accordion title="Node.js 20+">
    npm is included with Node.js.

    ```bash theme={null}
    brew install node
    ```

    Verify:

    ```bash theme={null}
    node -v   # v20.x.x or newer
    ```
  </Accordion>

  <Accordion title="A funded testnet wallet for your agent">
    Your agent needs a wallet that holds the source token (e.g. USDC on Base Sepolia) on the chain the merchant accepts.

    Export its private key — use a **testnet-only wallet**, never one holding real funds. See [Set up a testnet wallet](/get-started/reference/setup-testnet-wallet).

    If you are testing locally against the merchant's in-process stub facilitator, any private key will work since no real transaction is submitted.
  </Accordion>

  <Accordion title="Permit2 allowance (testnet / mainnet only)">
    For real on-chain settlement, the [Permit2](/get-started/concepts/permit2-and-approvals) contract must be approved to spend your source token.

    Run this once on the source chain:

    ```bash theme={null}
    cast send <TOKEN_ADDRESS> \
      "approve(address,uint256)" \
      0x000000000022D473030F116dDEE9F6B43aC78BA3 \
      $(cast max-uint) \
      --rpc-url <RPC_URL> \
      --private-key $PRIVATE_KEY
    ```

    Skip this step when testing locally — the stub facilitator does not check allowances.
  </Accordion>
</AccordionGroup>

### Prerequisites for real settlement

Local stub runs need no funds. Before you point the client at testnet or mainnet, confirm your payer wallet has the source token, native gas for the one-time Permit2 `approve()`, and an active allowance — see [Prerequisites](/get-started/start-building/prerequisites).

## 1. Clone and install

```bash theme={null}
git clone https://github.com/Atum-Labs/examples.git
cd examples/x402-make-payments
npm install
```

## 2. Configure

```bash theme={null}
cp .env.example .env
```

Set `PRIVATE_KEY` in `.env` to your agent wallet's `0x`-prefixed key — it's the only value you need to run against the local merchant in stub mode.

The client's other variables (`MERCHANT_URL`, `RPC_URL`) are documented in the [example README](https://github.com/Atum-Labs/examples/blob/main/x402-make-payments/README.md); the corridor itself is the merchant's config, not the client's.

<Tip>
  **Switching wallets, environments, or corridors?** If you exported `PRIVATE_KEY` in your shell earlier (`export PRIVATE_KEY=0x…`), that value overrides `.env` — dotenv does not replace variables already set in your environment, so the client can silently sign with the wrong wallet after you edit `.env`. Run `unset PRIVATE_KEY` before `npm run pay` so the value from `.env` is used.
</Tip>

## 3. Start the merchant (if running locally)

Follow [Agentic receives](/payment-protocols/x402/accept-payments/agentic-payment-acceptance) to start the example merchant first — it runs an in-process stub facilitator, so there's nothing else to start:

```bash theme={null}
cd ../x402-accept-payments
npm install
npm run dev
```

<Note>
  The merchant is a separate app, so it needs its own `npm install` (the clone step only installed `x402-make-payments`). To install all four example apps at once instead, run `npm run install:all` from the repo root.
</Note>

## 4. Run the client

Back in `x402-make-payments`:

```bash theme={null}
npm run pay
```

Expected output:

```
Requesting http://localhost:4020/paid …
Status: 200
{
  "message": "Access granted.",
  "data": "Your premium content here."
}
```

## What's happening

Looking at `src/client.ts` and `src/purchase.ts`:

1. `registerAtumEscrowScheme` teaches the x402 client how to construct and sign Atum-scheme payment credentials.
2. `wrapFetchWithAtumPayment` wraps the native `fetch` — your agent calls it with a **purchase identifier** (`paymentIdentifier`) so every re-attempt names the same payment.
3. On `402`, the wrapper reads the payment requirements, signs a Permit2 authorization, and retries **once** with `PAYMENT-SIGNATURE` — `wrapFetchWithAtumPayment` itself makes exactly that one attempt and returns, whatever the outcome. It does not loop.
4. The retry-until-settled behavior is a layer above it: [`src/purchase.ts`](https://github.com/Atum-Labs/examples/blob/main/x402-make-payments/src/purchase.ts)'s `payPurchase()` is application code that calls the wrapped `fetch` in a loop, re-attempting the **same purchase** (fresh `402`, re-signed credential, same `paymentIdentifier`) every few seconds while the response reports `settlement_pending`, until settlement reaches a terminal outcome. `src/client.ts` wires the two together — `payPurchase(() => pay(...))`. Integrating directly against the SDK instead of reusing this example means writing your own version of that loop. See [Idempotency](/payment-protocols/idempotency).

The wallet signs a **Permit2 authorization** — it does not broadcast a transaction. The settlement vault deposit only executes on-chain when the facilitator calls `settle`.

## Going to testnet or mainnet

Real settlement means funding your agent's wallet, approving the source token (Permit2), and pointing both merchant and client at Atum-provided URLs. See the [example README](https://github.com/Atum-Labs/examples/blob/main/x402-make-payments/README.md) for `.env` values, funding amounts, and on-chain verification — its **Going to testnet or mainnet** section walks through that app. New to Atum's environments? See [Choose an environment](/payment-protocols/environments) for which one to target and what to expect from `production-testnet`. Run through the [pre-flight checklist](/payment-protocols/pre-flight-checklist) before your first real payment.

<Tip>
  Cross-chain settlement can exceed the gateway's \~30s synchronous window. When it does, the facilitator reports `settlement_pending`, and it's `payPurchase()` — not `wrapFetchWithAtumPayment` itself — that re-attempts the same purchase until it settles. That re-attempt cannot charge twice, however many times it runs. If you integrate directly rather than reusing `purchase.ts`, you need your own version of that retry loop. Confirm the payment on the destination chain before paying again under a **new** purchase identifier. See [Idempotency](/payment-protocols/idempotency).
</Tip>

## Next steps

| Topic                               | Link                                                                                |
| ----------------------------------- | ----------------------------------------------------------------------------------- |
| Direct integration, no example repo | [Develop with Atum SDK](/payment-protocols/x402/make-payments/develop-with-the-sdk) |
| Merchant-side guide                 | [Accept payments](/payment-protocols/x402/accept-payments/overview)                 |
| Facilitator API reference           | [x402 Facilitator API](/api-reference/x402/introduction)                            |
| How settlement works end-to-end     | [Payment lifecycle](/get-started/overview/how-an-atum-payment-works)                |
| Reconcile a real payment            | [Reconciliation](/get-started/support/reconciliation)                               |
