Capped now issues prepaid virtual cards for AI agents — see what's new →
API Reference v1

Documentation

Everything you need to integrate capped.ai into your AI agent stack. Issue virtual cards, set spending policies, and handle real-time authorizations.

Quick Start

Get running in under 5 minutes. Create an account, issue your first agent card, and attach a spending policy.

1
Create an account
Sign up free at capped.ai/register — no credit card required.
2
Issue an agent card
Go to Agent Cards → Issue Card. A virtual card is created instantly.
3
Set a spending policy
Under Policies, set per-transaction limits, daily volume caps, and approval thresholds.
4
Get your API key
Go to API Keys and create a key. It starts with lim_.

POST /api/v1/actions/check

Evaluate whether an agent's spend is permitted under its current policy. Call this before your agent executes any purchase or payment.

curl -X POST https://capped.ai/api/v1/actions/check \
  -H "Authorization: Bearer lim_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agent_abc123",
    "action_type": "purchase",
    "amount_usd": 120,
    "reason": "Compute instance for data pipeline"
  }'

Request body

agent_idstringRequiredYour agent's ID from the dashboard
action_typestringRequiredpurchase, transfer, or any custom string
amount_usdnumberRequiredUSD value of the spend
reasonstringOptionalAgent's reason — stored in audit log

Response

{
  "status": "approved",            // approved | blocked | requires_approval | reduced
  "decision_id": "dec_xyz789",
  "reason": "All policy checks passed",
  "requires_human_approval": false,
  "allowed_amount_usd": null,      // set when status is "reduced"
  "policy_checks": [
    { "rule": "per_txn_limit", "result": "pass", "message": "$120 ≤ $500 limit" },
    { "rule": "daily_volume",  "result": "pass", "message": "$320 of $1,000 daily cap" }
  ]
}

Status values

StatusMeaning
approvedSpend passes all checks. Proceed.
blockedSpend violates a rule. Do not proceed.
requires_approvalAbove approval threshold. Wait for human review in the dashboard.
reducedAmount exceeded per-transaction limit. allowed_amount_usd has the capped value.

POST /api/v1/actions/:id/execute

After a requires_approval decision is approved by a human in the Approvals dashboard, call this to record it as executed.

curl -X POST https://capped.ai/api/v1/actions/dec_xyz789/execute \
  -H "Authorization: Bearer lim_your_api_key"

Python example

Use this helper to gate any spend in your agent code before the card is charged.

import requests

API_KEY = "lim_your_api_key"
BASE   = "https://capped.ai"

def check_spend(agent_id, amount_usd, reason=""):
    """Check if a purchase is allowed under the agent's spending policy."""
    res = requests.post(
        f"{BASE}/api/v1/actions/check",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={
            "agent_id":    agent_id,
            "action_type": "purchase",
            "amount_usd":  amount_usd,
            "reason":      reason,
        },
    )
    return res.json()

result = check_spend(
    "agent_abc123",
    amount_usd=120,
    reason="EC2 instance for data pipeline",
)

if result["status"] == "approved":
    # proceed with payment / API call
    pass
elif result["status"] == "requires_approval":
    print("Queued for human review:", result["decision_id"])
elif result["status"] == "reduced":
    print("Capped at:", result["allowed_amount_usd"])
else:
    print("Blocked:", result["reason"])

LangChain tool

Wrap capped.ai as a LangChain tool so your agent automatically checks policy before any spend.

from langchain.tools import tool
import requests

@tool
def spend_with_policy(amount_usd: float, reason: str = "") -> str:
    """Gate a purchase through the capped.ai policy engine before charging the card."""
    res = requests.post(
        "https://capped.ai/api/v1/actions/check",
        headers={"Authorization": "Bearer lim_your_api_key"},
        json={
            "agent_id":    "agent_abc123",
            "action_type": "purchase",
            "amount_usd":  amount_usd,
            "reason":      reason,
        },
    ).json()

    if res["status"] == "blocked":
        return f"Spend blocked: {res['reason']}"
    elif res["status"] == "requires_approval":
        return f"Queued for approval (id: {res['decision_id']})"
    elif res["status"] == "reduced":
        return f"Capped: proceed with ${res["allowed_amount_usd"]} instead"

    return f"Approved: ${amount_usd} approved"

Real-time authorization webhook

