Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions typescript/examples/x402-http-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# x402 HTTP Client Example

Demonstrates using Ampersend with the standard x402 fetch wrapper for HTTP API payments.

## Overview

This example shows how to add Ampersend payment authorization to x402-protected HTTP APIs. It uses the same `@x402/fetch` wrapper as the official x402 SDK, with minimal additions for Ampersend integration.

**Compare with the [official x402-v2 fetch example](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/fetch) to see the minimal setup difference.**

## Installation

```bash
# From the ampersend-examples root
pnpm install

# Or install this package specifically
cd typescript/examples/x402-http-client
pnpm install
```

## Usage

Set your private key and run:

```bash
PRIVATE_KEY=0x... pnpm dev
```

## How It Works

The example demonstrates the core Ampersend pattern for HTTP payments:

```typescript
import { x402Client, wrapFetchWithPayment } from "@x402/fetch"
import { AccountWallet, NaiveTreasurer } from "@ampersend_ai/ampersend-sdk"
import { wrapWithAmpersend } from "@ampersend_ai/ampersend-sdk/x402"

// --- Standard x402 setup (same as official example) ---
const client = new x402Client()

// --- Ampersend additions (replaces registerExactEvmScheme) ---
const wallet = AccountWallet.fromPrivateKey(privateKey)
const treasurer = new NaiveTreasurer(wallet) // Decides whether to pay
wrapWithAmpersend(client, treasurer, ["base", "base-sepolia"])

// --- Use it (identical to official example) ---
const fetchWithPayment = wrapFetchWithPayment(fetch, client)
const response = await fetchWithPayment("https://paid-api.example.com/resource")
```

## Comparison with x402-v2

| x402-v2 Official | Ampersend | Purpose |
|------------------|-----------|---------|
| `privateKeyToAccount(key)` | `AccountWallet.fromPrivateKey(key)` | Wallet creation |
| `registerExactEvmScheme(client, { signer })` | `wrapWithAmpersend(client, treasurer, networks)` | Payment registration |
| - | `new NaiveTreasurer(wallet)` | Payment authorization |

The key difference: Ampersend uses a **Treasurer** pattern that allows sophisticated payment policies (budgets, approvals, limits) instead of auto-signing everything.

## Development

```bash
pnpm build # Build TypeScript
pnpm dev # Run with tsx
pnpm lint # Run ESLint
pnpm format # Check formatting
```

## Project Structure

```
src/
└── index.ts # Main example demonstrating HTTP payment flow
```

## Learn More

- [HTTP x402 Adapter Documentation](https://github.com/edgeandnode/ampersend-sdk/tree/main/typescript/packages/ampersend-sdk/src/x402/http)
- [Ampersend SDK Documentation](https://github.com/edgeandnode/ampersend-sdk)
- [x402 Protocol](https://github.com/coinbase/x402)
3 changes: 3 additions & 0 deletions typescript/examples/x402-http-client/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import config from "../../eslint.config.mjs"

export default config
27 changes: 27 additions & 0 deletions typescript/examples/x402-http-client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@edgeandnode/x402-http-client-example",
"description": "Example x402 HTTP client with Ampersend payment handling",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "tsx src/index.ts",
"build": "tsc -b tsconfig.json",
"clean": "rm -rf dist .tsbuildinfo",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier . --check --ignore-path ../../.prettierignore",
"format:fix": "prettier . --write --list-different --ignore-path ../../.prettierignore"
},
"dependencies": {
"@ampersend_ai/ampersend-sdk": "^0.0.3",
"@modelcontextprotocol/sdk": "github:edgeandnode/mcp-typescript-sdk#2de06543904483073d8cc13db1d0e08e16601081",
"@x402/core": "^2.1.0",
"@x402/fetch": "^2.1.0",
"fastmcp": "github:edgeandnode/fastmcp#6446ea7b56eb291a6d4d7321e4a41ff0aacba1ef",
"x402": "^0.6.6"
},
"devDependencies": {
"tsx": "^4.21.0"
}
}
26 changes: 26 additions & 0 deletions typescript/examples/x402-http-client/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { x402Client, wrapFetchWithPayment } from "@x402/fetch"
import { AccountWallet, NaiveTreasurer } from "@ampersend_ai/ampersend-sdk"
import { wrapWithAmpersend } from "@ampersend_ai/ampersend-sdk/x402"

async function main() {
const privateKey = process.env.PRIVATE_KEY as `0x${string}`
if (!privateKey) {
console.error("PRIVATE_KEY environment variable is required")
process.exit(1)
}

// --- Standard x402 setup (same as official example) ---
const client = new x402Client()

// --- Ampersend additions (replaces registerExactEvmScheme) ---
const wallet = AccountWallet.fromPrivateKey(privateKey)
const treasurer = new NaiveTreasurer(wallet) // Decides whether to pay
wrapWithAmpersend(client, treasurer, ["base", "base-sepolia"])

// --- Use it (identical to official example) ---
const fetchWithPayment = wrapFetchWithPayment(fetch, client)
const response = await fetchWithPayment("https://paid-api.example.com/resource")
console.log("Response status:", response.status)
}

main().catch(console.error)
9 changes: 9 additions & 0 deletions typescript/examples/x402-http-client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.jsonc",
"include": ["src/**/*"],
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"types": ["node"]
}
}