The Walleteer Agent API enables AI agents to send USDC payments autonomously on the Solana blockchain. Agents authenticate with a per-agent API key, discover active merchants, and initiate payments within their configured spend policies.
All amounts are in USDC (6 decimal places). Balances are maintained on-chain and mirrored in the platform database.
The API is deployed on AWS Lambda (Solana devnet for staging). Mainnet deployment will use EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v as the USDC mint address.
Agent endpoints use the X-Agent-Key header. Bearer JWT authentication is used for customer-facing endpoints (balance, transaction history, merchant discovery).
# Obtained from POST /agents/{id}/regenerate-key or agent creation response curl https://api.walleteer.dev/agent/balance \ -H "X-Agent-Key: wlt_live_abcdef1234567890abcdef1234567890"
curl https://api.walleteer.dev/merchants \ -H "Authorization: Bearer <your_jwt>"
Returns the current USDC balance and Solana public key of the wallet owned by this agent's customer.
curl https://api.walleteer.dev/agent/balance \ -H "X-Agent-Key: wlt_live_abc123" # Response 200 { "balance": 42.500000, "currency": "USDC", "publicKey": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" }
Returns the transaction history for this agent, ordered by most recent first. Supports optional page and pageSize query params.
curl https://api.walleteer.dev/agent/transactions?page=1&pageSize=20 \ -H "X-Agent-Key: wlt_live_abc123" # Response 200 [ { "transactionId": "a1b2c3d4-...", "status": "Completed", "corridor": "AgentToMerchant", "amount": { "amount": 10.00, "currency": "USDC" }, "feeAmount": { "amount": 0.05, "currency": "USDC" }, "netAmount": { "amount": 10.00, "currency": "USDC" }, "itemizedDetails": "order:ORD-999", "orderId": "ORD-999", "createdAt": "2026-04-14T10:00:00Z" } ]
Lists all active merchants. Use the merchantCode for lookup or the merchantId for payments.
curl https://api.walleteer.dev/merchants \ -H "Authorization: Bearer <jwt>" # Response 200 [ { "merchantId": "f1a2b3c4-...", "merchantCode": "GAME001", "name": "Acme Games", "isActive": true } ]
Looks up a single active merchant by its unique merchant code. Returns 404 if not found or inactive.
curl https://api.walleteer.dev/merchants/GAME001 \ -H "Authorization: Bearer <jwt>" # Response 200 { "merchantId": "f1a2b3c4-...", "merchantCode": "GAME001", "name": "Acme Games", "isActive": true }
Initiates an AgentToMerchant USDC payment on-chain. The payment is subject to the agent's active spend policy. Provide a stable idempotencyKey to safely retry on network errors.
| Field | Type | Required | Description |
|---|---|---|---|
| merchantId | uuid | ✓ | From GET /merchants |
| amount | decimal | ✓ | USDC amount (e.g. 9.99) |
| currency | string | ✓ | Must be "USDC" |
| idempotencyKey | string | ✓ | Unique per payment attempt; safe to reuse on retry |
| orderId | string | — | Your order/invoice reference; included in webhook payload |
| itemizedDetails | string | — | Free-form string, e.g. "item:SKU-1;qty:2" |
curl -X POST https://api.walleteer.dev/agent/payments/merchant \ -H "X-Agent-Key: wlt_live_abc123" \ -H "Content-Type: application/json" \ -d '{ "merchantId": "f1a2b3c4-5678-...", "amount": 9.99, "currency": "USDC", "idempotencyKey": "ORD-999-attempt-1", "orderId": "ORD-999", "itemizedDetails": "item:PREMIUM_SKIN;qty:1" }' # Response 202 Accepted { "transactionId": "a1b2c3d4-...", "status": "Completed", "corridor": "AgentToMerchant", "createdAt": "2026-04-14T10:00:00Z" }
amount. Your wallet is debited amount + 0.05. The merchant receives the full amount.
Initiates an AgentToAgent USDC payment to another agent's wallet.
curl -X POST https://api.walleteer.dev/agent/payments/agent \ -H "X-Agent-Key: wlt_live_abc123" \ -H "Content-Type: application/json" \ -d '{ "recipientAgentId": "b2c3d4e5-...", "amount": 25.00, "currency": "USDC", "idempotencyKey": "transfer-abc-001" }' # Response 202 Accepted { "transactionId": "c3d4e5f6-...", "status": "Completed", "corridor": "AgentToAgent", "createdAt": "2026-04-14T10:01:00Z" }
When an agent successfully pays a merchant with a configured webhookUrl, Walleteer delivers a signed HTTP POST to that URL within milliseconds of on-chain settlement. Webhook delivery is fire-and-forget with a 10-second timeout.
The payload is signed with HMAC-SHA256 using the merchant's webhook secret. Always verify the signature before processing a payment notification.
{
"event": "payment.completed",
"transactionId": "a1b2c3d4-5678-90ab-cdef-...",
"agentId": "b2c3d4e5-...",
"merchantId": "f1a2b3c4-...",
"merchantCode": "GAME001",
"amount": 9.99,
"currency": "USDC",
"itemizedDetails": "item:PREMIUM_SKIN;qty:1",
"orderId": "ORD-999",
"solanaSignature": "5vLy8...Z7kp",
"timestamp": "2026-04-14T10:00:01.234Z"
}
Every delivery includes an X-Walleteer-Signature header of the form:
X-Walleteer-Signature: sha256=<hex-encoded HMAC-SHA256>
The HMAC is computed over the raw UTF-8 JSON body using the merchant's webhook secret as the key.
import hmac, hashlib def verify_signature(body: bytes, secret: str, header: str) -> bool: expected = hmac.new( secret.encode(), body, hashlib.sha256 ).hexdigest() received = header.removeprefix("sha256=") return hmac.compare_digest(expected, received) # Usage in Flask @app.route("/webhooks/walleteer", methods=["POST"]) def handle_webhook(): sig = request.headers.get("X-Walleteer-Signature", "") if not verify_signature(request.data, WEBHOOK_SECRET, sig): return "Forbidden", 403 payload = request.get_json() if payload["event"] == "payment.completed": fulfill_order(payload["orderId"], payload["amount"]) return "", 200
const crypto = require('crypto'); function verifySignature(body, secret, header) { const expected = crypto .createHmac('sha256', secret) .update(body) .digest('hex'); const received = header.replace(/^sha256=/, ''); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(received) ); } // Express handler app.post('/webhooks/walleteer', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['x-walleteer-signature'] || ''; if (!verifySignature(req.body, process.env.WEBHOOK_SECRET, sig)) return res.sendStatus(403); const payload = JSON.parse(req.body); if (payload.event === 'payment.completed') fulfillOrder(payload.orderId, payload.amount); res.sendStatus(200); });
hmac.compare_digest / crypto.timingSafeEqual) to prevent timing attacks. Never compare signatures with ==.
| Status | Meaning |
|---|---|
| 400 | Bad Request — malformed JSON or missing required field |
| 401 | Unauthorized — missing or invalid X-Agent-Key / Bearer token |
| 403 | Forbidden — agent's spend policy does not allow this payment |
| 404 | Not Found — merchant, agent, or resource does not exist |
| 409 | Conflict — duplicate merchant code on creation |
| 422 | Unprocessable Entity — validation error (see errors object in response) |
| 429 | Too Many Requests — rate limit exceeded (upcoming) |
| 500 | Internal Server Error — unexpected failure; safe to retry with the same idempotencyKey |
{
"title": "One or more validation errors occurred.",
"status": 422,
"errors": {
"Amount": [ "Amount must be greater than zero." ]
}
}
All payment endpoints accept an idempotencyKey field. Submitting the same key twice returns the original transaction without re-executing the payment — safe for retries after network errors.
"ORD-999-payment")# Recommended: derive from order ID for natural idempotency idempotencyKey = f"order-{order_id}-payment" # Or generate once and persist before submitting idempotencyKey = str(uuid.uuid4())
Walleteer Agent API — Built on Solana • Powered by USDC