Spending policy
Max per payment, daily limit, and an auto-pay threshold above which a human must approve. Every rule is checked before signing.
Equinox lets AI agents automatically pay for APIs using USDC on Solana. Your agent hits a paid endpoint, gets an HTTP 402, and Equinox checks the spending policy, signs the payment and retries — in under a second, without ever exposing a private key.
The x402 protocol turns HTTP 402 into a real payment handshake. Equinox sits between your agent and the paid API, enforcing your budget before a single lamport moves.
x402_fetch with a max pricePAYMENT-REQUIREDexact transfer locallyPAYMENT-SIGNATUREPAYMENT-RESPONSE (tx signature)Budgets are enforced in Equinox, not in the prompt. The model can ask; it can never sign.
Max per payment, daily limit, and an auto-pay threshold above which a human must approve. Every rule is checked before signing.
Only pay hosts you trust. The allowlist is re-checked on every hop, so a sneaky redirect can't route funds elsewhere.
Idempotency keys and nonce tracking mean a retried request never double-pays, and a captured signature can't be replayed.
The keypair lives in Equinox's process. Tools return balances, receipts and data — never secrets, never to the model.
Use it as an MCP server in Codex or Claude, a local REST API for any language, or a typed TypeScript SDK in your own code.
Develop on devnet with faucet USDC, then flip one CAIP-2 network id to go live on Solana mainnet. Same code, same policy.
Each tool returns structured JSON so the model can inspect a price, decide, pay, and report back with a transaction signature.
x402_inspect makes an unpaid request and decodes the x402 V2 PAYMENT-REQUIRED header so the agent can decide whether the price is worth it.
{
"url": "https://api.example.com/weather?city=Miami",
"method": "GET"
}{
"paymentRequired": true,
"price": "$0.01",
"amountUsd": 0.01,
"asset": "USDC",
"network": "solana",
"networkId": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"recipient": "7YhZ9pQ4kTn2xWm8bCvLr3sJfHd6Ee1uKpNa5qRtVx2",
"scheme": "exact",
"resource": "https://api.example.com/weather"
}x402_fetch requests the URL and, if it gets a 402 within maxPriceUsd and policy, signs a USDC payment, retries, and returns the data together with the on-chain transaction.
{
"url": "https://api.example.com/weather?city=Miami",
"method": "GET",
"maxPriceUsd": 0.03
}{
"success": true,
"paid": true,
"amountUsd": 0.01,
"network": "solana",
"transaction": "4xK9vQ2mN8pLrT6wYc3hJb1dFgE5sA7uZi9oPq2RmWf2Qe",
"status": 200,
"data": { "city": "Miami", "temperature": 82, "conditions": "Sunny" }
}wallet_balance reports the agent wallet's public address and current SOL (for fees) and USDC (for payments) balances on the configured network.
{}{
"address": "9uGkA3wRt5nMzq2Pv7xLc8JbHfYe4dSaWo6TiNpQr1Km",
"network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"networkName": "devnet",
"sol": 1.5,
"usdc": 9.87
}spending_status lets the agent plan: how much of today's budget is left, the per-payment ceiling, and the threshold above which it must ask a human.
{}{
"spentTodayUsd": 1.24,
"dailyLimitUsd": 5,
"remainingTodayUsd": 3.76,
"maxPaymentUsd": 0.1,
"autoPayLimitUsd": 0.02
}payment_history returns recent payments with domain, amount, recipient, status and the Solana transaction signature — an audit trail the agent can cite.
{ "limit": 10 }{
"payments": [
{
"id": "pay_01J9X4",
"timestamp": "2026-09-19T14:02:11.000Z",
"url": "http://localhost:4020/demo/weather",
"domain": "localhost",
"amountUsd": 0.001,
"asset": "USDC",
"network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"recipient": "7YhZ9pQ4kTn2xWm8bCvLr3sJfHd6Ee1uKpNa5qRtVx2",
"transaction": "5UkxR2mN8pLrT6wYc3hJb1dFgE5sA7uZi9oPq2RmWf2Qe",
"status": "settled",
"latencyMs": 812
}
]
}Drop the MCP server into Codex, call the local REST API from any language, or use the TypeScript SDK directly.
import { Equinox } from "equinox402";
// Wallet is read from .env (EQUINOX402_SOLANA_PRIVATE_KEY) — never passed around
const equinox = new Equinox({
maxPaymentUsd: 0.05,
dailyLimitUsd: 5,
autoPayLimitUsd: 0.02, // above this, a human must approve
allowedDomains: ["api.example.com", "localhost"],
});
// Look before you leap: decode the 402 without paying
const quote = await equinox.inspect("http://localhost:4020/demo/weather");
console.log(quote); // { paymentRequired: true, price: "$0.001", ... }
// Works like fetch() — pays if needed, capped at $0.03 for this call
const response = await equinox.fetch("http://localhost:4020/demo/weather", {
maxPriceUsd: 0.03,
});
console.log(await response.json()); // { city: "Miami", temperature: 82, conditions: "Sunny" }
console.log(response.payment); // { paid: true, amountUsd: 0.001, transaction: "5Ukx…" }
# Register Equinox as an MCP server for OpenAI Codex
[mcp_servers.equinox402]
command = "node"
args = ["--import", "tsx", "/path/to/equinox402/src/mcp/server.ts"]
tool_timeout_sec = 120
# Optional — overrides equinox402/.env (the wallet key stays in .env)
[mcp_servers.equinox402.env]
EQUINOX402_NETWORK = "devnet"
EQUINOX402_MAX_PAYMENT_USD = "0.05"
EQUINOX402_DAILY_LIMIT_USD = "5"
EQUINOX402_AUTO_PAY_LIMIT_USD = "0.02"
EQUINOX402_ALLOWED_DOMAINS = "localhost,api.example.com"
Then ask Codex: "Get the Miami weather from http://localhost:4020/demo/weather. You can spend up to $0.03."
curl -s http://localhost:4020/fetch \
-H "Content-Type: application/json" \
-d '{
"url": "http://localhost:4020/demo/weather",
"method": "GET",
"maxPriceUsd": 0.01
}'
{
"success": true,
"paid": true,
"amountUsd": 0.001,
"network": "solana",
"transaction": "5UkxR2mN8pLrT6wYc3hJb1dFgE5sA7uZi9oPq2RmWf2Qe",
"status": 200,
"data": { "city": "Miami", "temperature": 82, "conditions": "Sunny" }
}
// price above autoPayLimitUsd → ask a human, then re-send with "approved": true
{ "success": false, "approvalRequired": true, "amountUsd": 0.08,
"resource": "https://api.example.com/report", "recipient": "7YhZ…Vx2" }
// price above maxPriceUsd
{ "success": false, "code": "PRICE_EXCEEDS_REQUEST_LIMIT",
"error": "Price $0.08 exceeds the requested maxPriceUsd of $0.01." }
Everything runs locally. The only network calls are to Solana devnet and the faucets.
Node 20 or newer is required. Every file and command you need is in the README.
Pulls the x402 and Solana Kit packages.
Writes a fresh wallet into .env and prints only the public address. Fund devnet SOL at faucet.solana.com and devnet USDC at faucet.circle.com.
Open .env (created from .env.example) and set your limits and allowed domains.
Runs the REST API, the console at http://localhost:4020/app.html, and the paid demo GET /demo/weather ($0.001 USDC).
Register the MCP server (see the config.toml tab), then give Codex a budget and a URL.
x402 is the payment rail; the interesting part is what agents buy with it.
exact on Solana USDC payments on devnet and mainnetweb/upto payments authorize a ceiling, settle the exact usageOpen the console to see balances, budgets and a live paid request against the demo endpoint.