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".

Store this securely - you'll need it for all API requests. If you lose this key, you will need to generate a new API key and rotate.

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 Points: Agent 402 interacts directly with the x402 client (e.g. agent) not with the resource server, blockchain or any facilitators.

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:

This demo endpoint does not actually initiate the blockchain transactions, even if passed 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:

Prerequisites:

1. Install Dependencies:

npm install @modelcontextprotocol/sdk axios
Note: The 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:

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:

How It Works:

The withPaymentControllerInterceptor adds an axios response interceptor that automatically:

  1. Detects HTTP 402 responses - When a resource server requires payment, it returns a 402 status with payment details
  2. Requests authorization from Agent 402 - Calls /v1/authorize with the payment amount and your agent ID to check spending limits
  3. Retries the request with payment token - If authorized, adds the X-Payment-Token header and retries the original request
  4. Confirms the transaction - After successful payment, calls /v1/confirm to record the transaction
Demo Mode: The example above shows a complete working implementation. In the interceptor tab, you can see how payment authorization is handled automatically when your MCP tool encounters HTTP 402 responses. The blockchain private key is shown for reference but is not actively used in demo mode - facilitation is mocked for testing purposes.

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:

Prerequisites:

1. Install Dependencies:

pip install requests
Note: The core demo only requires 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:

  1. Detects HTTP 402 responses - When a paid API returns 402 Payment Required
  2. Requests authorization - Calls Agent 402 /v1/authorize to check spending limits
  3. Retries with payment token - If authorized, adds X-Payment-Token header and retries
  4. Confirms the transaction - Records with /v1/confirm for audit and updates usage counters
  5. Handles declines gracefully - Implements exponential backoff when limits are hit
Exponential Backoff: When velocity limits are exceeded, the demo backs off exponentially: 1s → 2s → 4s → 8s → 16s → 32s → 60s (max). This prevents hammering the API while respecting your spending rules. After 3 consecutive failures, the agent stops gracefully.

The payment flow with blockchain:

  1. Detect 402 - Resource server requires payment
  2. Authorize - Agent 402 checks spending rules
  3. Send X-PAYMENT-TOKEN - Send Payment token to Resource Server which initiates blockchain transaction.
  4. Retry request - Access the resource with payment token
  5. Confirm - Record transaction with blockchain tx hash

API Reference

Base URL: https://api.agent402.pro

Authentication: All requests require an API key passed in the 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:

Limits:

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:

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:

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").

Need Help? Contact us at support@agent402.pro or visit our full documentation.