Skip to content
Back to skills

003 Name Skill 30a4884f

ASecurity

Create x402 HTTP clients with Fetch and Axios that automatically handle 402 payments on Algorand. Use when building applications that consume x402-protected APIs, setting up automatic payment handling with wrapFetchWithPayment or wrapAxiosWithPayment, implementing ClientAvmSigner for browser wallets or Node.js private keys, configuring payment policies, or handling 402 payment flows. Strong triggers include "create x402 client", "wrap fetch with payment", "wrap axios with payment", "automatic...

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
documentationtypescriptgobashreactnodegitapidocumentation

Works with

  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 003-name-skill_30a4884f --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 003 Name Skill 30a4884f?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 003 Name Skill 30a4884f
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-003-name-skill-30a4884f/badge)](https://www.skillsdirectory.com/skills/tools-only-003-name-skill-30a4884f)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
---
name: create-typescript-x402-client
description: Create x402 HTTP clients with Fetch and Axios that automatically handle 402 payments on Algorand. Use when building applications that consume x402-protected APIs, setting up automatic payment handling with wrapFetchWithPayment or wrapAxiosWithPayment, implementing ClientAvmSigner for browser wallets or Node.js private keys, configuring payment policies, or handling 402 payment flows. Strong triggers include "create x402 client", "wrap fetch with payment", "wrap axios with payment", "automatic 402 payment", "ClientAvmSigner", "pay for API with USDC", "x402 fetch", "x402 axios".
---

# Creating x402 HTTP Clients (Fetch and Axios)

Build HTTP clients that automatically detect `402 Payment Required` responses, sign Algorand transactions, and retry requests with payment proof -- all transparently.

## Prerequisites

Before using this skill, ensure:

1. **Node.js or browser environment** with TypeScript support
2. **An Algorand wallet or private key** for signing payment transactions
3. **USDC balance** on the target network (testnet or mainnet) in the payer's account

## Core Workflow: The 402 Payment Flow

The key insight is that `wrapFetchWithPayment` and `wrapAxiosWithPayment` intercept 402 responses, sign a transaction group, and retry the original request with the payment header -- all automatically:

```
Client Request (GET /api/premium)
         |
         v
   Server Response
         |
         +-- Status != 402 --> Return response as-is
         |
         +-- Status == 402 -->
               |
               +-- Parse PaymentRequired (headers V2 / body V1)
               +-- Select scheme via registered x402Client
               +-- Build atomic transaction group
               +-- Sign with ClientAvmSigner (wallet or private key)
               +-- Encode PAYMENT-SIGNATURE header
               +-- Retry original request with payment header
               |
               v
           Return retried response
```

## How to Proceed

### Step 1: Install Dependencies

For Fetch-based clients:
```bash
npm install @x402-avm/fetch @x402-avm/avm algosdk
```

For Axios-based clients:
```bash
npm install @x402-avm/axios @x402-avm/avm algosdk axios
```

### Step 2: Implement a ClientAvmSigner

The `ClientAvmSigner` interface is what bridges your wallet or private key to the x402 payment system.

**Interface:**
```typescript
interface ClientAvmSigner {
  address: string;
  signTransactions(
    txns: Uint8Array[],
    indexesToSign?: number[],
  ): Promise<(Uint8Array | null)[]>;
}
```

**For Node.js (private key):**
```typescript
import algosdk from "algosdk";

const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
const address = algosdk.encodeAddress(secretKey.slice(32));

const signer = {
  address,
  signTransactions: async (txns: Uint8Array[], indexesToSign?: number[]) => {
    return txns.map((txn, i) => {
      if (indexesToSign && !indexesToSign.includes(i)) return null;
      const decoded = algosdk.decodeUnsignedTransaction(txn);
      const signed = algosdk.signTransaction(decoded, secretKey);
      return signed.blob;
    });
  },
};
```

**For Browser (@txnlab/use-wallet):**
```typescript
import { useWallet } from "@txnlab/use-wallet-react";
import type { ClientAvmSigner } from "@x402-avm/avm";

function useAvmSigner(): ClientAvmSigner | null {
  const { activeAccount, signTransactions } = useWallet();
  if (!activeAccount) return null;
  return {
    address: activeAccount.address,
    signTransactions: async (txns: Uint8Array[], indexesToSign?: number[]) => {
      return signTransactions(txns, indexesToSign);
    },
  };
}
```

### Step 3: Create and Configure the x402Client

```typescript
import { x402Client } from "@x402-avm/fetch"; // or "@x402-avm/axios"
import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";

const client = new x402Client();
registerExactAvmScheme(client, { signer });
```

### Step 4: Wrap Fetch or Axios

**Fetch:**
```typescript
import { wrapFetchWithPayment } from "@x402-avm/fetch";

const fetchWithPay = wrapFetchWithPayment(fetch, client);
const response = await fetchWithPay("https://api.example.com/premium-data");
```

**Axios:**
```typescript
import axios from "axios";
import { wrapAxiosWithPayment } from "@x402-avm/axios";

const api = wrapAxiosWithPayment(axios.create(), client);
const response = await api.get("https://api.example.com/premium-data");
```

### Step 5: Add Payment Policies (Optional)

Policies filter payment requirements before selection. They are applied in order:

```typescript
import type { PaymentPolicy } from "@x402-avm/fetch";

const maxAmount: PaymentPolicy = (version, reqs) => {
  return reqs.filter((r) => BigInt(r.amount ?? "0") <= BigInt("5000000"));
};

const preferAlgorand: PaymentPolicy = (version, reqs) => {
  const algoReqs = reqs.filter((r) => r.network.startsWith("algorand:"));
  return algoReqs.length > 0 ? algoReqs : reqs;
};

client.registerPolicy(preferAlgorand).registerPolicy(maxAmount);
```

### Step 6: Add Lifecycle Hooks (Optional)

Monitor and control the payment lifecycle:

```typescript
client.onBeforePaymentCreation(async ({ selectedRequirements }) => {
  const amountUSDC = Number(selectedRequirements.amount) / 1_000_000;
  console.log(`Paying $${amountUSDC.toFixed(6)} USDC`);
  if (amountUSDC > 10) {
    return { abort: true, reason: "Amount exceeds $10 limit" };
  }
});

client.onAfterPaymentCreation(async () => {
  console.log("Payment signed successfully");
});

client.onPaymentCreationFailure(async ({ error }) => {
  console.error("Payment failed:", error.message);
});
```

## Important Rules / Guidelines

1. **Always register a scheme before wrapping** -- `registerExactAvmScheme(client, { signer })` must be called before `wrapFetchWithPayment` or `wrapAxiosWithPayment`
2. **AVM_PRIVATE_KEY format** -- Base64-encoded 64-byte key (32-byte seed + 32-byte public key)
3. **Address derivation** -- Always use `algosdk.encodeAddress(secretKey.slice(32))`, never the first 32 bytes
4. **Single retry** -- The wrapper retries exactly once after 402. If the retry also returns 402, the error is propagated
5. **Interceptor order for Axios** -- Add your own interceptors first, then call `wrapAxiosWithPayment` last
6. **Config-based alternative** -- Use `wrapFetchWithPaymentFromConfig` / `wrapAxiosWithPaymentFromConfig` for declarative setup without manual `x402Client` construction
7. **Wildcard networks** -- Use `"algorand:*"` in config-based setups to match any Algorand network

## Config-Based Setup (Alternative)

Instead of creating an `x402Client` manually, use the config-based approach:

```typescript
import { wrapFetchWithPaymentFromConfig, type x402ClientConfig } from "@x402-avm/fetch";
import { ExactAvmScheme } from "@x402-avm/avm";

const config: x402ClientConfig = {
  schemes: [
    {
      network: "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
      client: new ExactAvmScheme(signer),
    },
  ],
  policies: [maxAmount],
};

const fetchWithPay = wrapFetchWithPaymentFromConfig(fetch, config);
```

## Common Errors / Troubleshooting

| Error | Cause | Solution |
|-------|-------|----------|
| `Failed to parse payment requirements` | Server returned 402 with invalid body | Check server is running x402-compatible middleware |
| `Failed to create payment payload` | Insufficient balance or wrong network | Ensure USDC balance on the correct network |
| `Payment already attempted` | Server returned 402 after payment was sent | Payment was rejected; check facilitator logs |
| `No network/scheme registered` | Server requires an unregistered network | Register the needed scheme with `registerExactAvmScheme` |
| `Payment creation aborted` | A `beforePaymentCreation` hook returned abort | Review hook logic; check amount limits |
| `All payment requirements were filtered out` | Policies removed all options | Relax policies or register additional schemes |
| `No client registered for x402 version: 2` | No schemes registered at all | Call `registerExactAvmScheme(client, { signer })` |

## Reading Payment Receipts

After a successful paid request, check the response header:

```typescript
import { decodePaymentResponseHeader } from "@x402-avm/fetch";

const paymentResponseHeader = response.headers.get("PAYMENT-RESPONSE");
if (paymentResponseHeader) {
  const receipt = decodePaymentResponseHeader(paymentResponseHeader);
  console.log("Transaction settled:", receipt);
}
```

## References / Further Reading

- [REFERENCE.md](./references/REFERENCE.md) - Detailed API reference
- [EXAMPLES.md](./references/EXAMPLES.md) - Complete code examples
- [x402-avm Fetch Examples](https://github.com/GoPlausible/x402-avm/tree/branch-v2-algorand-publish/examples/)
- [x402-avm Documentation](https://github.com/GoPlausible/.github/blob/main/profile/algorand-x402-documentation/)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…