Authentication & Payments
Proxagora uses x402 micropayments (USDC on Base) and Stripe MPP instead of API keys. No signup. No OAuth. The payment is the authorization.
Authentication & Payments
Proxagora doesn't use API keys or OAuth. Access to APIs is gated by payment.
When you call an API endpoint without payment, you get HTTP 402 with payment instructions. Attach payment proof and retry. That's the entire auth flow.
x402 — USDC on Base (Recommended)
x402 is the primary payment method. It uses USDC on Base Sepolia (testnet) or Base mainnet (production).
Flow
- Call
POST /api/{id}without payment header - Receive HTTP 402 with payment spec:
{
"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"
}]
}
- Send USDC transfer to
payToaddress on specified network - Encode payment proof in
X-Paymentheader (base64 JSON) - Retry original request — data returned
Network Addresses
| Network | USDC Contract | Chain ID |
|---------|---------------|----------|
| Base Sepolia (testnet) | 0x036CbD53842c5426634e7929541eC2318f3dCF7e | 84532 |
| Base Mainnet | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | 8453 |
Using the x402 Library
pip install x402
from x402.client import X402Client
from x402.wallet import LocalWallet
wallet = LocalWallet(private_key="0x_your_key")
client = X402Client(wallet=wallet)
# Handles 402 flow automatically
response = client.post(
"https://proxagora.com/api/ip-geo",
json={"ip": "8.8.8.8"}
)
npm install x402
import { wrapFetchWithPayment } from 'x402'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const fetch = wrapFetchWithPayment(globalThis.fetch, account)
const response = await fetch('https://proxagora.com/api/ip-geo', {
method: 'POST',
body: JSON.stringify({ ip: '8.8.8.8' })
})
Manual Payment Header
If building your own client, the X-Payment header is base64-encoded JSON:
{
"x402Version": 1,
"scheme": "exact",
"network": "base-sepolia",
"payload": {
"signature": "0x_transaction_hash",
"authorization": {
"from": "0x_your_wallet_address",
"to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"value": "1000",
"validAfter": "0",
"validBefore": "1749000000",
"nonce": "0x_transaction_hash"
}
}
}
Encode as: base64(JSON.stringify(payload))
Stripe MPP — Card Payments
For developers who prefer card payments or don't have a Base wallet set up.
Flow
- Create a Stripe MPP session with a balance top-up
- Get a session token
- Use
X-MPP-Payment: <token>on API calls - Each call deducts from the session balance
# Create MPP session
curl -X POST https://proxagora.com/api/pay \
-H "Content-Type: application/json" \
-d '{"amount_usd": 10.00, "provider": "stripe"}'
# Response: { "session_token": "mpp_...", "balance_usd": 10.00 }
# Use on calls
curl -X POST https://proxagora.com/api/ip-geo \
-H "Content-Type: application/json" \
-H "X-MPP-Payment: mpp_..." \
-d '{"ip": "8.8.8.8"}'
When to Use Each Method
| Scenario | Recommended | |----------|-------------| | Autonomous agent in production | x402 | | Agent testing on Base Sepolia | x402 | | Developer exploratory testing | Stripe MPP | | Team without crypto setup | Stripe MPP | | High-frequency pipelines | x402 (lower overhead) |
Getting Test USDC
For Base Sepolia testing:
- Get test ETH from Base Sepolia Faucet
- Get test USDC from Circle Faucet
- Set network to Base Sepolia (chain ID 84532) in your wallet
Your wallet needs both ETH (for gas) and USDC (for payments). Typical gas cost per payment: ~$0.001 in test ETH.
Payment Validation
Proxagora validates payments by:
- Checking the transaction hash exists on-chain
- Verifying recipient address matches the
payTofrom the 402 spec - Verifying amount matches
maxAmountRequired - Checking transaction is confirmed (at least 1 block)
- Checking
validBeforetimestamp hasn't expired
Failed validation returns HTTP 402 again with a reason in the response body.