> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentcard.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Set rules on a card

> Presets are optional rules for Vault purchases. Save one, attach it to a stored card, and only the purchases paid with that card are judged.

Presets are optional. Without them, every Vault purchase goes through as usual. Presets are the rules you put on what an agent may buy: a spend cap, a merchant list, a currency, a time window. A preset can apply to one of a user's stored cards.

Save a preset under a name of your choice, then attach it where it should apply.

```bash theme={null}
curl -X PUT https://api.agentcard.sh/api/v2/vault/presets/office-supplies \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"per_day": 50, "only_merchants": "EXAMPLE SHOP,ACME", "currencies": "usd"}'
```

Once you attach a preset, Agentcard judges each purchase it covers. A purchase made outside of the preset rules is refused, nothing is charged, and you are told which preset and which rule(s) refused it.

Attach a preset when you want a purchase-level restriction, guarding against how much a particular agent or set of agents should spend in a day, for example. You can also use presets while you build: set a tight preset to test your work before shipping to production. The rules and their refusal codes are the ones a [card preset](/issuing/set-rules-on-a-card) uses.

## Choose what to restrict

Pick the rules the preset holds when you save it. Caps count separately for each card the preset is attached to. Caps use the amount the processor charges. Send `amount` to have a purchase judged the moment your agent opens it.

| Rule                              | What it does                                                                                                                                                                       |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Total**                         | The most the purchases this preset covers spend in all, in US dollars.                                                                                                             |
| **Rate**                          | A cap per rolling 24 hours, 7 days, or 30 days, in US dollars, for the purchases this preset covers.                                                                               |
| **Category**                      | `meals`, `groceries`, `travel`, `software`, `ai`, `wellness`, `retail`. Judged on the merchant Agentcard names from the checkout page, never on the text your agent sends.         |
| **Merchant**                      | Names the merchant must match, such as `EXAMPLE SHOP` or `shop.example.com`. A pattern is a case-insensitive part of the merchant's name or checkout host as Agentcard names them. |
| **Place**                         | The country the merchant is in, such as `US, Canada` or `europe`. Not where your agent runs.                                                                                       |
| **Currency**                      | The currencies a purchase may be in, such as `usd,eur`.                                                                                                                            |
| **Time window**                   | Days and hours, always in a named zone. UTC unless you pass `timezone`.                                                                                                            |
| **Where the purchase comes from** | A Vault purchase always comes from your agent through the API, which counts as `api`. A rule that allows only `cli` refuses every one of them.                                     |

Available preset parameters:

| Field                                | Meaning                                                                                                                                  |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `total`                              | Cap on the purchases this preset covers, over all time, in US dollars                                                                    |
| `per_day` / `per_week` / `per_month` | Rolling caps for the purchases this preset covers, in US dollars                                                                         |
| `categories`                         | Categories, comma-separated: `meals`, `groceries`, `travel`, `software`, `ai`, `wellness`, `retail`                                      |
| `only_merchants`                     | Merchant name or host patterns the purchase must match, comma-separated                                                                  |
| `only_in`                            | Places, comma-separated: a country (`US`, `Canada`), a US state (`California`, `US-CA`), or a region (`europe`, `north-america`, `apac`) |
| `currencies`                         | The currencies a purchase may be in, comma-separated, by code or common name: `usd,eur` or `dollars,euros`                               |
| `only_days`                          | Days, comma-separated: `mon,tue,wed`, or `weekdays` / `weekends`                                                                         |
| `only_hours`                         | For example `9-17`, 24-hour clock, in `timezone`                                                                                         |
| `timezone`                           | IANA zone for `only_days` and `only_hours`, default `UTC`                                                                                |
| `only_from`                          | Where purchases may come from. A Vault purchase is always `api`                                                                          |
| `mode`                               | What the preset does when a purchase breaks any of its rules: `strict` refuses it (the default), `watch` lets it through and tells you   |

Caps are in US dollars. A purchase whose processor names no amount, with no `amount` from your agent, is refused right before the card is sent with `amount_unknown`, and a purchase in another currency is refused for the currency.

## Attach to a card

Attach a preset to one of a user's stored cards, and every purchase paid with that card follows it. Read the card id from the user's stored cards, or from the `id` in the `vault.card_stored` event:

```bash theme={null}
curl "https://api.agentcard.sh/api/v2/vault_cards?user_id=cmtvwbbz80002jpcctuianq78" \
  -H "Authorization: Bearer $ORG_TOKEN"
```

