Skip to content

Commit 997bf57

Browse files
committed
feat: add x402 payment tool example
Demonstrates how to build a payment-enabled tool for NeMo Agent Toolkit that handles HTTP 402 (Payment Required) responses using the x402 protocol. When an agent calls a paid API and receives HTTP 402, this tool: - Parses x402 payment requirements from the response - Evaluates cost against configurable spending policy - Signs a payment proof using the agent's wallet (key isolated) - Retries the request with payment proof attached Uses @register_function with FunctionBaseConfig, valid NAT workflow configs (functions/llms/workflow with _type refs), and nat.components entry point registration. Tools: fetch_paid_api (402 handling + payment) and get_payment_status (spending awareness). Includes mock server for e2e testing. Also adds Allowlist, Coinbase, Ethereum, and env to Vale's accept.txt for x402/blockchain terminology. Related: NVIDIA/NeMo-Agent-Toolkit#1806 Signed-off-by: up2itnow0822 <up2itnow0822@users.noreply.github.com>
1 parent 27ac411 commit 997bf57

File tree

9 files changed

+1003
-0
lines changed

9 files changed

+1003
-0
lines changed

ci/vale/styles/config/vocabularies/nemo-agent-toolkit-examples/accept.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Regular expressions are parsed according to the Go syntax: https://golang.org/pkg/regexp/syntax/
44

