How to give an AI agent a payment card
You've built an AI agent. It needs to call paid APIs — OpenAI, Anthropic, Pinecone, an exchange, an external SaaS. You want it to pay on its own, within strict spend limits, with a full audit trail. This guide shows you how, end to end, in under 15 minutes.
The problem
Today, AI agents either:
- Share a human's credit card — which means uncapped spend, no audit, no scope
- Hit your internal billing API — which means months of integration with each vendor
- Have you approve every charge manually — which kills the autonomy
You want: a card that only charges the merchants you allow, only in the amounts you allow, only for what your agent is supposed to do — with cryptographic proof of every decision.
Architecture
Agent runtime (Claude, GPT-4, custom)
↓ Ed25519 sign
Soren Pay signed intent
↓ POST /api/agents/[id]/intents
Authorization engine (verify sig + scopes)
↓ Visa issuing partner Intelligent Commerce
Merchant (OpenAI, Anthropic, …)
↓ swipe approved
Workspace ledger (debit)
↓ webhook
Your accounting / Sentry / Datadog
Step 1: Provision a workspace + API key
Sign up at sorenpay.com/signup → Business workspace. After KYB
(sandbox skips it), create an apk_ key with write:agents + write:cards + read:treasury.
Step 2: Register the agent
import { SorenAgent } from "@sorenpay/agent-sdk";
const soren = new SorenAgent({ apiKey: process.env.SOREN_API_KEY! });
const { agent, privateKeyPem } = await soren.register({
agentName: "research-assistant",
description: "Calls OpenAI + arxiv + scholar APIs to draft research memos",
protocols: ["TAP", "MPP", "ACP"],
});
console.log("agent id:", agent.id);
// → persist privateKeyPem to your secret store (e.g. AWS Secrets Manager,
// Doppler, 1Password, etc.). It's returned ONCE.Step 3: Mint a scoped card
const cardResponse = await fetch("https://api.sorenpay.com/api/cards", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SOREN_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
holderKind: "agent",
holderLabel: "research-assistant",
monthlyLimitUsdCents: 100_00, // $100/mo
perTxnLimitUsdCents: 10_00, // max $10 per call
allowedMccs: ["5734", "7372"], // 5734 = software, 7372 = computer services
allowedMerchants: ["openai", "anthropic", "pinecone"],
}),
});
const { card } = await cardResponse.json();
console.log("Visa card minted, last4:", card.last4);Step 4: Sign + submit an intent (inside the agent loop)
When the agent decides it wants to call OpenAI's API:
// Inside your agent's tool-call handler
async function callOpenAiPaid(prompt: string) {
// 1. Estimate cost (or use last-known token rate)
const estimatedCents = 150;
// 2. Sign a payment intent
const result = await soren.submitIntent({
agentId: agent.id,
privateKeyPem: process.env.AGENT_PRIVATE_KEY!,
merchant: { name: "OpenAI", mcc: "5734" },
amount: { currency: "USD", cents: estimatedCents },
protocol: "TAP",
ttlSeconds: 60,
});
// 3. If approved, proceed with the API call (use the card you minted)
if (result.decision !== "APPROVE") {
throw new Error(`payment denied: ${result.reason}`);
}
return fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
body: JSON.stringify({ /* ... */ }),
});
}Step 5: Watch the audit trail
Every intent + decision is logged to agent_intent_log (replay-protected by
unique intent_id). View it in /dashboard/agents/[id].
For real-time observability, subscribe to outbound webhooks:
{
"url": "https://yourapp.com/hooks/soren",
"events": [
"agent.intent.verified",
"agent.intent.rejected",
"card.authorization.approved",
"card.authorization.declined"
]
}Pipe these to Datadog, Sentry, or your own observability stack.
What this unlocks
- Per-agent scopes: each agent has its own card with its own merchant whitelist
- Cryptographic proof: every charge maps to a signed intent in
agent_intent_log - Velocity controls: enforce monthly + per-transaction caps in Postgres CTE, sub-200ms
- Audit immutability: the
auth_audit_chainis hash-chained — a single tampered row breaks the chain
Related
- Agent SDK quickstart — TS, Python, curl
- Protocols — TAP / MPP / ACP wire format
- Card capabilities — all 16 Visa issuing partner features
- Disputes + chargebacks — when an agent's purchase goes wrong