Skip to main content

Agent Card

Issue a virtual card an agent can spend with, governed by the same mandate layer as Pix. Every authorization is checked server-side; freeze or cancel instantly.

3 min read
View MarkdownEdit on GitHub
TIME
~15 min
CAPABILITY
codespar_issueGuardrails
SIDE
Buy-sideagent spends

Give your agent its own card instead of a human's. The card is issued through our card-issuing partner, bound to a mandate, and every authorization is evaluated against policy on our side before the network sees an approve or decline. If the agent misbehaves, you freeze or cancel the card in one call.

Why an issued card, not a borrowed one

The obvious shortcut is to paste a human's card number into the agent's context. It fails three ways:

  • Form-fill walls. Checkout pages fight bots with 3DS challenges, CAPTCHAs, and device fingerprinting. An agent typing a human's PAN into a form is exactly the traffic those walls exist to stop.
  • No caps. A borrowed card carries the human's full limit. There is no way to say "this agent gets R$500 a month and nothing more" at the card level.
  • No kill switch. If the agent goes wrong, your recourse is calling the bank. With an issued card, card-control: freeze takes effect at the next authorization.

An issued card flips the model: the instrument belongs to the agent, the limits belong to the mandate, and the authorization decision happens on infrastructure you govern.

The flow

THE FLOW
Two steps, one conversation
1
Issue a virtual card
session.issue("card-virtual")
Card created at our card-issuing partner, active immediately, bound to the agent's mandate
2
Agent spends at any merchant
card network
The card works anywhere cards work: SaaS checkouts, APIs, marketplaces
3
Authorization checked against the mandate
authorization webhook
Each authorization is evaluated server-side against caps and policy before approve/decline
4
Freeze or cancel on demand
session.issue("card-control")
One call disables the card at the next authorization attempt

This is the card face of the same governance you get on Pix: one mandate layer, two rails. The mandate does not care whether the debit arrives as a Pix initiation or a card authorization; the caps and the audit chain are shared.

Prerequisites

  • A CodeSpar API key (csk_test_...) with at least one project
  • Card issuing enabled on your account (contact us to provision a cardholder and a card program; you will reference both by id)
npm install @codespar/sdk

1. Issue the virtual card

codespar_issue with action: "card-virtual" (the default) creates a card that is active immediately. cardholder_id and program_id come from your issuing setup:

agent-card.ts
import { CodeSpar } from "@codespar/sdk";

const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY! });

const session = await codespar.create("agent-card-demo", {
  metadata: { source: "cookbook:agent-card" },
});

const card = await session.issue({
  action: "card-virtual",
  cardholder_id: "<issuer-user-id>",
  program_id: "<issuer-card-program-id>",
});

console.log("Card issued:", card.card_id);

The card is now a spend instrument the agent can use at checkout. It is not a transfer: no money moves until a merchant authorizes against it, and no authorization clears without passing the mandate check.

2. Check card status

card-get reads the card's current state. Useful as a pre-flight before handing the card to a purchase flow:

const status = await session.execute("codespar_issue", {
  action: "card-get",
  card_id: card.card_id,
});

console.log(status); // { card_id, state: "active", ... }

3. Authorizations hit the mandate, not your inbox

When the agent uses the card at a merchant, the issuer calls our authorization webhook in real time. We evaluate the authorization against the agent's mandate: amount caps, merchant policy, velocity. Within budget approves; outside it declines. Every decision lands on the audit chain, same as a governed Pix payment.

You do not integrate anything for this step. It is the point of issuing through the platform instead of holding raw issuer credentials: the policy check is server-side and the agent cannot route around it.

4. Freeze, then cancel

Freeze is reversible and takes effect at the next authorization attempt. Cancel is terminal:

// Pause the card without destroying it
await session.issue({
  action: "card-control",
  card_id: card.card_id,
  control: "freeze",
  reason: "agent budget review",
});

// Resume
await session.issue({
  action: "card-control",
  card_id: card.card_id,
  control: "unfreeze",
});

// Kill it for good
await session.issue({
  action: "card-control",
  card_id: card.card_id,
  control: "cancel",
  reason: "agent decommissioned",
});

The reason string is stamped on the control action and shows up in the audit trail, so a freeze six months from now still explains itself.

MCP variant: ask for the card in plain language

If your agent connects over MCP (npx -y @codespar/mcp serve in Claude, Codex, or any MCP client), it can do all of the above conversationally:

"Issue a virtual card for this agent with a R$500 monthly cap. If anything looks off, freeze it."

The agent calls codespar_issue with card-virtual, the cap lives in the mandate, and the freeze is one card-control call away. Same server-side governance; no SDK code required.

Variations

Physical card

Same call, action: "card-physical", plus a shipping_address. Useful when the "agent" is a back-office workflow whose spend ends at a real-world counter:

await session.issue({
  action: "card-physical",
  cardholder_id: "<issuer-user-id>",
  program_id: "<issuer-card-program-id>",
  shipping_address: {
    line1: "Av. Exemplo 100",
    city: "Rio de Janeiro",
    state: "RJ",
    postal_code: "22000-000",
    country: "BR",
  },
});

One card per agent

Issue one virtual card per agent identity rather than sharing a card across agents. Cards are cheap, mandates are per-agent, and a per-agent card means a freeze isolates exactly one workload instead of pausing your whole fleet.

Current status

Card issuing runs in a partner staging environment today; production issuing is in provisioning. The authorization webhook runs in observe mode before we flip it to enforce: decisions are computed and logged against the mandate, but the issuer's own limits are the backstop until enforcement is enabled per account. Build against this cookbook now; the flip to enforce changes no API surface.

Next steps

Agent Card | CodeSpar