# Agent spend

Agent spend is in beta. It watches AI agents that hold cards or pay from your accounts. Each agent asks Veqen before it spends, or tells Veqen afterwards, and Veqen matches every authorization and payment on the platforms you connect to that record, judged against the agent's mandate. Asking before spending, recording what agents did and the [free audit](/docs/audit) work on every plan; continuous matching, incidents, card freeze, evidence and the monthly report come with any paid plan, at no extra charge while it's in beta, for up to $100,000 of agent spend a month.

Veqen never moves or holds money. It reads with a read-only credential, and freezing a card or setting its limit uses a separate credential you add for that alone.

## Connect a platform

Under Settings › Cards and accounts, or `PUT /v1/agent-spend/platforms/{platform}`, or the `card_platforms` MCP tool:

| Platform | What Veqen reads | Read credential | Freeze access |
|---|---|---|---|
| Stripe Issuing | Cards, every authorization as it happens, refunds | A restricted key with read access to Issuing cards, cardholders, authorizations and transactions | A restricted key with write access to Issuing cards |
| Ramp | The funds your agent cards spend from, their limits, and every transaction, declines included | An app's client id and secret with `funds:read` and `transactions:read` | A second app with `funds:write` |
| Brex | Cards and their posted transactions | A user token with `cards.readonly` and `transactions.card.readonly` | A user token with `cards` |
| Mercury | Cards, Mercury's own agent cards, and the card spend, ACH and wire payments leaving the account you name | A read-only API token | Not in the beta: freeze its cards in Mercury |

A Ramp fund counts as one card, because agent cards spend from a fund and Ramp suspends the fund. Veqen reads Mercury without changing anything there while agent spend is in beta, so a Mercury card is frozen in Mercury. Veqen reads each platform every five minutes, going back six hours each time and three days on the day's first read, so pending charges settle. The first read covers the last 30 days: Veqen judges that history and shows it, but opens no incident for anything from before the platform was connected.

## Say which cards are agents'

Only an agent's cards are matched; a person's card is left alone. Veqen reads the agent from a card's metadata (`veqen_agent` or `agent`), from its name (`agent: procurement-bot`), or from Mercury's agent card flag. Assign the rest under Agent spend › Cards, with `PATCH /v1/agent-spend/cards/{id}` or the `agent_cards` tool, using `-` for a person's card. For a Mercury account set aside for agents, name the agent on the connection and every payment from it is that agent's.

## Set a mandate

Each agent can have its own mandate, and the agent named `*` sets the default every other agent follows:

- **Refuse one action above** (`per_action_usd`): the check answers deny.
- **A person approves one action above** (`approval_over_usd`) and **past the monthly limit** (`monthly_usd`): the check answers approval.
- **Payees it may pay on its own** (`merchants`): anything else waits for a person. **Payees it may never pay** (`blocked`) are refused.
- **Paused** refuses everything, and **freeze its cards by themselves** freezes the card when an incident needs action, where freeze access is set up.

`PUT /v1/agent-spend/agents/{agent}/policy`, or the `set_agent_policy` tool, changes it. Only the fields you send change, and a limit of 0 or `null` removes it. Owners, admins and finance members set mandates and answer approvals; turning automatic freezing on or off also takes the protection role (owners, admins and security members), because it acts at the platform.

## Ask before spending

```python
import veqen

decision = veqen.check_spend("procurement-bot", 120.00, payee="Acme Supplies", purpose="Laptop stand for OPS-412")
if decision.allowed:
    pay()
```

```javascript
import { checkSpend } from "@veqen/sdk";

const decision = await checkSpend({ agent: "procurement-bot", amount: 120, payee: "Acme Supplies", purpose: "Laptop stand" });
if (decision.allowed) await pay();
```

The answer is `allow`, `approval` or `deny`, with the reasons and what the agent has left this month. With `approval`, the people who approve hear about it, and the agent asks again with the same `action_id` (or reads `GET /v1/agent-actions/{action_id}`) to see their answer; a request nobody answers lapses in a day. An agent has at most 20 requests waiting for a person: past that the answer is deny, and only its first waiting request sends an alert. A send-only key reads and cancels only the actions it sent. When the SDK can't reach Veqen, or has no API key, the answer is `on_error`, which is `deny` unless you choose `allow`. A send-only key is enough: `POST /v1/agent-actions/check`. Over MCP, `check_agent_spend` does the same for owners, admins and members, the roles that may make keys.

