Calling APIs
POST /api/{id} with your parameters. Attach X-Payment (x402) or X-MPP-Payment (Stripe) header. Returns data or 402 with payment instructions.
Calling APIs
Every Proxagora API uses the same call pattern: POST /api/{id} with a JSON body. If payment is attached and valid, you get data. If not, you get 402 with instructions.
Endpoint Pattern
POST https://proxagora.com/api/{id}
Content-Type: application/json
X-Payment: <base64-payment-header> OR X-MPP-Payment: <stripe-session-token>
{ "param1": "value1", ... }
The {id} comes from the discovery catalog — it's the id field on each API object.
Success Response
HTTP 200 OK
Content-Type: application/json
{
"data": { ... }
}
Response shape varies by API. See individual API docs or call without payment first to see the 402 spec, which includes the response mime type.
Payment Required Response
HTTP 402 Payment Required
Content-Type: application/json
{
"x402Version": 1,
"accepts": [{
"scheme": "exact",
"network": "base-sepolia",
"maxAmountRequired": "1000",
"resource": "https://proxagora.com/api/ip-geo",
"description": "IP geolocation lookup",
"mimeType": "application/json",
"payTo": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"maxTimeoutSeconds": 300,
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
}]
}
maxAmountRequired is in USDC base units (6 decimals). 1000 = $0.001 USDC.
Full Call Examples
IP Geolocation
curl -X POST https://proxagora.com/api/ip-geo \
-H "Content-Type: application/json" \
-H "X-Payment: <payment-header>" \
-d '{"ip": "8.8.8.8"}'
Response:
{
"ip": "8.8.8.8",
"city": "Mountain View",
"region": "California",
"country": "US",
"lat": 37.386,
"lon": -122.0838,
"timezone": "America/Los_Angeles",
"asn": "AS15169",
"org": "Google LLC"
}
Domain Reputation
curl -X POST https://proxagora.com/api/domain-reputation \
-H "Content-Type: application/json" \
-H "X-Payment: <payment-header>" \
-d '{"domain": "example.com"}'
Response:
{
"domain": "example.com",
"risk_score": 12,
"blacklisted": false,
"categories": ["business", "reference"],
"registrar": "IANA",
"age_days": 10950
}
Email Validation
curl -X POST https://proxagora.com/api/email-validation \
-H "Content-Type: application/json" \
-H "X-Payment: <payment-header>" \
-d '{"email": "user@example.com"}'
Response:
{
"email": "user@example.com",
"deliverable": true,
"mx_found": true,
"disposable": false,
"free_provider": false,
"format_valid": true
}
SERP Results
curl -X POST https://proxagora.com/api/serp-results \
-H "Content-Type: application/json" \
-H "X-Payment: <payment-header>" \
-d '{"query": "x402 micropayments", "num_results": 10}'
Python — Generic Wrapper
import requests
import base64
import json
def build_payment_header(tx_hash: str, from_addr: str, to_addr: str,
amount: str, network: str) -> str:
payload = {
"x402Version": 1,
"scheme": "exact",
"network": network,
"payload": {
"signature": tx_hash,
"authorization": {
"from": from_addr,
"to": to_addr,
"value": amount,
"validAfter": "0",
"validBefore": str(int(__import__('time').time()) + 300),
"nonce": tx_hash
}
}
}
return base64.b64encode(json.dumps(payload).encode()).decode()
class ProxagoraClient:
BASE_URL = "https://proxagora.com"
def __init__(self, wallet, network="base-sepolia"):
self.wallet = wallet
self.network = network
def call(self, api_id: str, params: dict) -> dict:
url = f"{self.BASE_URL}/api/{api_id}"
# First attempt
resp = requests.post(url, json=params, headers={"Content-Type": "application/json"})
if resp.status_code == 402:
payment_req = resp.json()
accept = payment_req["accepts"][0]
# Pay via your wallet
tx_hash = self.wallet.pay_usdc(
to=accept["payTo"],
amount=int(accept["maxAmountRequired"]),
network=self.network
)
payment_header = build_payment_header(
tx_hash, self.wallet.address,
accept["payTo"], accept["maxAmountRequired"],
accept["network"]
)
# Retry
resp = requests.post(url, json=params, headers={
"Content-Type": "application/json",
"X-Payment": payment_header
})
resp.raise_for_status()
return resp.json()
# Usage
client = ProxagoraClient(wallet=my_wallet)
geo = client.call("ip-geo", {"ip": "8.8.8.8"})
TypeScript — Generic Wrapper
import { createWalletClient, http } from 'viem'
import { baseSepolia } from 'viem/chains'
const USDC = '0x036CbD53842c5426634e7929541eC2318f3dCF7e' // Base Sepolia
const ERC20_ABI = [{
inputs: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }],
name: 'transfer',
outputs: [{ name: '', type: 'bool' }],
type: 'function'
}] as const
export async function callProxagora<T = unknown>(
apiId: string,
params: Record<string, unknown>,
walletClient: ReturnType<typeof createWalletClient>
): Promise<T> {
const url = `https://proxagora.com/api/${apiId}`
const body = JSON.stringify(params)
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
let response = await fetch(url, { method: 'POST', headers, body })
if (response.status === 402) {
const payReq = await response.json()
const accept = payReq.accepts[0]
const txHash = await walletClient.writeContract({
address: USDC,
abi: ERC20_ABI,
functionName: 'transfer',
args: [accept.payTo as `0x${string}`, BigInt(accept.maxAmountRequired)]
})
const paymentPayload = btoa(JSON.stringify({
x402Version: 1,
scheme: accept.scheme,
network: accept.network,
payload: {
signature: txHash,
authorization: {
from: walletClient.account!.address,
to: accept.payTo,
value: accept.maxAmountRequired,
validAfter: '0',
validBefore: String(Math.floor(Date.now() / 1000) + 300),
nonce: txHash
}
}
}))
response = await fetch(url, {
method: 'POST',
headers: { ...headers, 'X-Payment': paymentPayload },
body
})
}
if (!response.ok) {
throw new Error(`Proxagora error: ${response.status} ${await response.text()}`)
}
return response.json()
}
Error Responses
| Status | Meaning | |--------|---------| | 200 | Success — data in response body | | 402 | Payment required — body contains x402 spec | | 400 | Bad request — missing or invalid params | | 422 | Payment validation failed — check tx hash and amount | | 429 | Rate limited — slow down or use pre-funded credits | | 500 | Upstream API error — retry |
Idempotency
Each API call creates a new payment transaction on-chain. There's no deduplication — calling the same endpoint twice with valid payment charges twice. For idempotent workflows, track which calls have succeeded in your own state.