Get started

Concepts

A precise mental model for how AgentPay issues cards, funds them, and decides when an agent can or cannot spend. Read this once; the API will make sense forever.

The platform shape

AgentPay is one Stripe Connect account that we control. End-users don't have Stripe accounts; they fill our KYB form (name, date of birth, address, phone) and we create a Stripe Issuing cardholder representing them on our one Connect account. All your cards live under that cardholder.

AgentPay platform Stripe account
  └── AgentPay Issuer  (ONE Stripe Connect account, we control it)
       ├── Cardholder for user A  (real KYB: name, DOB, address, phone)
       │     └── Card 1, Card 2, …  (each with metadata.agent_id, spend limit)
       ├── Cardholder for user B
       │     └── Card 1, …
       └── …  (one cardholder per end-user)

The funding model — honestly

When your agent asks for a $20 card, here's what actually happens on our side:

  1. We place a $20 off-session auth-hold on your saved payment method — an uncaptured PaymentIntent with capture_method: 'manual'. You don't see a prompt; the card is not charged yet.
  2. We mint a Stripe Issuing virtual card with spending_controls.spending_limit set to $20.
  3. When the agent uses the card, Stripe authorizes the charge against our Issuing balance (pre-funded float). The card is single-use, so it self-destructs after.
  4. Our webhook handler catches issuing_authorization.created and captures your auth-hold — you pay us, we replenish the float.
Why auth-hold instead of charging you directly? Card networks need a funding decision in about 2 seconds. Charging your PM synchronously on every authorization isn't reliable. We pre-fund a balance, settle cards against it, and collect from you after — the hold is our credit-risk hedge on the float while the card is in flight.

Cards

  • Single-use (v0). Designed for one authorization. Multi-use cards for recurring subscriptions are planned for v1.
  • $500 max per card in v0 (Stripe Issuing soft default). Adjustable via policy up to that ceiling.
  • metadata.agent_id on every card — set it at creation so you can group cards by agent in your own reporting.
  • PAN/CVV reveal is via Stripe's ephemeral-key flow. GET /v1/cards/:id returns an ephemeral_key_secret your client exchanges for the full number using Stripe.js. We never return the raw PAN over our API.

Agents — what they are, honestly

An agent in AgentPay is a logical actor under your account — it has a name, a status (active, paused, revoked), and optional per-agent policy overrides. When you pass agent_id on POST /v1/cards, we attribute the card to that agent and apply agent-level rules on top of your user-level policy.

Agents DO

  • • Kill-switch — pause/revoke to instantly stop new cards for that agent.
  • • Per-agent lifetime + live card caps (max_cards_per_agent, max_active_cards_per_agent).
  • • Per-agent per-card amount override below the policy default.
  • • Per-agent MCC allowlist (stored; v1 enforces at authorization).
  • • Fleet caps (max_agents, max_active_agents).
  • • Group reporting — see spend per agent in the dashboard.

Agents DO NOT

  • • Authenticate. All agents under one user share one API key.
  • • Bind cryptographically. agent_id is a claim from the caller.
  • • Rate-limit separately. The 1000 req/hr cap is per-key, not per-agent.
  • • Enforce anything if agent_id is omitted on create_card — only the user-level policy applies.

v1 direction: per-agent API keys (sk_*_agt_) so one compromised agent can be revoked without killing the others. Today agents are an organizational + policy primitive, not a security boundary.

Policies

A policy is the record that decides whether a card can be created, how big it can be, andwhen it needs human approval. Every user has exactly one default policy. Each card request can override selected fields.

{
  "approval_required": false,
  "approval_threshold_cents": 2000,
  "approval_channels": ["dashboard"],
  "max_card_amount_cents": 5000,
  "max_total_held_cents": 50000,
  "max_agents": 10,
  "max_active_agents": 5,
  "max_cards_per_agent": 25,
  "max_active_cards_per_agent": 5,
  "velocity_day_cents": 10000,
  "velocity_week_cents": 50000
}
  • Approval: approval_required forces every card to queue; approval_threshold_cents queues only cards at or above that amount.
  • Per-card + aggregate caps: max_card_amount_cents + max_total_held_cents.
  • Fleet caps: max_agents, max_active_agents, max_cards_per_agent, max_active_cards_per_agent.
  • Velocity: rolling-window spend caps per 24h and 7d.

See the policy cookbook for common patterns (allowed ceiling by agent tier, auto-approve under $X, etc.).

Approvals

When a request is queued, POST /v1/cards returns 202 PENDING_APPROVAL with an approval_id. The request lives in approval_requests for up to 1 hour. Either approve (mints the card) or reject (records a decline) from /approvals or via POST /v1/approvals/:id/approve|reject.

The setup-required flow

If the authenticated user hasn't completed KYB or connected a payment method, we return a structured 403 setup_required error with a setup_url. The MCP server surfaces this verbatim so your agent can tell the user exactly what to do:

{
  "error": {
    "code": "setup_required",
    "message": "AgentPay setup must be completed before cards can be issued. Open: https://app.agentpay.dev/setup?return=mcp",
    "details": {
      "missing": ["kyb", "payment_method"],
      "setup_url": "https://app.agentpay.dev/setup?return=mcp"
    },
    "request_id": "req_…"
  }
}

On the first blocked request we also email the user a one-click setup link — historically a 10x conversion lift over the welcome email alone.