capped.ai evaluates every card authorization in real time before it clears. When an agent's card is used, the network calls our authorization webhook and capped.ai responds with approved: true or approved: false within 2 seconds based on the active policy.

# Authorization webhook (preconfigured — no setup required):
https://capped.ai/api/webhooks/authorize

# capped.ai evaluates every authorization in real time:
# 1. Check per-transaction limit
# 2. Check daily volume cap
# 3. Check approval threshold
# 4. Respond approved: true or false

No additional code needed — the webhook is preconfigured when you create an agent card.

Spending policy reference

Configure policies in the dashboard under Policies. Each policy is attached to one agent card.

RuleUnitBehaviour
Per-transaction limitUSDSingle card charge cannot exceed this value
Daily volume capUSDTotal approved spend per calendar day
Requires approval aboveUSDCharges above this value queue for human review
Max transactions/daycountHard cap on daily approved transaction count

tradingMode values

ValueEffect
paper_onlyTrade actions are simulated. No real execution. (Default)
live_disabledAll trade-type actions are immediately blocked. Payments still allowed.
blockedHard blocks all trade actions at the policy level, regardless of other rules.

Connect your first agent

Get an AI agent making purchases through a capped.ai virtual card in under 15 minutes.

Before you start: Complete KYB verification in your account settings. Card provisioning is gated on approval.

1
Create a virtual card
Go to Dashboard → Cards → New Card. Set a spend limit for testing (e.g. $10 per transaction). Copy the card number, expiry, and CVV shown after creation.
2
Option A: Bare API / direct credentials
Pass card credentials to your agent as environment variables:
export AGENT_CARD_NUMBER="4111111111111234"
export AGENT_CARD_EXPIRY="12/28"
export AGENT_CARD_CVV="123"
3
Option B: LangChain integration
Wrap capped.ai as a LangChain tool:
import { LimitMD } from '@capped/sdk'
import { tool } from '@langchain/core/tools'
import { z } from 'zod'

const limitmd = new LimitMD({ apiKey: process.env.LIMIT_MD_API_KEY })

const purchaseTool = tool(
  async ({ amount, merchant }) => {
    const token = await limitmd.tokens.create({
      cardId: process.env.LIMIT_MD_CARD_ID,
      amount,
      merchant,
      expiresIn: 300,
    })
    return { token: token.value, expiry: token.expiry }
  },
  {
    name: 'make_purchase',
    description: "Make a purchase using the agent's virtual card",
    schema: z.object({
      amount: z.number().describe('Amount in cents'),
      merchant: z.string(),
    }),
  }
)
4
Run a test transaction
Use the sandbox base URL https://api.sandbox.capped.ai for testing. No real money moves.

GET /api/agents/:id — Balance & card state

Fetch an agent's virtual balance and card status. Use this to display remaining budget or confirm a card is active before making purchases.

curl https://capped.ai/api/agents/agent_abc123 \
  -H "Authorization: Bearer lim_your_api_key"

Response

{
  "agent": {
    "id": "agent_abc123",
    "name": "research-agent",
    "mode": "paper",
    "status": "active",
    "virtualBalanceUsd": 4832.50,
    "cardStatus": "open",
    "stripeCardId": "ic_xyz789",
    "policies": [{ "perTransactionLimitUsd": 500, "dailyVolumeLimitUsd": 1000 }]
  }
}

Key fields

FieldMeaning
virtualBalanceUsdRemaining paper balance in USD — reflects all approved spend against the starting budget.
cardStatusopen (active) · paused (frozen) · cancelled
modepaper · approval_only · live_disabled — see Agent mode section

Freeze / unfreeze a card

# Freeze
curl -X PATCH https://capped.ai/api/agents/agent_abc123/card \
  -H "Authorization: Bearer lim_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "action": "freeze" }'

# Unfreeze
curl -X PATCH https://capped.ai/api/agents/agent_abc123/card \
  -H "Authorization: Bearer lim_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "action": "unfreeze" }'

GET /api/agents/:id/transactions — Transaction history

List the 50 most recent card transactions for an agent, newest first. Works in both sandbox and production.

curl https://capped.ai/api/agents/agent_abc123/transactions \
  -H "Authorization: Bearer lim_your_api_key"

Response