```json theme={null}
{
  "object": "list",
  "data": [
    {
      "object": "vault_card",
      "id": "cmtvwbbzj0006jpccycjrkqy4",
      "brand": "visa",
      "last4": "7318",
      "expiry_month": 12,
      "expiry_year": 2030,
      "created_at": "2026-09-10T17:36:29.700Z"
    }
  ]
}
```

Attach the preset to that card:

```bash theme={null}
curl -X PUT https://api.agentcard.sh/api/v2/vault/presets/office-supplies/attachments \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind": "card", "target_id": "cmtvwbbzj0006jpccycjrkqy4"}'
```

```json theme={null}
{
  "object": "vault_preset",
  "name": "office-supplies",
  "id": "cmtvwbc0g000bjpcc88yiyx8z",
  "version": 1,
  "summary": "Up to $50.00 per day. Merchants: EXAMPLE SHOP, ACME. Currency: USD.",
  "attachments": [
    {
      "kind": "card",
      "target_id": "cmtvwbbzj0006jpccycjrkqy4",
      "last4": "7318"
    }
  ]
}
```

A card id that is not one of your users' cards is refused:

```json theme={null}
{
  "error": {
    "code": "card_not_found",
    "message": "No stored card with that id belongs to one of your users. List a user's cards at GET /api/v2/vault_cards?user_id=…, or read the id from the vault.card_stored event.",
    "docs": "https://docs.agentcard.sh"
  }
}
```

From now on `office-supplies` judges every purchase paid with that card. Your agent opens a purchase on the card by sending `card_id` on the checkout authorization; at a merchant the preset does not allow, the call answers HTTP 403 and no authorization exists:

```bash theme={null}
curl -X POST https://api.agentcard.sh/api/v2/checkout/authorizations \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"user": "cmtvwbbz80002jpcctuianq78", "merchant": "Braxter'\''s Deli", "checkout_origin": "https://www.braxters-deli.example", "amount": 2306, "currency": "usd", "psp": "shopify", "card_id": "cmtvwbbzj0006jpccycjrkqy4", "request": { "url": "https://checkout.pci.shopifyinc.com/sessions", "method": "POST", "headers": {}, "body": "..." }}'
```

```json theme={null}
{
  "error": {
    "code": "merchant_denied",
    "message": "Preset \"office-supplies\", attached to the card ending in 7318: merchant denied. This purchase is at braxters-deli.example. The preset allows EXAMPLE SHOP and ACME. Add the merchant to the preset with PUT /api/v2/vault/presets/office-supplies, or buy from an allowed merchant.",
    "docs": "https://docs.agentcard.sh",
    "preset": {
      "id": "cmtvwbc0g000bjpcc88yiyx8z",
      "version": 1,
      "name": "office-supplies"
    },
    "attachment": {
      "kind": "card",
      "target_id": "cmtvwbbzj0006jpccycjrkqy4",
      "last4": "7318"
    },
    "rule": "merchant",
    "stage": "create",
    "refusals": [
      {
        "preset": {
          "id": "cmtvwbc0g000bjpcc88yiyx8z",
          "version": 1,
          "name": "office-supplies"
        },
        "attachment": {
          "kind": "card",
          "target_id": "cmtvwbbzj0006jpccycjrkqy4",
          "last4": "7318"
        },
        "rule": "merchant",
        "reason": "merchant_denied",
        "message": "Preset \"office-supplies\", attached to the card ending in 7318: merchant denied. This purchase is at braxters-deli.example. The preset allows EXAMPLE SHOP and ACME. Add the merchant to the preset with PUT /api/v2/vault/presets/office-supplies, or buy from an allowed merchant."
      }
    ]
  }
}
```

Send `card_id`, or leave the user with exactly one stored card, and Agentcard judges the card's presets the moment your agent opens the purchase; otherwise it judges them right before the card is sent, once the user has chosen and unlocked a card.

To stop using the preset on that card, detach it with the same body:

```bash theme={null}
curl -X DELETE https://api.agentcard.sh/api/v2/vault/presets/office-supplies/attachments \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind": "card", "target_id": "cmtvwbbzj0006jpccycjrkqy4"}'
```

```json theme={null}
{
  "object": "vault_preset",
  "name": "office-supplies",
  "id": "cmtvwbc0g000bjpcc88yiyx8z",
  "version": 1,
  "summary": "Up to $50.00 per day. Merchants: EXAMPLE SHOP, ACME. Currency: USD.",
  "attachments": []
}
```

A per-day cap attached to a card counts that card's purchases alone. Attach the same preset to two cards and each has its own \$50 a day.

## Combine several presets

When one or more presets apply to a purchase, the purchase must satisfy all of them. Agentcard judges each purchase against every attached preset, and any that would cause a refusal are named in the response.