If the agent decides not to go ahead, `POST /v1/agent-actions/{action_id}/cancel` stops it counting toward the month. To tell Veqen afterwards instead of asking first, use `veqen.record_action(...)`, `recordAction(...)`, `POST /v1/agent-actions` (up to 1,000 at a time) or `record_agent_actions`.

## What Veqen flags

Each transaction on an agent's card is matched to one of the agent's actions: from within a week before it (and a day after, for posting dates), within 10% or a dollar of the amount, recorded before Veqen first saw the transaction (or within ten minutes after), on a rail that fits, and naming the payee. A payee matches a merchant when every word of one, three letters or more, is in the other, so "Acme Supplies" matches "ACME SUPPLIES INC" and "Ramp" doesn't match "Trampoline". An action without a payee matches only when it names the card. Then the mandate is checked:

| Rule | What it means |
|---|---|
| No action explains it | Card spend the agent never recorded |
| Told not to | Spend after Veqen answered deny |
| Not approved | Spend a person was asked to approve and didn't |
| Paused, blocked payee, payee not allowed | Spend outside the mandate |
| Over one action's limit, over the month | Spend past the mandate's limits |
| Dormant card | A card Veqen has known for 30 days, with no spend in them, was used |
| Pooled merchant | A merchant agents were tricked into paying at two or more other companies |
| New merchant | A merchant the agent has never paid, where it has a history |
| Declined | The platform declined the agent's card |

A card's findings close together in time group into one incident on the [Incidents](/docs/protection) list, which alerts owners, admins and security members within minutes and can freeze the card from the alert. "This was us" keeps the card quiet for a week, except for spend Veqen told the agent not to make, spend nobody approved, a paused agent, a blocked payee or a dormant card. An action the agent says it took that no platform showed after three days is marked unseen, and it can still match when the transaction arrives late.

## Freeze, evidence and disputes

Freeze a card from its incident, from Agent spend › Cards, with `POST /v1/agent-spend/cards/{id}/freeze`, or with the `agent_cards` tool. With two-person shut-off on, a freeze waits for a second owner, admin or security member, for a day. A freeze the mandate asks for is tried up to three times, an hour apart, and each answer from the platform is on the incident's timeline. The incident's evidence (`GET /v1/incidents/{id}/evidence`, or `.csv`) sets each charge against the action the agent recorded and any approval, with the mandate in force, for a dispute or an auditor. Record the dispute on the incident and what came back when it's settled.

## The monthly report

Agent spend › Report, `GET /v1/agent-spend/report/{YYYY-MM}` (or `.csv`), or `agent_spend_view` with `view: report` shows each agent's spend, how much an action explained, declines, approvals, incidents, freezes and what came back, with the mandate in force. Card platforms post the purchases to your books themselves, so Veqen doesn't book them again; the report is the evidence of how the spend was controlled. It takes the month-end permission.

## Everything else over the API and MCP

| What | API | MCP |
|---|---|---|
| Agents and this month's spend | `GET /v1/agent-spend` | `agent_spend_view` |
| One agent | `GET /v1/agent-spend/agents/{agent}` | `agent_spend_view` (`view: agent`) |
| Transactions and actions | `GET /v1/agent-spend/transactions`, `GET /v1/agent-spend/actions` | `agent_spend_view` |
| Approvals | `GET /v1/agent-spend/approvals`, `POST /v1/agent-spend/approvals/{id}` | `agent_approvals` |
| Cards, freezes and limits | `GET /v1/agent-spend/cards`, `PATCH` and `POST .../freeze`, `.../limit`, `POST /v1/agent-spend/freezes/{id}/confirm` | `agent_cards` |
| Platforms and freeze access | `GET`, `PUT` and `DELETE /v1/agent-spend/platforms/{platform}` and `.../freeze-access` | `card_platforms` |
