Documentation
Everything you need to integrate AgentPay into your AI agent or register your API as a provider.
Quick Start
Get your AI agent calling APIs in under 5 minutes.
1. Install the SDK
pip install agentpay
# or for TypeScript:
npm install agentpay2. Set up your Solana keypair
AgentPay uses your Solana keypair for signing payments. On devnet you can use the Solana CLI default keypair.
solana-keygen new --outfile ~/.config/solana/id.json
solana airdrop 1 # devnet SOL for tx fees3. Get devnet USDC
Each call costs USDC. On devnet you can use the SPL faucet:
# Visit https://spl-token-faucet.com and request devnet USDC
# or use our helper:
python -m agentpay fund-devnet4. Make your first paid call
from agentpay import AgentPay
ap = AgentPay(network="devnet")
# Discover APIs
apis = ap.discover(query="weather")
print(apis[0]) # { slug, name, price_usdc, ... }
# Call & pay automatically
result = ap.call("weather-v1", {"city": "Karachi"})
print(result) # { temp: 34, condition: "Sunny", ... }The SDK handles the entire 402 challenge → on-chain pay → retry flow. You just call .call().
Payment Flow
AgentPay uses HTTP 402 Payment Required as a machine-readable payment challenge.
Initial request
Agent sends a normal HTTP request to the gateway URL with X-Agent-Wallet header.
402 challenge
Gateway responds with nonce, USDC amount, recipient wallet, and expiry timestamp.
On-chain payment
SDK builds a USDC SPL transfer with the nonce embedded in a Memo instruction.
Verification + proxy
Gateway verifies the tx on-chain, checks replay nonce, then forwards to provider API.
Response returned
Provider response is forwarded back. Usage is logged for hourly settlement.
402 challenge response
HTTP/1.1 402 Payment Required
Content-Type: application/json
X-Payment-Nonce: 0x9f2c…a8e3
X-Payment-Amount: 300
X-Payment-Currency: USDC-DEVNET
X-Payment-Recipient: 7xKX…m3Pq
X-Payment-Expires: 1746800000
{
"challenge": {
"nonce": "0x9f2c…a8e3",
"amount_usdc_micro": 300,
"recipient": "7xKX…m3Pq",
"memo_template": "agentpay:0x9f2c…a8e3",
"expires_at": 1746800000
}
}Authentication
Two distinct authentication mechanisms operate inside AgentPay:
1. Agents — wallet signatures (no auth at all)
Agents do not authenticate. They prove they paid by including a confirmed Solana transaction signature on the retry request:
POST /api/proxy/{slug}
X-Payment-Tx: 5Hq2KL...kL9n
X-Payment-Nonce: 0x9f2c…a8e3
X-Agent-Wallet: 7xKX...m3Pq
{ "your": "params" }2. Providers — Sign-In With Solana (SIWS)
Providers authenticate to manage their APIs and read usage data. The flow:
// 1. Wallet signs a SIWS message
const message = "AgentPay wants you to sign in with your Solana account:\n" + wallet;
const signature = await wallet.signMessage(encodeUTF8(message));
// 2. POST signature to /auth/signin → JWT
const { access_token } = await fetch("/api/auth/signin", {
method: "POST",
body: JSON.stringify({ wallet_address, message, signature })
}).then(r => r.json());
// 3. Use JWT for /providers/me, /apis, etc.
fetch("/api/providers/me", {
headers: { Authorization: `Bearer ${access_token}` }
});Tokens expire after 24 hours by default. SIWS messages are not stored — only the JTI (token ID) is tracked for revocation.
Discovery API
Public endpoint for finding APIs. No auth required — your agent can call this to dynamically pick services.
GET /api/v1/discover?query=weather&category=weather&limit=20Query parameters
| param | type | description |
|---|---|---|
| query | string? | Substring match against name/description/category |
| category | string? | weather · finance · scraping · llm · geo · data · other |
| limit | int | Max 100. Default 20. |
| offset | int | Pagination offset. Default 0. |
Response
{
"apis": [
{
"slug": "weather-v1",
"name": "Weather API",
"description": "Real-time weather data for any city",
"category": "weather",
"price_usdc": 0.0003,
"price_usdc_micro": 300,
"gateway_url": "https://agentpay.io/api/proxy/weather-v1",
"provider": "MeteoCore"
}
],
"total": 1, "offset": 0, "limit": 20
}SDK Reference
The Python SDK is the reference implementation. The TypeScript SDK exposes the same surface.
AgentPay()
AgentPay(
network="devnet", # "devnet" | "mainnet-beta"
keypair_path=None, # path to id.json
keypair_secret=None, # base58 secret key string
gateway_url=None, # override default gateway
timeout=30.0, # request timeout in seconds
max_spend_usdc=None, # safety cap per session
).discover()
apis = ap.discover(
query="weather",
category="weather",
limit=20,
)
# Returns list[ApiInfo] — { slug, name, price_usdc, gateway_url, ... }.call()
result = ap.call(
slug="weather-v1",
data={"city": "NYC"},
method="POST", # GET / POST / PUT / PATCH / DELETE
max_price_usdc=0.001, # refuses if API price exceeds this
)
# Returns parsed JSON response from the providerAlways set max_price_usdc in production agents — it's the easiest defence against a misconfigured upstream charging more than expected.
Error handling
from agentpay.exceptions import (
GatewayUnavailableError,
InsufficientFundsError,
PaymentVerificationError,
AgentPayError,
)
try:
ap.call("weather-v1", {"city": "NYC"})
except InsufficientFundsError:
# Top up devnet USDC and retry
...
except PaymentVerificationError:
# Tx didn't confirm in time — usually a transient devnet issue
...Becoming a Provider
Any HTTP API can be listed on AgentPay. You register the endpoint, set a price, and AgentPay handles discovery, payment, and settlement.
How requests reach your API
When a paid agent call arrives, AgentPay forwards it to your base_url verbatim, plus your provider API key as the Authorization header. The agent's request body and method are passed through.
Settlement
A cron job runs every hour, sums unsettled usage logs per provider, deducts a 5% platform fee, and sends USDC directly to your payout_wallet. Every settlement is fully visible on Solana Explorer.
REST API
Backend endpoints exposed by the AgentPay gateway.
| Method · Path | Auth | Description |
|---|---|---|
| GET /api/v1/discover | — | Public discovery |
| POST /api/auth/signin | — | SIWS sign-in → JWT |
| POST /api/auth/signout | JWT | Revoke session |
| GET /api/providers/me | JWT | Current provider profile |
| PUT /api/providers/me | JWT | Update profile + payout wallet |
| POST /api/providers/onboard | JWT | Complete onboarding |
| GET /api/providers/me/usage | JWT | Usage summary |
| GET /api/providers/me/usage/logs | JWT | Usage logs (paginated) |
| GET /api/providers/me/payouts | JWT | Settlement history |
| GET /api/apis | JWT | List your APIs |
| POST /api/apis | JWT | Register a new API |
| PATCH /api/apis/{id} | JWT | Update an API |
| DELETE /api/apis/{id} | JWT | Pause an API (soft delete) |
| ANY /api/proxy/{slug} | Payment | Paid gateway — 402 challenge protocol |
Errors & Limits
HTTP error codes
| Code | Meaning | What to do |
|---|---|---|
| 400 | Bad request | Inspect detail field |
| 401 | Invalid SIWS signature or expired JWT | Re-sign in |
| 402 | Payment required | SDK handles automatically |
| 403 | Forbidden — wrong wallet for this API | Sign in with the owning wallet |
| 404 | API slug not found | Confirm the slug exists on /v1/discover |
| 409 | Slug already taken | Choose a different slug |
| 429 | Rate limited | Back off — see Retry-After header |
| 503 | API paused or upstream unavailable | Check provider status |
Rate limits
Per-API rate limits are configurable by the provider (default 60 req/min). Discovery is rate-limited at 120 req/min per IP.
Replay protection
Every 402 challenge is single-use. The nonce is checked on-chain (via the Memo) and in Redis. Submitting the same tx twice returns 409 Conflict.