Make payments using Viem wallets.
Installation
# npm
npm install @armory-sh/client-viem
# yarn
yarn add @armory-sh/client-viem
# pnpm
pnpm add @armory-sh/client-viem
# bun
bun add @armory-sh/client-viem
armoryPay
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'
);
if (result.success) {
console.log(result.data);
} else {
console.error(result.code, result.message);
}
With Custom Amount
await armoryPay(
{ account },
'https://api.example.com/premium',
'base',
'usdc',
{ amount: '5.0' }
);
createArmoryClient
import { createArmoryClient } from '@armory-sh/client-viem';
const armory = createArmoryClient({
walletClient,
publicClient,
});
const result = await armory.pay({
to: '0x...',
amount: 1000000000n,
token: TOKENS.USDC_BASE,
});
Configuration Options
import { createX402Client } from '@armory-sh/client-viem';
const client = createX402Client({
wallet: { type: 'account', account },
// Protocol version (default: 2)
version: 2,
// Authorization expiry in seconds (default: 3600)
defaultExpiry: 7200,
// Custom nonce generator - MUST return bytes32 hex string
nonceGenerator: () => `0x${Date.now().toString(16).padStart(64, '0')}` as `0x${string}`,
// Enable debug logging
debug: true,
});
Nonce Format: The nonceGenerator must return a bytes32 hex string (64 hex characters after 0x). This is required for EIP-712 signature compatibility with the x402 specification.
Extension Hooks
The client supports an extension hook system for handling protocol extensions like Sign-In-With-X and Payment Identifier.
Using Hooks
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: [
createSIWxHook({
domain: 'example.com',
statement: 'Sign in to access premium content'
}),
createPaymentIdHook(),
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');
Hook Order
Hooks execute in array order.
Custom Hooks
Create custom hooks for your own extensions:
import { createCustomHook } from '@armory-sh/extensions';
const myHook = createCustomHook({
key: 'my-extension',
handler: async (context) => {
// context.payload - the payment payload (when available)
// context.paymentContext - the original payment required context
// context.serverExtensions - extensions requested by server
if (context.payload) {
context.payload.extensions = {
...(context.payload.extensions ?? {}),
'my-extension': { customData: 'value' }
};
}
},
priority: 75
});
const client = createX402Client({
wallet: { type: 'account', account },
hooks: [myHook]
});
Hook Execution Points
Hooks can execute at:
onPaymentRequired
selectRequirement
beforeSignPayment
afterPaymentResponse
onError
Exports
| Export | Description |
|---|
createX402Client | Create a full x402 client |
createX402Transport | Create a fetch function for payments |
armoryPay | One-line payment function |
executeHooks | Execute extension hooks |
mergeExtensions | Merge extension objects |