Reference@t402/axios

@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 axios

Quick 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
): AxiosInstance

Parameters

ParameterTypeDescription
axiosInstanceAxiosInstanceThe Axios instance to wrap
clientt402ClientConfigured 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
): AxiosInstance

Example

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:

  1. Intercepts 402 - Catches responses with status 402
  2. Parses requirements - Extracts payment requirements from response
  3. Creates payment - Signs a payment authorization
  4. Retries request - Sends original request with payment header
  5. 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 wrapAxiosWithPayment

Multi-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';