## Read a refused purchase

Agentcard checks a purchase twice: when your agent opens it, and again right before the card is sent, after the user approves. If a preset refuses at the second check, the user sees:

```text theme={null}
This purchase was refused
The company that set up this checkout has rules on its purchases, and this one is outside them. Your card was not sent.
Nothing was charged. Ask your agent, or the company, before trying again.
```

Your agent reads the same outcome when it reads the authorization back: `status` is `declined`, with the preset and the rule named. A purchase every attached preset allows is approved and paid like any other.

## Replace or delete a preset

Read your presets, or one preset and where it is attached:

```bash theme={null}
curl https://api.agentcard.sh/api/v2/vault/presets \
  -H "Authorization: Bearer $ORG_TOKEN"
curl https://api.agentcard.sh/api/v2/vault/presets/office-supplies \
  -H "Authorization: Bearer $ORG_TOKEN"
```

To replace a preset, save the same name again. The new rules apply everywhere it is attached. Purchases already counted toward a cap stay counted, so tightening a rate at noon does not reset the day.

To delete a preset, remove it by name. It stops judging every purchase it was attached to:

```bash theme={null}
curl -X DELETE https://api.agentcard.sh/api/v2/vault/presets/office-supplies \
  -H "Authorization: Bearer $ORG_TOKEN"
```

Save the same name again later and its caps start from zero.

## Relax restrictions

You can relax a preset's restrictions by changing what it does when a purchase breaks a rule: a warning instead of the default refusal. Set `"mode": "watch"` on the preset, or save the same rules under a second preset with `"mode": "watch"`. For example, a currency rule:

```bash theme={null}
curl -X PUT https://api.agentcard.sh/api/v2/vault/presets/watch-eur \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"currencies": "eur", "mode": "watch"}'
```

Attach it, and a purchase in another currency goes through. Once the charge is recorded you are told, with the preset and where it is attached named:

```text theme={null}
Watched purchase: $23.06 at Example Shop
Bought by cmtvwbbz80002jpcctuianq78.

Preset "watch-eur", attached to the card ending in 7318: a $23.06 purchase at example-shop.example went through. It is in USD, and this preset allows EUR only. Nothing is blocked. To stop these notices, change the preset with PUT /api/v2/vault/presets/watch-eur.
```

Every rule relaxes the same way. A watched cap says by how much the purchase went over it.

## Receive the notices

Every refusal and every watched purchase sends one notice, three ways: an event to your webhook, an email to your billing contact and your account's owners and admins, and a post in your Slack conversation with Agentcard once you have connected it. A test-mode purchase sends the webhook only. Every notice names the preset, where it is attached, the rule, and what to do next.

A refusal when your agent opens the purchase is a `checkout_authorization.refused` event. It has no authorization id, because none was created:

```json theme={null}
{
  "authorization_id": null,
  "user_id": "cmtvwbbz80002jpcctuianq78",
  "external_user_id": "cmtvwbbz80002jpcctuianq78",
  "merchant": "Braxter's Deli",
  "amount": 2306,
  "currency": "usd",
  "amount_display": "$23.06",
  "psp": "shopify",
  "mode": "token",
  "stage": "create",
  "reason": "merchant_denied",
  "rule": "merchant",
  "message": "Preset \"office-supplies\", attached to the card ending in 7318: merchant denied. This purchase is at braxters-deli.example. The preset allows EXAMPLE SHOP and ACME. Add the merchant to the preset with PUT /api/v2/vault/presets/office-supplies, or buy from an allowed merchant.",
  "preset": {
    "id": "cmtvwbc0g000bjpcc88yiyx8z",
    "name": "office-supplies",
    "version": 1
  },
  "attachment": {
    "kind": "card",
    "last4": "7318",
    "target_id": "cmtvwbbzj0006jpccycjrkqy4"
  },
  "refusals": [
    {
      "rule": "merchant",
      "preset": {
        "id": "cmtvwbc0g000bjpcc88yiyx8z",
        "name": "office-supplies",
        "version": 1
      },
      "reason": "merchant_denied",
      "message": "Preset \"office-supplies\", attached to the card ending in 7318: merchant denied. This purchase is at braxters-deli.example. The preset allows EXAMPLE SHOP and ACME. Add the merchant to the preset with PUT /api/v2/vault/presets/office-supplies, or buy from an allowed merchant.",
      "attachment": {
        "kind": "card",
        "last4": "7318",
        "target_id": "cmtvwbbzj0006jpccycjrkqy4"
      }
    }
  ]
}
```

