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

# With Viem.js

> Make payments with Viem

# Make Payments with Viem

Make payments to Armory-protected APIs using Viem wallets.

`hooks` are lifecycle callbacks. `extensions` are protocol fields on x402 payloads/challenges. They work together but are separate.

When payment verification fails on retry (`402`), Armory surfaces server detail (for example `insufficient_funds`) in the thrown error.

## Basic Payment

```typescript theme={null}
import { armoryPay } from '@armory-sh/client-viem';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount('0x...');

const result = await armoryPay(
  { account },
  'https://api.example.com/data',
  'base',
  'usdc'
);

console.log(result.data);
```

## Prefer the Armory object (method-based API)

For multi-call flows the new `createArmory` object bundles the payment client with method helpers and automatic server option selection.

```typescript theme={null}
import { createArmory } from '@armory-sh/client-viem';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount('0x...');

const armory = createArmory({
  wallet: { account },
  // Restrict the object to Base + USDC if you want to avoid extra lookups
  chains: 'base',
  tokens: 'usdc',
  debug: true,
});

const premium = await armory.post('https://api.example.com/premium', { signal: 'upgrade' });
const info = await armory.call('https://api.example.com/data');

console.log(premium.data, info.data);
```

`createArmory` handles 402 responses from `PAYMENT-REQUIRED` and selects from `accepts[]`. Without hooks it uses the first compatible option. Add `@armory-sh/client-hooks` to apply chain/token/cheapest preference logic. The object exposes `.get`, `.post`, `.put`, `.delete`, `.patch`, `.pay`, and a `.call` shorthand for GET requests.

Use `armory.pay(url, { method: 'PATCH', body })` when you need to override the HTTP method; call `.call` for a simple GET.

## With Custom Amount

```typescript theme={null}
const result = await armoryPay(
  { account },
  'https://api.example.com/premium',
  'base',
  'usdc',
  { amount: '5.0' }
);
```

## Using Public Client

```typescript theme={null}
import { createPublicClient, http } from 'viem';
import { base } from 'viem/chains';

const publicClient = createPublicClient({
  chain: base,
  transport: http()
});

const result = await armoryPay(
  { account, publicClient },
  'https://api.example.com/data',
  'base',
  'usdc'
);
```

## With Extension Hooks

For servers that require protocol extensions (like Sign-In-With-X):

```typescript theme={null}
import { createX402Client } from '@armory-sh/client-viem';
import { createSIWxHook, createPaymentIdHook } from '@armory-sh/extensions';
import { PaymentPreference, Logger } from '@armory-sh/client-hooks';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount('0x...');

const client = createX402Client({
  wallet: { type: 'account', account },
  hooks: [
    // Extension hooks
    createSIWxHook({
      domain: 'example.com',
      statement: 'Sign in to access premium content'
    }),
    createPaymentIdHook(),

    // Optional preference hooks
    PaymentPreference.chain(['base', 'polygon', 'skale']),
    PaymentPreference.token(['USDT', 'USDC', 'WBTC']),
    PaymentPreference.cheapest(),
    Logger.console(),
  ]
});

// Hooks automatically add extensions when server requests them
const response = await client.fetch('https://api.example.com/protected');
const data = await response.json();
```

## Multiple Requests

Reuse the client for multiple requests:

```typescript theme={null}
const client = createX402Client({
  wallet: { type: 'account', account },
  hooks: [createSIWxHook()]
});

// First request - may trigger SIWX signing
const response1 = await client.fetch('https://api.example.com/data1');

// Subsequent requests - hooks execute as needed
const response2 = await client.fetch('https://api.example.com/data2');
```

## Custom Extensions

Create custom hooks for your own extensions:

```typescript theme={null}
import { createCustomHook } from '@armory-sh/extensions';

const myExtensionHook = createCustomHook({
  key: 'my-extension',
  handler: async (context) => {
    if (context.payload) {
      context.payload.extensions = {
        ...(context.payload.extensions ?? {}),
        'my-extension': { timestamp: Date.now() }
      };
    }
  },
  priority: 75
});

const client = createX402Client({
  wallet: { type: 'account', account },
  hooks: [myExtensionHook]
});
```