{
  "transactions": [
    {
      "id": "txn_abc123",
      "agentId": "agent_abc123",
      "amount": 12000,
      "currency": "USD",
      "merchant": "AWS Marketplace",
      "status": "approved",
      "declineReason": null,
      "createdAt": "2026-06-19T10:22:14Z"
    }
  ]
}

Generating test transactions (sandbox)

Use the sandbox base URL (https://api.sandbox.capped.ai) and send POST /api/v1/actions/check — each call creates a synthetic transaction that appears in this list immediately. Sandbox data resets every 24 hours; no real money moves.

Transaction statuses

StatusMeaning
approvedAuthorization passed all policy checks. Card was charged.
declinedAuthorization rejected. See declineReason for the specific code.
reversedAuthorization was reversed by the merchant or capped.ai.
settledAuthorization settled (1–3 business days after approval).

Decline codes

When a card transaction is declined, the API returns a machine-readable code. Find the code in Dashboard → Transactions → [transaction] → Decline reason or in the error response body.

{
  "error": {
    "code": "SPEND_LIMIT_EXCEEDED",
    "message": "Transaction of $150.00 exceeds the per-transaction limit of $100.00.",
    "transactionId": "txn_xyz789"
  }
}
CodeMeaningFix
SPEND_LIMIT_EXCEEDEDExceeds per-transaction limit.Raise the card limit or split the purchase.
CYCLE_LIMIT_EXCEEDEDCard has hit its per-cycle cap.Increase the per-cycle limit or wait for reset (1st of month).
LIFETIME_LIMIT_EXCEEDEDCard exhausted its lifetime allowance.Cancel and provision a new card with a higher limit.
INSUFFICIENT_FUNDSAccount balance too low.Add funds via Dashboard → Billing. Enable auto-reload.
CARD_FROZENCard was manually frozen.Unfreeze via Dashboard → Cards or PATCH /api/agents/{id}/card with {"action":"unfreeze"}.
CARD_CANCELLEDCard permanently cancelled.Provision a new card. Cancellation is irreversible.
MERCHANT_BLOCKEDMerchant category blocked by card policy.Update merchant controls in Dashboard → Cards → Merchant Controls.
CURRENCY_MISMATCHTransaction currency differs from card currency.Use a card configured for that currency.
CARD_NOT_ACTIVECard not yet activated.Activate via Dashboard → Cards.
EXPIRED_CARDCard's expiry date has passed.Provision a replacement card.
INVALID_CVVCVV does not match.Verify the CVV matches the dashboard value.
PLATFORM_LIMIT_EXCEEDEDAccount-level platform limit hit.Request a limit increase via Settings → Account.
VELOCITY_EXCEEDEDToo many transactions in a short window.Spread transactions over time or contact support.
SUSPECTED_FRAUDAutomated fraud detection flagged this.Freeze the card and contact security@capped.ai immediately.
PROVIDER_ERRORUnderlying card network error.Retry once. If persists after 5 minutes, contact support with the transaction ID.

Authentication troubleshooting

Every capped.ai API request requires a Bearer token in the Authorization header.

Authorization: Bearer lim_<64 hex characters>

Key format

PrefixEnvironmentWhat it does
lim_All environments64-character hex string. There is no live/test prefix split — environment is determined by which base URL you call.

Production base URL: https://api.capped.ai
Sandbox base URL: https://api.sandbox.capped.ai
A sandbox key sent to the production URL returns 401.

Common errors

# Wrong — no "Bearer" prefix
curl -H "Authorization: lim_yourkey" https://capped.ai/api/v1/actions/check

# Wrong — "Token" instead of "Bearer"
curl -H "Authorization: Token lim_yourkey" https://capped.ai/api/v1/actions/check

# Correct
curl -H "Authorization: Bearer lim_yourkey" https://capped.ai/api/v1/actions/check
ErrorCause and fix
401 Unauthorized — missing or malformed tokenAuthorization header is missing or incorrectly formatted. Ensure you include Bearer before the key.
401 Unauthorized — invalid API keyKey was revoked, belongs to a different account, or has trailing whitespace. Copy the key fresh from Dashboard → API Keys.
401 Unauthorized — environment mismatchCalling the wrong base URL (e.g. sandbox endpoint when targeting production). Use https://capped.ai for production.
403 Forbidden — insufficient permissionsKey is valid but lacks permission for this action. Generate a key with the required scopes.

Rotating keys safely

1
Generate a new key
Dashboard → Settings → API Keys → New Key.
2
Update your environment
Replace the old key in your environment variables or secrets manager.
3
Verify the new key
Make a GET /api/agents call to confirm it works.
4
Revoke the old key
Dashboard → Settings → API Keys → Revoke.

Incident response

If you see transactions you did not authorize, or suspect your API key has been leaked, act immediately.

1
Freeze all cards (do this first)
Go to Dashboard → Cards. Freeze each card. Freezing is instant and reversible.
curl -X PATCH https://capped.ai/api/agents/CARD_ID/card \
  -H "Authorization: Bearer lim_yourkey" \
  -H "Content-Type: application/json" \
  -d '{ "action": "freeze" }'
2
Rotate your API key
Dashboard → Settings → API Keys → Revoke active key → Create new key. Update all agent deployments. If the dashboard is inaccessible, email security@capped.ai.
3
Change your password and enable 2FA
Dashboard → Settings → Security.
4
Document what happened
Gather unauthorized transaction IDs, timestamps, amounts, and merchant names from Dashboard → Transactions.
5
Contact support
Email security@capped.ai with subject: [URGENT] Account compromise. Include transaction IDs and timeline. Expect a response within 1 hour during business hours.
6
Dispute unauthorized charges
capped.ai initiates disputes with the card network on your behalf. Do not contact merchants directly — route all disputes through support.

Identity verification (KYB)

capped.ai is a financial product. Before you can provision your first virtual card, your business must pass Know Your Business (KYB) verification. This is a regulatory requirement and takes 1–3 business days.

How to complete KYB

1
Go to Dashboard → Settings → Verification
Click Start Verification.
2
Fill in your business details
Have ready: business legal name, EIN or tax ID, physical business address, and beneficial owner's full name and date of birth.
3
Submit
You'll receive an email when the review is complete (usually within 24 hours).

KYB status

StatusMeaning
Not startedYou haven't submitted yet.
PendingUnder review. No action needed.
ApprovedYou can provision cards.
Additional info requiredCheck your email — we need more documentation.
RejectedContact support to understand the decision.

While KYB is pending, you can use the sandbox environment. No KYB required for sandbox.

Spend limit types

capped.ai gives you three independent controls over how much a virtual card can spend. All three apply simultaneously.

Limit typeEffectWhen to use
Per-transaction limitMaximum a card can charge in a single transaction. Any individual charge above this is declined.Capping what an agent can spend on any single action.
Per-cycle limitMaximum spend in a billing cycle (calendar month). Resets on the 1st of each month.Monthly budget control per agent.
Lifetime limitTotal the card can ever spend across its entire existence. Once hit, the card is permanently over-limit.One-time or project-scoped agents with a fixed budget.

A transaction is approved only if it passes all configured limits. Omitting a dimension means no limit is enforced for that dimension.

Configure all three limits in the dashboard: Dashboard → Cards → [select card] → Edit Limits. Changes take effect immediately.

Webhook integration

capped.ai sends webhook events to your endpoint when transactions occur, cards change state, or other account events happen.

1
Register your endpoint
Dashboard → Settings → Webhooks → Add Endpoint. Enter a publicly reachable HTTPS URL (use ngrok for local development).
2
Verify the signature (required)
Every webhook request includes an X-Capped-Signature header. The signature is HMAC-SHA256(signingSecret, requestBody), hex-encoded.
import crypto from 'crypto'

function verifyWebhook(body: string, signature: string, signingSecret: string): boolean {
  const expected = crypto
    .createHmac('sha256', signingSecret)
    .update(body, 'utf8')
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(signature, 'hex')
  )
}

