Agent 402 Documentation
Agent 402 is a lightweight, non-custodial payment control system for AI agents. This guide will walk you through setting up transaction monitoring and spending controls for your autonomous agents.
Quickstart
Get up and running in 5 minutes:
1. Create Your Account
Visit dashboard.agent402.pro and sign up with your email.
2. Generate API Key
Navigate to API Keys in the dashboard and click "Create API Key".
3. Register Your First Agent
Go to the Agents page and create an agent.
4. Test Authorizing Transactions
Try making your first authorization request:
curl -X POST https://api.agent402.pro/v1/authorize \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "$AGENT_ID",
"amount": "5.00",
"currency": "USDC",
"service": "OpenAI"
}'
Core Concepts
x402 Payment Flow
The diagram below shows how Agent 402 handles HTTP 402 (Payment Required) responses with automatic authorization and spending controls:
sequenceDiagram
participant Client as AI Agent
participant ResourceServer as Resource Server
participant Agent402 as Agent 402
participant Blockchain
Note over Client,Blockchain: x402 Payment Flow with Agent 402 Controls
Client->>ResourceServer: 1. GET /api/resource
ResourceServer-->>Client: 2. 402 Payment Required
{price, currency, paymentToken}
Note over Agent402: Agent 402
Spending Controls
Client->>Agent402: 4. POST /v1/authorize
{agent_id, amount, currency}
Note over Agent402: 5. Check spending limits
and rules
Agent402-->>Client: 6. Authorization response
{authorized: true}
Client->>ResourceServer: 7. Retry request with
X-Payment-Token header
ResourceServer->>Blockchain: 8. Submit transaction
Blockchain-->>ResourceServer: 9. Payment confirmed
ResourceServer-->>Client: 10. 200 OK - Resource data
Note over Agent402: Agent 402
Confirmation
Client->>Agent402: 11. POST /v1/confirm
{authorization_id, tx_hash}
Agent402-->>Client: 12. Confirmation
Key Components
Agents - Your AI systems that make transactions. Each agent is tracked separately.
Rules - Spending controls and limits you configure (velocity limits, amount limits, service allowlists).
Transactions - Individual payment events that are authorized, logged, and audited.
Integration
Test Resource Server
Agent 402 provides a test x402-compatible endpoint for development and testing. This endpoint simulates a paid API service that returns HTTP 402 Payment Required responses.
Endpoint: https://api.agent402.pro/demo/x402dice
What it does:
- Rolls dice and returns the results. Costs $0.01 USDC per roll (simulated)
- Returns HTTP 402 Payment Required with payment details
- If provided
X-PAYMENT-TOKEN, will return results of a dice roll
X-PAYMENT-TOKEN.
MCP (Claude Desktop)
Agent 402 extends the x402.org x402 MCP Server guide with payment controls and spending limits. This allows you to build MCP servers that handle paid API requests with automatic authorization checks.
What This Enables:
- Automatic payment handling for HTTP 402 (Payment Required) responses
- Spending controls and velocity limits on MCP tool calls
- Transaction monitoring and audit logs for Claude Desktop usage
Prerequisites:
- Node.js v20 or higher
- Claude Desktop with MCP support
- Agent 402 API key and registered agent
- A x402-compliant resource server (see Test Resource Server above)
1. Install Dependencies:
npm install @modelcontextprotocol/sdk axios
withPaymentControllerInterceptor function is included in the code tabs above. You can copy it directly into your project. In the future, this will be provided by the official @agent402/sdk package.
2. Create MCP Server with Payment Controls:
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
// Agent 402 Configuration
const AGENT402_API_KEY = process.env.AGENT402_API_KEY;
const AGENT402_AGENT_ID = process.env.AGENT402_AGENT_ID;
const AGENT402_API_URL = process.env.AGENT402_API_URL || "https://api.agent402.pro";
// Resource server URL (the x402-compatible endpoint)
const RESOURCE_SERVER_URL = process.env.RESOURCE_SERVER_URL || "https://api.agent402.pro/demo/x402dice";
// Blockchain configuration (for production use)
const PRIVATE_KEY = process.env.PRIVATE_KEY; // Your wallet private key
// Create axios client with Agent 402 interceptor
const client = axios.create({
baseURL: RESOURCE_SERVER_URL
});
// This extends the standard x402 pattern with Agent 402 spending controls.
// Standard x402 guide: https://x402.gitbook.io/x402/guides/mcp-server-with-x402
//
// Standard x402 withPaymentInterceptor (without Agent 402):
// withPaymentInterceptor(client, {
// privateKey: PRIVATE_KEY,
// onPaymentRequired: async (paymentData) => {
// // Direct blockchain payment without authorization checks
// return await processPayment(paymentData);
// }
// });
// Agent 402 version adds authorization layer before payment:
if (AGENT402_API_KEY && AGENT402_AGENT_ID) {
withPaymentControllerInterceptor(client, {
apiKey: AGENT402_API_KEY,
agentId: AGENT402_AGENT_ID
});
console.error("[Agent 402] Payment controls enabled");
} else {
console.error("[Agent 402] Warning: API key or agent ID not set - payment controls disabled");
}
// Create MCP server
const server = new Server(
{
name: "agent402-demo",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// Register tool handlers
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "roll_dice",
description: "Roll dice and get the results. This is a paid service ($0.01 USDC per roll) protected by Agent 402.",
inputSchema: {
type: "object",
properties: {
count: {
type: "number",
description: "Number of dice to roll (1-10)",
default: 3,
},
},
required: ["count"],
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "roll_dice") {
const count = request.params.arguments?.count || 3;
try {
// This request will automatically:
// 1. Check Agent 402 spending limits
// 2. Handle HTTP 402 response and authorize payment
// 3. Retry request with payment token
// 4. Confirm transaction
const response = await client.get("", {
params: { count }
});
return {
content: [
{
type: "text",
text: `🎲 Rolled ${count} dice: ${response.data.dice.join(', ')}\nTotal: ${response.data.total}\n\nThis roll was paid for using Agent 402 payment controls.`,
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error.message}`,
},
],
isError: true,
};
}
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
// Start the server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Agent 402 Demo MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
// Payment controller interceptor - handles HTTP 402 responses
// In the future, this will be provided by @agent402/sdk
function withPaymentControllerInterceptor(client, config) {
client.interceptors.response.use(
(response) => response,
async (error) => {
// Check if this is a 402 Payment Required response
if (error.response?.status === 402) {
const paymentData = error.response.data;
const paymentToken = error.response.headers['x-payment-token'];
console.error(`[Agent 402] Payment Required: ${paymentData.price} ${paymentData.currency}`);
console.error(`[Agent 402] Service: ${paymentData.message}`);
// Step 1: Request authorization from Agent 402
try {
const authResponse = await axios.post(
`${config.apiUrl || 'https://api.agent402.pro'}/v1/authorize`,
{
agent_id: config.agentId,
amount: paymentData.price,
currency: paymentData.currency,
service: error.response.headers['x-agent402-service'] || 'Unknown',
metadata: {
endpoint: error.response.headers['x-agent402-endpoint'],
payment_token: paymentToken
}
},
{
headers: {
'X-API-Key': config.apiKey,
'Content-Type': 'application/json'
}
}
);
// Step 2: Check if payment was authorized
if (authResponse.data.authorized === true) {
console.error(`[Agent 402] Payment authorized: ${authResponse.data.transaction_id}`);
// Step 3: Retry the original request with payment token
const originalRequest = error.config;
originalRequest.headers['X-Payment-Token'] = paymentToken;
const retryResponse = await axios(originalRequest);
// Step 4: Confirm the transaction with Agent 402
await axios.post(
`${config.apiUrl || 'https://api.agent402.pro'}/v1/confirm`,
{
transaction_id: authResponse.data.transaction_id,
auth_token: authResponse.data.authorization_token,
tx_hash: `demo_${Date.now()}`, // In production, use actual blockchain tx hash
status: 'completed',
timestamp: new Date().toISOString()
},
{
headers: {
'X-API-Key': config.apiKey,
'Content-Type': 'application/json'
}
}
);
console.error(`[Agent 402] Payment confirmed`);
return retryResponse;
} else {
throw new Error(`Payment not authorized: ${authResponse.data.status}`);
}
} catch (authError) {
console.error(`[Agent 402] Authorization failed:`, authError.message);
throw authError;
}
}
throw error;
}
);
}
3. Configure Claude Desktop:
# Edit: ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"agent402-demo": {
"command": "node",
"args": ["/path/to/agent402-mcp-server/server.js"],
"env": {
"AGENT402_API_KEY": "ak_live_1234567890abcdef",
"AGENT402_AGENT_ID": "claude-assistant",
"AGENT402_API_URL": "https://api.agent402.pro",
"RESOURCE_SERVER_URL": "https://api.agent402.pro/demo/x402dice",
"PRIVATE_KEY": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}
}
}
Environment Variables Explained:
AGENT402_API_KEY- Your Agent 402 API key from the dashboardAGENT402_AGENT_ID- Your registered agent ID (create in dashboard)AGENT402_API_URL- Agent 402 API endpoint for authorization/confirmationRESOURCE_SERVER_URL- The x402-compatible resource you want to access (test endpoint)PRIVATE_KEY- Your wallet private key (for production; not used in demo mode)
4. Test the MCP Server:
Restart Claude Desktop and try asking:
"Can you roll 3 dice for me?"
Claude will use the roll_dice tool, which will:
- Request the paid resource (costs $0.01 USDC)
- Receive HTTP 402 Payment Required
- Automatically authorize with Agent 402 (checking your spending rules)
- Retry with payment token and get the dice results
- Confirm the transaction
How It Works:
The withPaymentControllerInterceptor adds an axios response interceptor that automatically:
- Detects HTTP 402 responses - When a resource server requires payment, it returns a 402 status with payment details
- Requests authorization from Agent 402 - Calls
/v1/authorizewith the payment amount and your agent ID to check spending limits - Retries the request with payment token - If authorized, adds the
X-Payment-Tokenheader and retries the original request - Confirms the transaction - After successful payment, calls
/v1/confirmto record the transaction
LangChain (Python)
Build autonomous LangChain agents with automatic payment controls and spending limits. This integration provides a Python wallet class that handles HTTP 402 responses seamlessly.
What This Enables:
- Autonomous agents that make paid API calls safely
- Custom LangChain tools with built-in payment authorization
- Automatic retry logic with exponential backoff
- Spending controls prevent runaway agent costs
Prerequisites:
- Python 3.10 or higher
- Agent 402 API key and registered agent
- A x402-compliant resource server (see Test Resource Server above)
1. Install Dependencies:
pip install requests
requests. For building custom LangChain tools, also install: pip install langchain pydantic
2. Create Agent402Wallet Class:
"""Agent 402 Wallet Class with Payment Controls"""
import requests
import time
from typing import Dict, Any, Optional
from datetime import datetime
# Uncomment for production Ethereum payments:
# from web3 import Web3
# from eth_account import Account
# from decimal import Decimal
class Agent402Wallet:
"""Wallet that intercepts HTTP 402 and handles authorization"""
def __init__(
self,
api_key: str,
agent_id: str,
api_url: str = "https://api.agent402.pro",
private_key: Optional[str] = None,
rpc_url: Optional[str] = None
):
self.api_key = api_key
self.agent_id = agent_id
self.api_url = api_url
self.session = requests.Session()
# Uncomment for production Ethereum payments:
# self.private_key = private_key
# self.rpc_url = rpc_url or "https://base-mainnet.g.alchemy.com/v2/YOUR_KEY"
# self.w3 = Web3(Web3.HTTPProvider(self.rpc_url)) if rpc_url else None
# self.account = Account.from_key(private_key) if private_key else None
#
# # USDC contract on Base mainnet
# self.usdc_address = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
def get(self, url: str, **kwargs) -> requests.Response:
"""Make a GET request with automatic 402 handling"""
response = self.session.get(url, **kwargs)
if response.status_code == 402:
return self._handle_payment_required(response, 'GET', url, **kwargs)
return response
def _handle_payment_required(self, response, method: str, url: str, **kwargs):
"""Handle HTTP 402 by authorizing payment and retrying"""
payment_data = response.json()
payment_token = response.headers.get('x-payment-token')
print(f"[Agent 402] Payment Required: {payment_data.get('price')} {payment_data.get('currency')}")
# Step 1: Request authorization
auth_response = self._authorize_payment(
amount=payment_data.get('price'),
currency=payment_data.get('currency'),
service=response.headers.get('x-agent402-service', 'Unknown'),
endpoint=url,
payment_token=payment_token
)
if not auth_response.get('authorized'):
raise Exception(f"Payment not authorized: {auth_response.get('reason')}")
print(f"[Agent 402] Payment authorized: {auth_response['transaction_id']}")
# Step 2: Send blockchain payment (production only)
# Uncomment for production:
# tx_hash = self._send_blockchain_payment(
# recipient=payment_data.get('recipient_address'),
# amount=payment_data.get('price'),
# currency=payment_data.get('currency')
# )
tx_hash = f'demo_{int(time.time() * 1000)}' # Demo mode
# Step 3: Retry with payment token
kwargs.setdefault('headers', {})
kwargs['headers']['X-Payment-Token'] = payment_token
retry_response = self.session.get(url, **kwargs) if method == 'GET' else self.session.post(url, **kwargs)
# Step 4: Confirm transaction
self._confirm_transaction(
transaction_id=auth_response['transaction_id'],
auth_token=auth_response['authorization_token'],
status='completed' if retry_response.status_code == 200 else 'failed',
tx_hash=tx_hash
)
print(f"[Agent 402] Payment confirmed")
return retry_response
def _authorize_payment(self, amount: str, currency: str, service: str, endpoint: str, payment_token: str) -> Dict[str, Any]:
"""Request authorization from Agent 402 API"""
url = f"{self.api_url}/v1/authorize"
headers = {'X-API-Key': self.api_key, 'Content-Type': 'application/json'}
payload = {
'agent_id': self.agent_id,
'amount': amount,
'currency': currency,
'service': service,
'metadata': {'endpoint': endpoint, 'payment_token': payment_token}
}
response = requests.post(url, json=payload, headers=headers)
# Check if authorization was denied
if response.status_code != 200:
try:
error_data = response.json()
error_msg = error_data.get('message', 'Unknown error')
error_type = error_data.get('error', 'unknown')
raise Exception(f"Payment not authorized [{error_type}]: {error_msg}")
except ValueError:
response.raise_for_status()
return response.json()
def _confirm_transaction(self, transaction_id: str, auth_token: str, status: str, tx_hash: Optional[str] = None) -> Dict[str, Any]:
"""Confirm transaction with Agent 402 API"""
url = f"{self.api_url}/v1/confirm"
headers = {'X-API-Key': self.api_key, 'Content-Type': 'application/json'}
payload = {
'transaction_id': transaction_id,
'auth_token': auth_token,
'status': status,
'timestamp': datetime.utcnow().isoformat() + 'Z',
'tx_hash': tx_hash or f'demo_{int(time.time() * 1000)}'
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
# def _send_blockchain_payment(self, recipient: str, amount: str, currency: str) -> str:
# """Send USDC payment on Base blockchain (production only)"""
# if not self.w3 or not self.account:
# raise Exception("Web3 not configured")
#
# # Convert to USDC smallest unit (6 decimals)
# amount_wei = int(Decimal(amount) * Decimal(10**6))
#
# # Get USDC contract and build transfer transaction
# usdc_contract = self.w3.eth.contract(
# address=self.w3.to_checksum_address(self.usdc_address),
# abi=[{"constant": False, "inputs": [{"name": "_to", "type": "address"},
# {"name": "_value", "type": "uint256"}], "name": "transfer",
# "outputs": [{"name": "", "type": "bool"}], "type": "function"}]
# )
#
# transaction = usdc_contract.functions.transfer(
# self.w3.to_checksum_address(recipient), amount_wei
# ).build_transaction({
# 'chainId': self.w3.eth.chain_id,
# 'gas': 100000,
# 'gasPrice': self.w3.eth.gas_price,
# 'nonce': self.w3.eth.get_transaction_count(self.account.address),
# })
#
# # Sign and send
# signed = self.w3.eth.account.sign_transaction(transaction, self.private_key)
# tx_hash = self.w3.eth.send_raw_transaction(signed.raw_transaction)
# receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
#
# if receipt.status != 1:
# raise Exception(f"Transaction failed: {tx_hash.hex()}")
#
# return tx_hash.hex()
"""Simple Usage Example"""
from agent402_wallet import Agent402Wallet
import os
# Initialize wallet
wallet = Agent402Wallet(
api_key=os.getenv("AGENT402_API_KEY"),
agent_id=os.getenv("AGENT402_AGENT_ID", "dice-demo")
)
# Roll three dice
resource_url = "https://api.agent402.pro/demo/x402dice"
response = wallet.get(resource_url, params={'count': 3})
if response.status_code == 200:
data = response.json()
print(f"Dice: {data['dice']}") # e.g., [4, 2, 5]
print(f"Total: {data['total']}") # e.g., 11
# Example: Roll dice multiple times with payment controls
for i in range(10):
try:
response = wallet.get(resource_url, params={'count': 3})
if response.status_code == 200:
data = response.json()
print(f"Roll {i+1}: {data['dice']} = {data['total']}")
else:
print(f"Roll {i+1} failed: {response.status_code}")
except Exception as e:
print(f"Roll {i+1} error: {e}")
# Agent 402 spending limit may have been reached
break
"""Three Dice Distribution Analysis"""
import os
import time
from collections import Counter
from agent402_wallet import Agent402Wallet
AGENT402_API_KEY = os.getenv("AGENT402_API_KEY")
AGENT402_AGENT_ID = os.getenv("AGENT402_AGENT_ID", "dice-demo")
wallet = Agent402Wallet(api_key=AGENT402_API_KEY, agent_id=AGENT402_AGENT_ID)
rolls = []
backoff_time = 1
num_rolls = 50
print(f"Rolling three dice {num_rolls} times...\n")
for roll_num in range(1, num_rolls + 1):
print(f"[Roll {roll_num}/{num_rolls}]", end=" ")
try:
resource_url = "https://api.agent402.pro/demo/x402dice"
response = wallet.get(resource_url, params={'count': 3})
if response.status_code == 200:
data = response.json()
rolls.append(data['total'])
print(f"🎲 {data['dice']} → {data['total']}")
backoff_time = 1
else:
print(f"✗ Failed")
except Exception as e:
if "velocity limit" in str(e).lower():
print(f"✗ Limit reached, backing off {backoff_time}s...")
time.sleep(backoff_time)
backoff_time = min(backoff_time * 2, 60)
else:
print(f"✗ Error: {e}")
break
time.sleep(0.5)
# Analyze distribution
print(f"\n{'='*60}\nDISTRIBUTION ANALYSIS\n{'='*60}\n")
print(f"Total Rolls: {len(rolls)}\n")
distribution = Counter(rolls)
max_count = max(distribution.values()) if distribution else 0
for total in range(3, 19):
count = distribution.get(total, 0)
percentage = (count / len(rolls) * 100) if rolls else 0
bar = "â–ˆ" * int((count / max_count * 40)) if max_count > 0 else ""
print(f"{total:2d}: {bar} {count:3d} ({percentage:5.1f}%)")
if rolls:
avg = sum(rolls) / len(rolls)
print(f"\nAverage: {avg:.2f} (Expected: 10.50, Deviation: {avg - 10.5:+.2f})")
3. Run the Demo:
export AGENT402_API_KEY="your-api-key"
export AGENT402_AGENT_ID="test"
python demo.py
Expected Output:
Rolling three dice 50 times...
[Roll 1/50] [Agent 402] Payment Required: 0.01 USDC
[Agent 402] Payment authorized: txn_abc123
[Agent 402] Payment confirmed
🎲 [4, 2, 5] → 11
[Roll 2/50] 🎲 [3, 6, 1] → 10
[Roll 3/50] 🎲 [5, 5, 2] → 12
...
[Roll 10/50] 🎲 [2, 4, 4] → 10
[Roll 11/50] ✗ Error: Payment not authorized [rule_violation]: Velocity limit exceeded
[Agent 402] 🛑 SPENDING LIMIT REACHED!
Backing off for 1 seconds...
[Roll 12/50] ✗ Limit reached, backing off 2s... (Exponential backoff!)
[Agent 402] Stopped after 3 consecutive failures.
============================================================
DISTRIBUTION ANALYSIS
============================================================
Total Rolls: 10
3: 0 ( 0.0%)
4: â–ˆ 1 ( 10.0%)
5: ██ 2 ( 20.0%)
...
10: ████████████████████████████████████████ 4 ( 40.0%)
11: ███ 2 ( 20.0%)
12: â–ˆ 1 ( 10.0%)
...
18: 0 ( 0.0%)
Average: 10.20 (Expected: 10.50, Deviation: -0.30)
How It Works:
The Agent402Wallet class wraps HTTP requests and automatically:
- Detects HTTP 402 responses - When a paid API returns 402 Payment Required
- Requests authorization - Calls Agent 402
/v1/authorizeto check spending limits - Retries with payment token - If authorized, adds X-Payment-Token header and retries
- Confirms the transaction - Records with
/v1/confirmfor audit and updates usage counters - Handles declines gracefully - Implements exponential backoff when limits are hit
The payment flow with blockchain:
- Detect 402 - Resource server requires payment
- Authorize - Agent 402 checks spending rules
- Send
X-PAYMENT-TOKEN- Send Payment token to Resource Server which initiates blockchain transaction. - Retry request - Access the resource with payment token
- Confirm - Record transaction with blockchain tx hash
API Reference
Base URL: https://api.agent402.pro
X-API-Key header. Generate your API key in the dashboard.
POST /v1/authorize
Request authorization for a payment transaction. This endpoint checks if the transaction is allowed based on your configured spending rules.
Request
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-API-Key |
string | Yes | Your Agent 402 API key |
Content-Type |
string | Yes | Must be application/json |
Body Parameters
| Name | Type | Required | Description |
|---|---|---|---|
agent_id |
string | Yes | The ID of the agent making the transaction |
amount |
string | Yes | Transaction amount (e.g., "5.00") |
currency |
string | Yes | Currency (only USDC is supported currently) |
service |
string | Yes | Name of the service (e.g., "OpenAI", "Anthropic") |
service_endpoint |
string | No | The service endpoint URL being accessed |
metadata |
object | No | Additional metadata about the transaction |
Example Request
POST /v1/authorize
Host: api.agent402.pro
Content-Type: application/json
X-API-Key: agp_sk_abc123...
{
"agent_id": "my-assistant",
"amount": "5.00",
"currency": "USDC",
"service": "OpenAI",
"service_endpoint": "https://api.openai.com/v1/chat/completions",
"metadata": {
"model": "gpt-4",
"tokens_estimate": 1000
}
}
Response
Status Codes
| Code | Description |
|---|---|
200 |
Authorization successful (check authorized field for result) |
400 |
Invalid request parameters |
401 |
Invalid or missing API key |
403 |
API key does not have permission |
500 |
Internal server error |
Response Schema
| Field | Type | Description |
|---|---|---|
authorized |
boolean | Whether the transaction was authorized |
transaction_id |
string | Unique transaction identifier |
authorization_token |
string | Token to use when confirming the transaction |
expires_at |
string | ISO 8601 timestamp when the authorization expires |
reason |
string? | Reason if authorization was denied |
current_usage |
object? | Current usage statistics for velocity limits |
retry_after |
number? | Seconds until authorization can be retried (if denied) |
Example Response (Authorized)
HTTP/1.1 200 OK
Content-Type: application/json
{
"authorized": true,
"transaction_id": "13a417a2-3af9-4a38-bfe2-51cb39daa02c",
"authorization_token": "auth_a31d856b9e454d6d898f5b1a24291ad1",
"expires_at": "2025-10-29T04:58:24.590521941Z",
"reason": null,
"current_usage": null,
"retry_after": null
}
Example Response (Denied)
HTTP/1.1 200 OK
Content-Type: application/json
{
"authorized": false,
"transaction_id": null,
"authorization_token": null,
"expires_at": null,
"reason": "Velocity limit exceeded for rule 'Daily Limit': 10 transactions in hour (limit: 10)",
"current_usage": {
"count": 10,
"amount_cents": 5000,
"window": "hour"
},
"retry_after": 1800
}
POST /v1/confirm
Confirm that a payment transaction was completed. This records the transaction in your audit log and updates usage counters for spending rules.
Request
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-API-Key |
string | Yes | Your Agent 402 API key |
Content-Type |
string | Yes | Must be application/json |
Body Parameters
| Name | Type | Required | Description |
|---|---|---|---|
transaction_id |
string | Yes | The transaction ID from the authorization response |
auth_token |
string | Yes | The authorization token from the authorization response |
status |
string | Yes | Transaction status: "completed" or "failed" |
timestamp |
string | Yes | ISO 8601 timestamp of when the transaction completed |
tx_hash |
string | No | Blockchain transaction hash (if applicable) |
amount_paid |
string | No | Actual amount paid (if different from requested) |
error_message |
string | No | Error message if status is "failed" |
metadata |
object | No | Additional metadata about the transaction result |
Example Request
POST /v1/confirm
Host: api.agent402.pro
Content-Type: application/json
X-API-Key: agp_sk_abc123...
{
"transaction_id": "13a417a2-3af9-4a38-bfe2-51cb39daa02c",
"auth_token": "auth_a31d856b9e454d6d898f5b1a24291ad1",
"status": "completed",
"timestamp": "2025-10-28T10:30:00Z",
"tx_hash": "0x1234567890abcdef...",
"amount_paid": "4.50",
"metadata": {
"tokens_used": 950
}
}
Response
Status Codes
| Code | Description |
|---|---|
200 |
Transaction confirmed successfully |
400 |
Invalid request parameters |
401 |
Invalid authorization token |
404 |
Transaction not found |
422 |
Validation error (missing required fields) |
500 |
Internal server error |
Response Schema
| Field | Type | Description |
|---|---|---|
confirmed |
boolean | Whether the confirmation was successful |
transaction_id |
string | The confirmed transaction ID |
message |
string | Confirmation message |
Example Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"confirmed": true,
"transaction_id": "13a417a2-3af9-4a38-bfe2-51cb39daa02c",
"message": "Transaction confirmed successfully"
}
Rules
When a transaction is requested, all active rules are evaluated. If any rule fails, the transaction is declined.
Velocity Limits
Control transaction frequency and spending over time windows. Velocity rules track how many transactions or how much money has been spent within a specific time period.
Time Windows:
- Minute: Last 60 seconds
- Hour: Last 60 minutes
- Daily: Last 24 hours
- Weekly: Last 7 days
Limits:
- Transaction Count: Maximum number of transactions within the time window
- Amount Limit: Maximum total spending (in cents) within the time window
Scope: Can be applied organization-wide or restricted to a specific agent_id.
Note: Only completed and authorized transactions count towards velocity limits. Declined transactions are logged but do not affect the limits.
Maximum Amount Per Transaction
Sets a ceiling on individual transaction amounts. Any transaction exceeding this limit is declined.
Options:
- Max Amount: Maximum transaction size in cents
- Agent Scope: Apply to specific agent or organization-wide
- Domain Pattern: Optionally restrict to specific service domains (supports wildcards like *.example.com)
Service Allowlists and Blocklists
(Coming Soon) Control which services agents can interact with by allowing or blocking specific domains or service identifiers.
System Rules vs Organization Rules
System Rules are globally enforced to protect the platform:
- Rate Limiting: Prevents DOS attacks by limiting the number of requests per minute per API key. Returns HTTP 429 if exceeded.
Organization Rules are configured per organization through the dashboard:
Troubleshooting
Transaction Denied
If a transaction is denied, check the response message for details:
{
"authorized": false,
"reason": "velocity_limit_exceeded",
"message": "Daily transaction limit of 100 exceeded",
"rule_triggered": "Daily Spending Limit"
}
Common Issues
401 Unauthorized - Check that your API key is correct and included in the X-API-Key header.
404 Agent Not Found - Ensure you've registered the agent in the dashboard first.
422 Invalid Amount - Amount must be a positive number as a string (e.g., "5.00").