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

register-agent.tstypescript
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

mint-card.tstypescript
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:

agent-loop.tstypescript
// 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:

POST /api/webhook-endpointsjson
{
"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_chain is hash-chained — a single tampered row breaks the chain

Related