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

# Payer Guide

> Pay an x402-protected endpoint as an agent, using a real EIP-3009 signature.

This is the "you're making a payment" side of x402 — typically an AI agent that needs to pay for an API call and keep going without a human in the loop.

## Full round trip

```ts theme={null}
import { privateKeyToAccount } from "viem/accounts";
import { signEip3009Authorization } from "@xentfi/x402-facilitator";
import type { Eip3009TokenDomain, X402Challenge } from "@xentfi/x402-facilitator";

const account = privateKeyToAccount(process.env.PAYER_PRIVATE_KEY! as `0x${string}`);

const domain: Eip3009TokenDomain = {
  chainId: 8453,
  tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  tokenName: "USD Coin",
  tokenVersion: "2",
  tokenDecimals: 6,
};

async function main() {
  const url = "https://merchant.example.com/premium-report";

  // 1. First request — expect a 402 challenge.
  const firstResponse = await fetch(url);
  if (firstResponse.status !== 402) {
    console.log("Already accessible without payment:", await firstResponse.json());
    return;
  }

  const challenge = (await firstResponse.json()) as X402Challenge;
  const requirement = challenge.accepts.find((r) => r.scheme === "eip3009");
  if (!requirement) throw new Error("Server doesn't support the 'eip3009' scheme");

  console.log("Got 402 challenge, paying:", requirement.maxAmountRequired, "to", requirement.payTo);

  // 2. Sign a real EIP-3009 authorization for the required amount.
  const paymentPayload = await signEip3009Authorization({
    account,
    to: requirement.payTo,
    amount: requirement.maxAmountRequired,
    domain,
  });

  // 3. Retry with the signed payment attached.
  const header = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
  const secondResponse = await fetch(url, { headers: { "X-PAYMENT": header } });

  console.log("Result:", secondResponse.status, await secondResponse.json());
}

main();
```

<Steps>
  <Step title="Probe the endpoint">
    Make a normal request. A `402` response means payment is required; the body is an `X402Challenge` listing accepted `PaymentRequirement`s.
  </Step>

  <Step title="Pick a requirement your agent can pay">
    Filter `challenge.accepts` for a `scheme`/`network`/`assetId` you support. XentFi's facilitator currently supports the `eip3009` scheme.
  </Step>

  <Step title="Sign, don't call the facilitator directly">
    `signEip3009Authorization()` is pure local cryptography — it never touches the network. Your agent's private key (or wallet adapter) never leaves the client.
  </Step>

  <Step title="Attach and retry">
    Base64-encode the signed payload and send it as `X-PAYMENT`. The resource server calls `verify()`/`settle()` on your behalf using its own facilitator credentials — your agent doesn't need a XentFi API key at all to *pay*.
  </Step>
</Steps>

<Note>
  Only the resource server needs a WAAS `apiKey`/`orgId` (to verify and settle). A pure payer only needs a viem-compatible account capable of `signTypedData` — no XentFi credentials required.
</Note>

## Getting the token domain right

`signEip3009Authorization` needs the token's **real EIP-712 domain** — it must match the deployed contract exactly, or both the facilitator and the token contract itself will reject the signature.

| Field           | Description                                                                                   |
| --------------- | --------------------------------------------------------------------------------------------- |
| `chainId`       | Numeric chain ID (e.g. `8453` for Base mainnet).                                              |
| `tokenAddress`  | The ERC-20 contract address.                                                                  |
| `tokenName`     | The contract's EIP-712 domain `name` (often, but not always, the token's display name).       |
| `tokenVersion`  | The contract's EIP-712 domain `version` (commonly `"1"` or `"2"` — check the specific token). |
| `tokenDecimals` | Used to convert your human-readable `amount` into base units.                                 |

Pull these from the merchant's `PaymentRequirement`/`getSupported()` response rather than hardcoding them — different tokens on different chains have different `version` strings, and getting it wrong produces a signature the contract silently rejects.

## Next steps

<CardGroup cols={2}>
  <Card title="Signing Reference" icon="pen-tool" href="/x402/signing">
    Full parameter reference for `signEip3009Authorization`.
  </Card>

  <Card title="Resource Server Guide" icon="server" href="/x402/resource-server">
    See the other side of this flow.
  </Card>
</CardGroup>