A refusal right before the card is sent is a `checkout_authorization.declined` event with the same fields. A watched purchase is a `checkout_authorization.watched` event, sent after `approved`. See [Checkout authorization events](/webhooks/checkout-authorizations/overview).

The email for the refusal above:

```text theme={null}
Purchase refused: $23.06 at Braxter's Deli
Your preset refused a $23.06 purchase at Braxter's Deli for cmtvwbbz80002jpcctuianq78. Nobody was asked to approve it, and nothing was charged.

Preset "office-supplies", attached to the card ending in 7318: merchant denied. This purchase is at braxters-deli.example. The preset allows EXAMPLE SHOP and ACME. Add the merchant to the preset with PUT /api/v2/vault/presets/office-supplies, or buy from an allowed merchant.
```

The Slack post for the same refusal:

```text theme={null}
⛔ $23.06 at Braxter's Deli for cmtvwbbz80002jpcctuianq78 refused by your preset. Nobody was asked to approve it, and nothing was charged.
Preset "office-supplies", attached to the card ending in 7318: merchant denied. This purchase is at braxters-deli.example. The preset allows EXAMPLE SHOP and ACME. Add the merchant to the preset with PUT /api/v2/vault/presets/office-supplies, or buy from an allowed merchant.
```

## Look up a refusal code

Codes from `merchant_denied` down are returned when your agent opens the purchase or right before the card is sent. The first three are returned when you save or attach.

| Code                   | What it means                                                                                                                                                                               | What to do                                                                                                              |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `policy_invalid`       | The rules cannot be read: an unknown category, an ambiguous place code, an unknown built-in, an ambiguous currency, a misspelled zone, a bad name, or a mode other than `strict` or `watch` | Correct the rule the message names                                                                                      |
| `preset_not_found`     | No preset of that name is saved                                                                                                                                                             | Save it, or list your presets                                                                                           |
| `card_not_found`       | The card id is not a card one of your users stored                                                                                                                                          | Use the id from the stored-cards list or the `vault.card_stored` event                                                  |
| `merchant_denied`      | The merchant's name and checkout host match none of the patterns the preset allows                                                                                                          | Add the merchant, or buy from an allowed one                                                                            |
| `merchant_unknown`     | The purchase carries no checkout origin, so there is no merchant to match                                                                                                                   | Update the checkout SDK, or send `checkout_origin` on the authorization                                                 |
| `category_denied`      | The merchant's category is outside the category rule, and the preset is `strict`                                                                                                            | Buy from an allowed merchant, or allow this one with a `merchant_allow` rule on its host                                |
| `category_unknown`     | Agentcard does not know the merchant, or the purchase carries no checkout origin, so the category is unknown                                                                                | Buy from a merchant Agentcard knows, allow this one with a `merchant_allow` rule on its host, or send `checkout_origin` |
| `geo_denied`           | The merchant is outside the places the rule allows                                                                                                                                          | Buy from a merchant in an allowed place, or widen the rule                                                              |
| `geo_unknown`          | Agentcard does not know where the merchant is: an unknown merchant, or one that sells in several countries                                                                                  | Buy from a merchant in an allowed place, or drop the place rule                                                         |
| `spend_total_exceeded` | The purchase would take this preset past its total, or is in a currency other than dollars                                                                                                  | Raise the total, or pay in dollars                                                                                      |
| `spend_rate_exceeded`  | The purchase would take this preset's rolling window past its cap                                                                                                                           | Wait for the window to roll, or raise the cap                                                                           |
| `spend_rate_unknown`   | A currency other than dollars, so the cap cannot be checked                                                                                                                                 | Pay in dollars                                                                                                          |
| `amount_unknown`       | The preset caps spending, and right before the card was sent no authority named an amount: the processor's request carries none and your agent sent none                                    | Send `amount` with `currency` on the authorization                                                                      |
| `currency_denied`      | The currency is outside the currency rule, and the preset is `strict`                                                                                                                       | Buy in an allowed currency, or change the rule                                                                          |
| `currency_unknown`     | No currency on the purchase, and the preset is `strict`                                                                                                                                     | Send `currency`, or set `mode` to `watch`                                                                               |
| `time_window_denied`   | Outside the allowed days or hours, in the rule's zone                                                                                                                                       | Retry inside the window, or change it                                                                                   |
| `surface_denied`       | The preset allows purchases from somewhere other than the API; every Vault purchase comes through the API                                                                                   | Allow `api` in `only_from`, or drop the rule                                                                            |

Every refusal names the preset that refused and the card it is attached to, with its last four digits. When several presets refuse the same purchase, `refusals` lists each one, and the top-level fields are the first.
