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.

DiscoveryPublishing APIs