@t402/axios
Axios interceptor that automatically handles 402 Payment Required responses. Seamlessly integrates with existing Axios-based applications.
Installation
npm install @t402/axios @t402/core axiosQuick Start
import axios from 'axios';
import { wrapAxiosWithPayment, t402Client } from '@t402/axios';
import { ExactEvmClient } from '@t402/evm/exact/client';
import { privateKeyToAccount } from 'viem/accounts';
// Create a signer
const account = privateKeyToAccount('0xYourPrivateKey');
// Create t402 client with payment schemes
const client = new t402Client()
.register('eip155:*', new ExactEvmClient(account));
// Wrap Axios instance
const api = wrapAxiosWithPayment(axios.create(), client);
// Make requests - payments handled automatically
const response = await api.get('https://api.example.com/premium');
console.log(response.data);API Reference
wrapAxiosWithPayment
Adds a response interceptor to handle 402 responses automatically.
function wrapAxiosWithPayment(
axiosInstance: AxiosInstance,
client: t402Client
): AxiosInstanceParameters
| Parameter | Type | Description |
|---|---|---|
axiosInstance | AxiosInstance | The Axios instance to wrap |
client | t402Client | Configured client for payment handling |
Returns: The wrapped Axios instance (same reference, modified in place).
Example
import axios from 'axios';
import { wrapAxiosWithPayment, t402Client } from '@t402/axios';
const client = new t402Client()
.register('eip155:8453', new ExactEvmClient(signer));
const api = wrapAxiosWithPayment(axios.create({
baseURL: 'https://api.example.com',
timeout: 30000,
}), client);wrapAxiosWithPaymentFromConfig
Wraps Axios with payment handling using a configuration object.
function wrapAxiosWithPaymentFromConfig(
axiosInstance: AxiosInstance,
config: t402ClientConfig
): AxiosInstanceExample
import axios from 'axios';
import { wrapAxiosWithPaymentFromConfig } from '@t402/axios';
import { ExactEvmClient } from '@t402/evm/exact/client';
const api = wrapAxiosWithPaymentFromConfig(axios.create(), {
schemes: [
{ network: 'eip155:*', client: new ExactEvmClient(signer) },
],
});How It Works
The interceptor hooks into Axios’s response error handling:
- Intercepts 402 - Catches responses with status 402
- Parses requirements - Extracts payment requirements from response
- Creates payment - Signs a payment authorization
- Retries request - Sends original request with payment header
- Returns response - Returns the successful response
// Internal flow (simplified)
axiosInstance.interceptors.response.use(
response => response,
async (error) => {
if (error.response?.status !== 402) {
throw error;
}
// Parse payment requirements
const paymentRequired = parsePaymentRequired(error.response);
// Create signed payment
const paymentPayload = await client.createPaymentPayload(paymentRequired);
// Add payment header and retry
error.config.headers['Payment-Signature'] = encodePayment(paymentPayload);
return axiosInstance.request(error.config);
}
);Usage Patterns
Base Configuration
const api = wrapAxiosWithPayment(axios.create({
baseURL: 'https://api.example.com',
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
}), client);
// All requests use the same configuration
await api.get('/premium/data');
await api.post('/premium/upload', { data: 'content' });Multiple API Clients
// Premium API with payments
const premiumApi = wrapAxiosWithPayment(axios.create({
baseURL: 'https://premium-api.example.com',
}), client);
// Free API without payments
const freeApi = axios.create({
baseURL: 'https://free-api.example.com',
});With Request Interceptors
const api = wrapAxiosWithPayment(axios.create(), client);
// Add auth header to all requests
api.interceptors.request.use((config) => {
config.headers.Authorization = `Bearer ${getToken()}`;
return config;
});
// Payment interceptor is already added by wrapAxiosWithPaymentMulti-Network Support
import { t402Client } from '@t402/axios';
import { ExactEvmClient } from '@t402/evm/exact/client';
import { ExactTonClient } from '@t402/ton/exact/client';
const client = new t402Client()
.register('eip155:*', new ExactEvmClient(evmSigner))
.register('ton:mainnet', new ExactTonClient(tonWallet));
const api = wrapAxiosWithPayment(axios.create(), client);
// Works with any server supporting these networks
await api.get('https://evm-service.com/data');
await api.get('https://ton-service.com/data');Error Handling
const api = wrapAxiosWithPayment(axios.create(), client);
try {
const response = await api.get('/premium/data');
console.log(response.data);
} catch (error) {
if (axios.isAxiosError(error)) {
if (error.message.includes('Failed to parse payment requirements')) {
console.error('Invalid payment requirements from server');
} else if (error.message.includes('Failed to create payment payload')) {
console.error('Could not sign payment');
} else if (error.response?.status === 402) {
// Payment retry failed
console.error('Payment failed after retry');
} else {
console.error('Request failed:', error.response?.status);
}
}
}Payment Response
Access settlement details from response headers:
import { decodePaymentResponseHeader } from '@t402/axios';
const response = await api.get('/premium/data');
// Check payment response
const paymentResponse = decodePaymentResponseHeader(
response.headers['payment-response']
);
if (paymentResponse) {
console.log('Transaction:', paymentResponse.transactionHash);
console.log('Network:', paymentResponse.network);
}With React Query
import { useQuery } from '@tanstack/react-query';
import { wrapAxiosWithPayment, t402Client } from '@t402/axios';
const api = wrapAxiosWithPayment(axios.create({
baseURL: 'https://api.example.com',
}), client);
function usePremiumData() {
return useQuery({
queryKey: ['premium-data'],
queryFn: async () => {
const response = await api.get('/premium/data');
return response.data;
},
});
}With Vue
// api.ts
import axios from 'axios';
import { wrapAxiosWithPayment, t402Client } from '@t402/axios';
export const api = wrapAxiosWithPayment(axios.create({
baseURL: import.meta.env.VITE_API_URL,
}), client);
// Component.vue
<script setup>
import { ref, onMounted } from 'vue';
import { api } from './api';
const data = ref(null);
onMounted(async () => {
const response = await api.get('/premium/data');
data.value = response.data;
});
</script>Payment Policy
Apply spending limits:
import { t402Client, PaymentPolicy } from '@t402/axios';
const policy: PaymentPolicy = {
maxAmount: '1000000', // Max 1 USDT per request
allowedNetworks: ['eip155:8453'],
};
const client = new t402Client({ policy })
.register('eip155:*', new ExactEvmClient(signer));
const api = wrapAxiosWithPayment(axios.create(), client);Retry Prevention
The interceptor prevents infinite payment loops:
// If payment fails, it won't retry again
// The __is402Retry flag prevents loops
const api = wrapAxiosWithPayment(axios.create(), client);
try {
await api.get('/premium/data');
} catch (error) {
// Will throw after one payment retry attempt
console.error('Payment failed');
}Type Exports
// Client
export { t402Client, t402HTTPClient } from '@t402/core/client';
// Configuration types
export type {
PaymentPolicy,
SchemeRegistration,
SelectPaymentRequirements,
t402ClientConfig,
} from '@t402/core/client';
// Utilities
export { decodePaymentResponseHeader } from '@t402/core/http';
// Protocol types
export type {
Network,
PaymentPayload,
PaymentRequired,
PaymentRequirements,
SchemeNetworkClient,
} from '@t402/core/types';Related
- @t402/fetch - Fetch wrapper
- @t402/core - Core protocol types
- @t402/evm - EVM payment scheme
- Client Guide - Client implementation guide