app.post('/webhooks/limitmd', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-capped-signature'] as string
  if (!verifyWebhook(req.body.toString(), sig, process.env.LIMIT_MD_WEBHOOK_SECRET!)) {
    return res.status(401).send('Invalid signature')
  }
  const event = JSON.parse(req.body.toString())
  res.status(200).send('ok')
  // process event async...
})
3
Respond within 5 seconds
Return HTTP 200 within 5 seconds. Move processing to a background queue. If your endpoint returns non-200 or times out, capped.ai retries with exponential backoff (5s, 30s, 2m, 10m, 1h) up to 5 attempts.

Webhook event types

EventTriggered when
transaction.authorizedA card authorization is approved or declined.
transaction.settledAn authorization settles (1–3 business days after authorization).
transaction.reversedAn authorization is reversed (e.g. refund or merchant void).
card.createdA new card is provisioned.
card.frozenA card is frozen.
card.unfrozenA card is unfrozen.
card.cancelledA card is permanently cancelled.
limit.exceededA spend limit was exceeded (transaction declined).
account.fundedAccount balance increased (ACH settled or card top-up).

Funding and auto-reload

capped.ai operates on a prepaid model. Your account balance is drawn down as your agents make purchases.

Adding funds

MethodSettlement timeNotes
ACH bank transfer1–3 business daysNo fee. Go to Dashboard → Billing → Add Funds → Bank Transfer.
Debit or credit cardImmediateSmall processing fee applies. Go to Dashboard → Billing → Add Funds → Card.

