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

# x402 Client — Paying for APIs

> Use Chipi wallets to pay for x402-protected API endpoints

<Info>
  **Using a SHHH V8.4 wallet?** This page covers `X402Client`, which signs
  payments for legacy **CHIPI v29** and **READY (Argent X)** wallets. SHHH
  V8.4 wallets — the default for new wallets since v14.5.0 — use
  [`X402ShhhClient`](/sdk/guides/x402-shhh-buyers) instead, because V8.4
  rejects the raw `{r, s}` signature shape `X402Client` produces.
</Info>

## Overview

The x402 client automatically handles HTTP 402 responses. When a server requires payment, the client:

1. Parses the payment requirement from the `PAYMENT-REQUIRED` header
2. Validates the amount against your configured limits
3. Signs the payment using your Starknet account
4. Retries the request with the `X-PAYMENT` header

## React — `useX402Payment` Hook

The easiest way to use x402 in a React/Next.js app:

```typescript theme={null}
import { useX402Payment } from "@chipi-stack/chipi-react";

function PremiumContent() {
  const { x402Fetch, isPaying, lastTxHash, paymentCount, error } = useX402Payment({
    wallet,
    encryptKey: pin,
    getBearerToken: getToken,
    maxPaymentAmount: "1.00", // Max $1 per request
    onPaymentComplete: (txHash, amount) => {
      console.log(`Paid ${amount} USDC — tx: ${txHash}`);
    },
  });

  const fetchData = async () => {
    const response = await x402Fetch("https://api.example.com/premium");
    const data = await response.json();
    // data is available — payment was handled automatically
  };

  return (
    <div>
      <button onClick={fetchData} disabled={isPaying}>
        {isPaying ? "Paying..." : "Get Premium Data"}
      </button>
      {lastTxHash && <p>Last payment: {lastTxHash}</p>}
      <p>Total payments: {paymentCount}</p>
    </div>
  );
}
```

### Hook Configuration

| Property            | Type                       | Description                             |
| ------------------- | -------------------------- | --------------------------------------- |
| `wallet`            | `WalletData`               | Wallet data from `useChipiWallet`       |
| `encryptKey`        | `string`                   | User's PIN/password for signing         |
| `getBearerToken`    | `() => Promise<string>`    | Auth token provider                     |
| `maxPaymentAmount`  | `string?`                  | Max USDC per request (e.g. `"1.00"`)    |
| `allowedRecipients` | `string[]?`                | Whitelist of allowed merchant addresses |
| `session`           | `SessionKeyData?`          | Session key for automatic payments      |
| `onPaymentComplete` | `(txHash, amount) => void` | Callback after successful payment       |

### Hook Return Values

| Property       | Type                                       | Description                   |
| -------------- | ------------------------------------------ | ----------------------------- |
| `x402Fetch`    | `(url, init?) => Promise<Response>`        | Drop-in `fetch` replacement   |
| `signPayment`  | `(requirement) => Promise<PaymentPayload>` | Manual payment signing        |
| `isPaying`     | `boolean`                                  | Payment in progress           |
| `lastTxHash`   | `string \| null`                           | Last payment transaction hash |
| `lastAmount`   | `string \| null`                           | Last payment amount (USDC)    |
| `error`        | `Error \| null`                            | Last error                    |
| `paymentCount` | `number`                                   | Total payments this session   |

## Node.js — `X402Client`

For server-side or CLI applications:

```typescript theme={null}
import { X402Client, DirectSigner, createAccount } from "@chipi-stack/core";
import { RpcProvider } from "starknet";

// Create account from private key (server-side only)
const signer = new DirectSigner(process.env.PRIVATE_KEY!);
const provider = new RpcProvider({ nodeUrl: "https://starknet-mainnet.infura.io/..." });
const account = await createAccount({ signer, provider });

// Create x402 client with safety limits
const client = new X402Client(account, {
  maxPaymentAmount: "0.50",        // Max $0.50 per request
  allowedRecipients: ["0xTRUSTED_MERCHANT"],  // Only pay trusted servers
});

// Automatic 402 handling
const response = await client.fetch("https://api.example.com/ai-endpoint");
const data = await response.json();
```

### Configuration Options

| Option              | Type        | Default                | Description                     |
| ------------------- | ----------- | ---------------------- | ------------------------------- |
| `maxPaymentAmount`  | `string?`   | `undefined` (no limit) | Max USDC per request            |
| `allowedRecipients` | `string[]?` | `[]` (allow all)       | Whitelist of merchant addresses |
| `headerName`        | `string?`   | `"X-PAYMENT"`          | Custom payment header name      |

<Warning>
  **Always set `maxPaymentAmount` in production.** Without it, a compromised or malicious server
  could request an arbitrarily large payment. Set it to the maximum amount you expect to pay per
  request (e.g. `"1.00"` for \$1 USDC).
</Warning>

## Python

```python theme={null}
from chipi_sdk import ChipiSDK, X402Client, X402ClientConfig

sdk = ChipiSDK(config)
client = X402Client(sdk, X402ClientConfig(
    max_payment_amount="0.10",  # Max $0.10 per request
))

# Sync
response = client.fetch("https://api.example.com/data", bearer_token="...")

# Async
response = await client.afetch("https://api.example.com/data", bearer_token="...")
```

## Safety Features

### Amount Limits

Always set `maxPaymentAmount` to prevent unexpected charges:

```typescript theme={null}
const client = new X402Client(account, {
  maxPaymentAmount: "0.10", // Never pay more than $0.10 per request
});
```

If a server requests more than your limit, the client throws an error instead of signing.

### Recipient Whitelist

Restrict which servers can charge you:

```typescript theme={null}
const client = new X402Client(account, {
  allowedRecipients: [
    "0xTRUSTED_API_1",
    "0xTRUSTED_API_2",
  ],
});
```

### Asset Validation

The client only accepts payments in native USDC on Starknet mainnet. Requests for any other token are automatically rejected.

## Error Handling

```typescript theme={null}
try {
  const response = await client.fetch("https://api.example.com/data");
} catch (error) {
  if (error.message.includes("exceeds maximum")) {
    // Payment too expensive
  } else if (error.message.includes("not in the allowed")) {
    // Unknown merchant
  } else if (error.message.includes("PAYMENT-REQUIRED")) {
    // Server misconfigured (no payment requirement header)
  }
}
```
