Metered API Access
Pay for any x402 API with a simple API key — no wallets, no signing, no crypto in your code. Think of it as Stripe for x402 buyers.
Quick Start
1Create an API Key
Go to Dashboard → Metered API Access and click "New Key". This creates:
- An API key (prefix:
rpx_) - A Solana custodial wallet (for Solana x402 APIs)
- An EVM custodial wallet (for Base, SKALE Base, Avalanche APIs)
Or via API:
curl -X POST https://api.relai.fi/metered/register \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{"label": "My App"}'Response example
{
"apiKey": "rpx_a1b2c3d4e5f6...",
"label": "My App",
"wallets": {
"solana": {
"address": "4KuwK7vPceo...",
"network": "solana"
},
"evm": {
"address": "0x0787F752a0...",
"networks": ["base", "skale-base", "avalanche"]
}
}
}2Deposit USDC
Send USDC to the wallet addresses from step 1:
| Network | Token | Send to |
|---|---|---|
| Solana | USDC (SPL) | Your Solana wallet address |
| Base / SKALE / Avalanche | USDC (ERC-20) | Your EVM wallet address |
3Make API Calls
Call any x402 API through the proxy — payment is handled automatically:
curl "https://api.relai.fi/metered/x?url=https://api.example.com/data" \ -H "X-API-Key: rpx_your_key_here"
The proxy forwards your request, detects 402, signs payment from your wallet, retries with payment proof, and returns the API response.
API Reference
Authentication
Two auth methods depending on the endpoint:
| Endpoints | Auth | Header |
|---|---|---|
| register, keys, delete | JWT Bearer | Authorization: Bearer <JWT> |
| balance, usage, proxy | API Key | X-API-Key: rpx_... |
/metered/registerCreate a new API key with custodial wallets. Max 5 keys per user.
Request Body
{ "label": "My App" } // optionalResponse 201
{
"apiKey": "rpx_...",
"label": "My App",
"wallets": {
"solana": { "address": "...", "network": "solana" },
"evm": { "address": "...", "networks": ["base", "skale-base", "avalanche"] }
},
"depositInstructions": "..."
}/metered/keysList all API keys for the authenticated user. Secrets are never returned.
Response
{
"keys": [{
"apiKey": "rpx_...",
"label": "My App",
"active": true,
"wallets": { "solana": { "address": "..." }, "evm": { "address": "..." } },
"spendingLimitUsd": null,
"createdAt": "2026-02-09T12:00:00.000Z"
}]
}/metered/keys/:apiKeyRevoke an API key immediately.
Response
{ "success": true }/metered/keys/:apiKeyUpdate key settings — label and spending limits. All fields optional.
Request Body
{
"maxPerTransactionUsd": 5.00,
"maxPerPeriodUsd": 50.00,
"periodType": "daily"
}| Field | Type | Description |
|---|---|---|
maxPerTransactionUsd | number | null | Max USDC per single payment. null = unlimited |
maxPerPeriodUsd | number | null | Max total USDC per period. null = unlimited |
periodType | string | daily, weekly, or monthly |
label | string | Key label |
Response
{ "success": true, "updated": { "maxPerTransactionUsd": 5.00, "maxPerPeriodUsd": 50.00 } }/metered/balanceCheck USDC balance across all networks. Auth: X-API-Key
Response
{
"totalBalance": 10.50,
"balances": {
"solana": { "address": "...", "balance": 5.00, "network": "solana" },
"base": { "address": "...", "balance": 3.50, "network": "base" },
"skale-base": { "address": "...", "balance": 2.00, "network": "skale-base" },
"avalanche": { "address": "...", "balance": 0.00, "network": "avalanche" }
}
}/metered/usageSpending summary and recent request logs. Auth: X-API-Key
Response
{
"totalSpentUsd": 1.25,
"totalRequests": 42,
"recentLogs": [{
"targetUrl": "https://api.example.com/data",
"network": "base",
"amountUsd": 0.01,
"status": 200,
"createdAt": "2026-02-09T12:30:00.000Z"
}]
}/metered/keys/:apiKey/withdrawWithdraw USDC from a custodial wallet to an external address.
Request Body
{
"network": "solana",
"toAddress": "4KuwK7vPceojCsmeq...",
"amount": 5.00
}Response
{
"success": true,
"txHash": "5xY9...",
"explorerUrl": "https://solscan.io/tx/5xY9...",
"amount": 5.00,
"network": "solana",
"toAddress": "4KuwK7vP..."
}/metered/keys/:apiKey/export-keyExport private keys for the custodial wallets. Handle with extreme care.
Response
{
"wallets": {
"solana": {
"address": "4KuwK7vP...",
"privateKey": "[1,2,3,...]",
"format": "JSON array (paste into Phantom/Solflare)"
},
"evm": {
"address": "0x0787F7...",
"privateKey": "0xabc123...",
"format": "Hex (paste into MetaMask)"
}
}
}/metered/x?url=<target>The core proxy endpoint. Forwards any HTTP request to the target URL and handles x402 payment automatically.
| Param | Required | Description |
|---|---|---|
url | Yes | Target x402 API URL |
X-API-Key | Yes | Your Metered API Access key |
Supports: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS. All headers and body are forwarded to the target. Response includes X-Proxy: RelAI-BuyerProxy header.
# GET request
curl "https://api.relai.fi/metered/x?url=https://api.example.com/data" \
-H "X-API-Key: rpx_..."
# POST with body
curl -X POST "https://api.relai.fi/metered/x?url=https://api.example.com/submit" \
-H "X-API-Key: rpx_..." \
-H "Content-Type: application/json" \
-d '{"prompt": "Hello"}'Integration Examples
JavaScript / Node.js
const PROXY = "https://api.relai.fi/metered/x";
const KEY = process.env.RELAI_PROXY_KEY;
async function callX402(url, options = {}) {
const res = await fetch(
`${PROXY}?url=${encodeURIComponent(url)}`,
{
method: options.method || "GET",
headers: {
"X-API-Key": KEY,
"Content-Type": "application/json",
...options.headers,
},
body: options.body ? JSON.stringify(options.body) : undefined,
}
);
return res.json();
}
// GET request
const data = await callX402("https://api.example.com/data");
// POST request with JSON body
const result = await callX402("https://api.example.com/generate", {
method: "POST",
body: { prompt: "Hello world", maxTokens: 100 },
});Python
import os, requests
PROXY = "https://api.relai.fi/metered/x"
KEY = os.environ["RELAI_PROXY_KEY"]
def call_x402(url, method="GET", json=None):
r = requests.request(
method, PROXY,
params={"url": url},
headers={"X-API-Key": KEY},
json=json,
)
return r.json()
# GET request
data = call_x402("https://api.example.com/data")
# POST request with JSON body
result = call_x402(
"https://api.example.com/generate",
method="POST",
json={"prompt": "Hello world", "maxTokens": 100},
)cURL
# Simple GET
curl "https://api.relai.fi/metered/x?url=https://api.example.com/data" \
-H "X-API-Key: $RELAI_PROXY_KEY"
# POST with JSON body
curl -X POST "https://api.relai.fi/metered/x?url=https://api.example.com/submit" \
-H "X-API-Key: $RELAI_PROXY_KEY" \
-H "Content-Type: application/json" \
-d '{"key": "value"}'How It Works
Your Code RelAI Proxy x402 API
| | |
|--- GET /metered/x →| |
| X-API-Key: rpx_... | |
| |--- GET /data --------→|
| |←-- 402 Payment Req ---|
| | |
| | [Sign payment] |
| | |
| |--- GET + X-PAYMENT --→|
| |←-- 200 OK + data ----|
| | |
|←-- 200 OK + data -----| |1. Your request is forwarded to the target URL
2. If the target returns 402, the proxy parses the PAYMENT-REQUIRED header
3. For EVM: signs an EIP-2612 permit. For Solana: signs an SPL transfer
4. Re-sends the request with X-PAYMENT header
5. Returns the final API response to you
6. Logs the payment for your usage tracking
Spending Limits
Control costs by setting spending limits per API key. Configure via the dashboard (Limits button) or the PATCH /metered/keys/:apiKey endpoint.
Per-Transaction Limit
Set maxPerTransactionUsd to reject any single x402 payment above a certain amount.
// Example: reject payments over $1.00
PATCH /metered/keys/rpx_...
{ "maxPerTransactionUsd": 1.00 }If an API requires $2.00 and the limit is $1.00, the proxy returns 402 with error "Per-transaction limit exceeded".
Periodic Limit
Set maxPerPeriodUsd + periodType to cap total spending over a time window.
// Example: max $50/day
{ "maxPerPeriodUsd": 50.00, "periodType": "daily" }| Period | Resets at |
|---|---|
daily | Midnight (server time) |
weekly | Start of week (Sunday) |
monthly | 1st of month |
Removing Limits
Set any limit to null to remove it (unlimited):
{ "maxPerTransactionUsd": null, "maxPerPeriodUsd": null }Supported Networks
| Network | Type | Token | Payment Method |
|---|---|---|---|
| Solana | SVM | USDC (SPL) | Signed SPL transfer |
| Base | EVM | USDC (ERC-20) | EIP-2612 permit |
| SKALE Base | EVM | USDC (bridged) | EIP-2612 permit |
| Avalanche | EVM | USDC (ERC-20) | EIP-2612 permit |
All EVM networks share a single custodial wallet address. Solana has its own wallet.
Error Handling
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
402 | Payment failed (insufficient balance, signing error, spending limit exceeded) |
400 | Missing url parameter or invalid URL |
502 | Target returned 402 without valid x402 requirements, or proxy failed |
Example error responses
// Spending limit exceeded
{ "error": "Spending limit exceeded", "limit": 10.00, "spent": 9.50, "required": 1.00 }
// No wallet for network
{ "error": "Cannot pay: No EVM custodial wallet available for network base",
"targetUrl": "...", "network": "eip155:8453", "amountUsd": 0.01 }FAQ
What happens if I don't have enough USDC?
The proxy returns a 402 error explaining which network needs funding and how much.
Can one API key work across multiple networks?
Yes. Each key comes with both Solana and EVM wallets. The proxy picks the right one automatically.
Is there a fee for using the proxy?
You only pay the x402 price set by the API. RelAI does not add any markup.
What x402 versions are supported?
Both x402 v1 and v2 payment requirements are supported.
Can I use this for non-x402 APIs?
Yes — if the target doesn't return 402, the response is forwarded directly. The proxy is transparent for non-x402 endpoints.
Are my wallet keys safe?
Private keys are stored encrypted server-side. They are never exposed through the API or dashboard.