Auto-reload

Auto-reload prevents your agents from stalling due to a low balance. When your balance drops below a threshold you set, capped.ai automatically pulls from your linked bank account via ACH.

1
Go to Dashboard → Settings → Billing → Auto-Reload
Link a bank account if you haven't already.
2
Set a minimum balance threshold
e.g. $200. When balance drops below this, reload triggers.
3
Set a reload amount
e.g. $500. How much to pull each time.

Best practice: Set your auto-reload threshold to at least 3× your average daily spend so the 1–3 day ACH settlement window is covered.

// Check agent balance via GET /api/agents/:id
const res = await fetch('https://capped.ai/api/agents/agent_abc123', {
  headers: { 'Authorization': 'Bearer lim_yourkey' },
})
const { agent } = await res.json()
// agent.virtualBalanceUsd — remaining paper balance in USD

Team management

Invite teammates to your capped.ai account and control what each person can do using roles.

RoleWhat they can do
AdminEverything: create and cancel cards, set spend limits, manage team members, view billing, rotate API keys, initiate fund transfers.
ViewerRead-only: see cards, transactions, and account balance. Cannot create cards, change limits, invite users, or access billing.

Invite a team member via Dashboard → Settings → Team → Invite Member. Role changes take effect immediately. Removing a team member revokes their access immediately — rotate any API keys they created separately.

Agent mode

The mode field on an agent — and tradingMode on its attached policy — controls how the policy engine treats every incoming action. Set it when you create an agent or update one at any time.

ValueWhen to useEffect
paperDevelopment and simulationAll policy checks run; no real card charges are executed. Paper-trade positions track simulated P&L.
approval_onlyMaximum human oversightEvery action is queued for human approval regardless of amount or policy thresholds.
live_disabledTemporarily suspend tradingtrade actions are blocked immediately. payment, api_spend, and wallet_transfer continue unaffected.
blockedHard trading suspension (policy-level)All trade actions rejected immediately. Set on policy.tradingMode; the agent mode field does not accept this value.

live_disabled enforcement: when policy.tradingMode is live_disabled, the policy engine returns status: "blocked" for any request where action_type is trade. Non-trade actions — payment, api_spend, wallet_transfer — bypass this check and are evaluated normally against all other policy rules.

Create and update agent mode

const BASE = 'https://capped.ai'
const API_KEY = process.env.CAPPED_API_KEY

// Create an agent in paper mode (safe default for development)
const res = await fetch(`${BASE}/api/agents`, {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'research-agent',
    mode: 'paper',          // paper | approval_only | live_disabled
    virtualBalanceUsd: 5000,
  }),
})
const { agent } = await res.json()
// agent.id, agent.mode === "paper"

// Gate every trade behind a human before going live
await fetch(`${BASE}/api/agents/${agent.id}`, {
  method: 'PATCH',
  headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ mode: 'approval_only' }),
})

// Immediately halt all trading while keeping payments live
await fetch(`${BASE}/api/agents/${agent.id}`, {
  method: 'PATCH',
  headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ mode: 'live_disabled' }),
})

Rate limits

PlanLimitsAPI burst
Free1 card · 500 transactions/mo
Builder10 cards · unlimited100 req/min
EnterpriseUnlimited cardsCustom

Support

Questions, bugs, or feedback — email hello@capped.ai. Enterprise support includes a dedicated Slack channel.

For billing questions: billing@capped.ai. For security incidents: security@capped.ai.