55
[Aa]gentic
6+
[Aa]llowlist(ed|ing)?
67
[Aa]gno
78
AIQ
89
API(s?)
@@ -24,6 +25,7 @@ arXiv
2425
# clangd is never capitalized even at the start of a sentence https://clangd.llvm.org/
2526
clangd
2627
CMake
28+
Coinbase
2729
[Cc]omposability
2830
[Cc]omposable
2931
Conda
@@ -48,6 +50,8 @@ DB(s?)
4850
[Dd]evcontainer(s?)
4951
[Dd]ocstring(s?)
5052
[Ee]mbedder(s?)
53+
env
54+
Ethereum
5155
[Ee]ngineerable
5256
[Ee]val
5357
[Ee]xplainability
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Local config (copied from .example.yml)
2+
src/nat_x402_payment/configs/payment-agent.yml
3+
.venv/
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
<!--
2+
SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
18+
# x402 Payment Tool for NeMo Agent Toolkit
19+
20+
## Overview
21+
22+
### The Problem
23+
24+
AI agents increasingly need to interact with paid APIs and services. When an agent encounters an HTTP 402 (Payment Required) response, it needs to evaluate the cost, authorize payment, and retry — all autonomously. Unlike regular API errors, payment operations are **irreversible**, requiring security guarantees beyond standard tool integrations.
25+
26+
### The Solution
27+
28+
This example implements a payment-enabled tool for NeMo Agent Toolkit using `@register_function` that handles [x402](https://github.com/coinbase/x402) payment negotiation within a ReAct agent loop.
29+
30+
### How It Works
31+
32+
```
33+
Agent receives user query
34+
35+
36+
fetch_paid_api tool called with target URL
37+
38+
39+
API responds with HTTP 402 + x402 payment requirements
40+
41+
42+
Tool checks spending policy (per-tx cap, daily limit, recipient allowlist)
43+
44+
├── DENIED → Return denial reason to agent
45+
46+
47+
Wallet signer (isolated process) signs the payment
48+
49+
50+
Tool retries request with X-PAYMENT header
51+
52+
53+
Agent receives data and continues reasoning
54+
```
55+
56+
## Best Practices for x402 Payment Tools
57+
58+
### 1. Isolate Wallet Keys from the Agent Process
59+
60+
Payment tools handle irreversible value transfer. The signing key must never live in the same process as the agent.
61+
62+
| Mode | Key Location | Use Case |
63+
|------|-------------|----------|
64+
| **Inline** (dev only) | `WALLET_PRIVATE_KEY` env var | Local testing with mock server |
65+
| **Remote signer** (production) | Separate process via `WALLET_SIGNER_URL` | Any deployment with real funds |
66+
67+
The remote signer pattern ensures that even if the agent process is compromised, the attacker cannot sign arbitrary transactions — the signer only accepts pre-validated payment requests.
68+
69+
### 2. Enforce Spending Policy Before Signing
70+
71+
Spending limits are checked **before** the wallet is asked to sign, not after. This prevents a compromised or hallucinating agent from constructing valid payment transactions that exceed budget.
72+
73+
```yaml
74+
# In your NAT workflow config:
75+
functions:
76+
fetch_paid_api:
77+
_type: fetch_paid_api
78+
max_per_transaction: 0.10 # Max USDC per payment
79+
max_daily_spend: 5.00 # Daily cap
80+
allowed_recipients: # Only these addresses can receive funds
81+
- "0x..."
82+
```
83+
84+
### 3. Allowlist Payment Recipients
85+
86+
Never allow an agent to pay arbitrary addresses. Configure `allowed_recipients` with the addresses of your known API providers. Any payment to an unlisted address is rejected before signing.
87+
88+
### 4. Log Every Payment Attempt
89+
90+
The `get_payment_status` tool provides the agent with spending awareness and gives operators a full audit trail. Every payment attempt (successful, denied, or failed) is logged with timestamp, amount, recipient, and transaction hash.
91+
92+
## Prerequisites
93+
94+
- Python >= 3.11
95+
- NeMo Agent Toolkit >= 1.4.0 (`pip install nvidia-nat[langchain]`)
96+
- An NVIDIA API key for NIM models (set `NVIDIA_API_KEY`)
97+
- For testing: no wallet needed (mock server accepts any signature)
98+
- For production: an Ethereum wallet with USDC on Base network
99+
100+
## Quick Start
101+
102+
### 1. Install the Example
103+
104+
```bash
105+
cd examples/x402_payment_tool
106+
pip install -e .
107+
```
108+
109+
### 2. Start the Mock x402 Server
110+
111+
```bash
112+
python scripts/mock_x402_server.py &
113+
# Server runs on http://localhost:8402
114+
# GET /v1/market-data → 402 (requires payment)
115+
# GET /v1/market-data + X-PAYMENT header → 200 (mock data)
116+
```
117+
118+
### 3. Configure and Run
119+
120+
```bash
121+
# Copy example config
122+
cp src/nat_x402_payment/configs/payment-agent.example.yml \
123+
src/nat_x402_payment/configs/payment-agent.yml
124+
125+
# Set wallet key (any hex string works with mock server)
126+
export WALLET_PRIVATE_KEY="0x0000000000000000000000000000000000000000000000000000000000000001"
127+
128+
# Set NVIDIA API key for the LLM
129+
export NVIDIA_API_KEY="your-nvidia-api-key"
130+
131+
# Run the agent
132+
nat run --config_file src/nat_x402_payment/configs/payment-agent.yml
133+
```
134+
135+
### 4. Test the Agent
136+
137+
Once the agent is running, try prompts like:
138+
139+
```
140+
> Fetch the premium market data from http://localhost:8402/v1/market-data
141+
```
142+
143+
The agent will:
144+
1. Call `fetch_paid_api` with the URL
145+
2. Receive a 402 response
146+
3. Evaluate the cost (0.05 USDC) against the spending policy
147+
4. Sign payment and retry
148+
5. Return the market data
149+
150+
```
151+
> What's my current payment spending status?
152+
```
153+
154+
The agent will call `get_payment_status` and report daily spend and recent transactions.
155+
156+
## File Structure
157+
158+
```
159+
x402_payment_tool/
160+
├── README.md
161+
├── pyproject.toml
162+
├── scripts/
163+
│ └── mock_x402_server.py # Mock paid API for testing
164+
└── src/nat_x402_payment/
165+
├── __init__.py
166+
├── register.py # NAT tool registration (@register_function)
167+
├── wallet.py # Wallet signing abstraction (inline/remote)
168+
└── configs/
169+
└── payment-agent.example.yml # NAT workflow configuration
170+
```
171+
172+
## Configuration Reference
173+
174+
### Spending Policy
175+
176+
| Parameter | Default | Description |
177+
|-----------|---------|-------------|
178+
| `max_per_transaction` | 0.10 | Maximum USDC per single payment |
179+
| `max_daily_spend` | 5.00 | Daily spending cap in USDC |
180+
| `allowed_recipients` | [] | Allowlisted addresses (empty = allow all) |
181+
| `wallet_signer_url` | "" | Remote signer URL (empty = inline mode) |
182+
| `request_timeout` | 30.0 | HTTP request timeout in seconds |
183+
184+
### Wallet Modes
185+
186+
**Inline (development):**
187+
```bash
188+
export WALLET_PRIVATE_KEY="0x..."
189+
```
190+
191+
**Remote signer (production):**
192+
```yaml
193+
functions:
194+
fetch_paid_api:
195+
_type: fetch_paid_api
196+
wallet_signer_url: "http://localhost:8900"
197+
```
198+
199+
The remote signer exposes three endpoints:
200+
- `GET /address` — wallet public address
201+
- `GET /balance?asset=...&network=...` — token balance
202+
- `POST /sign` — sign a payment request
203+
204+
## References
205+
206+
- [x402 Protocol (Coinbase)](https://github.com/coinbase/x402) — HTTP 402 payment standard
207+
- [agent-wallet-sdk](https://github.com/up2itnow0822/agent-wallet-sdk) — Non-custodial agent wallets with on-chain spending policies
208+
- [agentpay-mcp](https://github.com/up2itnow0822/agentpay-mcp) — MCP payment server implementation
209+
- Related issue: [NVIDIA/NeMo-Agent-Toolkit#1806](https://github.com/NVIDIA/NeMo-Agent-Toolkit/issues/1806)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
[build-system]
17+
build-backend = "setuptools.build_meta"
18+
requires = ["setuptools >= 64", "setuptools-scm>=8"]
19+
20+
[tool.setuptools_scm]
21+
git_describe_command = "git describe --long --first-parent"
22+
root = "../.."
23+
24+
[project]
25+
name = "nat_x402_payment"
26+
dynamic = ["version"]
27+
dependencies = [
28+
"nvidia-nat[langchain]>=1.4.0a0,<1.5.0",
29+
"httpx>=0.27.0",
30+
"eth-account>=0.13.0",
31+
]
32+
requires-python = ">=3.11,<3.14"
33+
description = "x402 payment-enabled tool for NeMo Agent Toolkit — handle HTTP 402 payment negotiation in agent loops"
34+
keywords = ["ai", "payments", "x402", "nvidia", "agents", "wallet"]
35+
classifiers = ["Programming Language :: Python"]
36+
37+
[project.entry-points.'nat.components']
38+
nat_x402_payment = "nat_x402_payment.register"
39+
40+
[tool.setuptools.packages.find]
41+
where = ["src"]

0 commit comments

Comments
 (0)