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

# Control Types

> Every policy type and the configuration it accepts.

There are five policy types, in two families: **restrictions** that block transactions by what or where, and **limits** that cap by how much or how often. Every policy carries a `type`, a [`scope`](/spend-policies/scopes), a `name`, and a `config` whose shape depends on the type.

All amounts are in USD.

## Restrictions

Restrictions block a transaction based on the single transaction in front of them. They hold no running state.

### Merchant restriction

`type: MERCHANT_RESTRICTION`. Blocks transactions whose merchant matches the criteria. The match works on one dimension at a time:

| Dimension          | Matches on             | Value                              |
| ------------------ | ---------------------- | ---------------------------------- |
| `MCC`              | Merchant Category Code | A list of 4-digit codes            |
| `MERCHANT_COUNTRY` | The merchant's country | A list of ISO 3166-1 alpha-2 codes |

Block a set of merchant categories (here, gambling and dating):

```json theme={null}
{
  "type": "MERCHANT_RESTRICTION",
  "scope": { "type": "CARD", "id": "<cardId>" },
  "name": "Block gambling and dating",
  "config": {
    "match": { "dimension": "MCC", "codes": ["7995", "7273"] }
  }
}
```

Block transactions in specific countries:

```json theme={null}
{
  "config": {
    "match": { "dimension": "MERCHANT_COUNTRY", "countries": ["RU", "KP"] }
  }
}
```

The merchant MCC and country are visible on every transaction under `merchant`, so you can confirm what a given transaction would match against.

<Tip>
  For a full list of Merchant Category Codes, see page 24 of the [Visa Merchant Data Standards Manual](https://usa.visa.com/content/dam/VCOM/download/merchants/visa-merchant-data-standards-manual.pdf).
</Tip>

### Channel restriction

`type: CHANNEL_RESTRICTION`. Blocks transactions on the listed channels. A transaction is blocked if its channel is in the list.

| Channel     | Description               |
| ----------- | ------------------------- |
| `POS`       | In-store, card present    |
| `ECOMMERCE` | Online / card-not-present |
| `ATM`       | Cash withdrawal           |

Disable ATM withdrawals on a card:

```json theme={null}
{
  "type": "CHANNEL_RESTRICTION",
  "scope": { "type": "CARD", "id": "<cardId>" },
  "name": "No ATM",
  "config": { "channels": ["ATM"] }
}
```

## Limits

Limits cap value. The per-transaction cap looks only at the current transaction; the spend and count limits track usage over a calendar window.

### Transaction amount limit

`type: TRANSACTION_AMOUNT_LIMIT`. Rejects any single transaction above `maxAmount`. Has no window.

```json theme={null}
{
  "type": "TRANSACTION_AMOUNT_LIMIT",
  "scope": { "type": "CARD", "id": "<cardId>" },
  "name": "Max $1,000 per transaction",
  "config": { "maxAmount": 1000 }
}
```

### Spend limit

`type: SPEND_LIMIT`. Caps cumulative spend over a calendar window at `maxAmount`. A transaction is rejected if it would push spend in the current window past the cap.

```json theme={null}
{
  "type": "SPEND_LIMIT",
  "scope": { "type": "CARD", "id": "<cardId>" },
  "name": "Daily card limit",
  "config": {
    "window": { "type": "CALENDAR", "period": "DAILY" },
    "maxAmount": 500
  }
}
```

### Transaction count limit

`type: AUTHORIZATION_COUNT_LIMIT`. Caps the number of transactions over a calendar window at `maxCount`.

```json theme={null}
{
  "type": "AUTHORIZATION_COUNT_LIMIT",
  "scope": { "type": "CARD", "id": "<cardId>" },
  "name": "Max 10 transactions a day",
  "config": {
    "window": { "type": "CALENDAR", "period": "DAILY" },
    "maxCount": 10
  }
}
```

### Windows

Spend and count limits track usage over a calendar window. The window is fixed when the policy is created; to change the period, create a new policy.

| Period     | Resets                          |
| ---------- | ------------------------------- |
| `DAILY`    | Start of each day               |
| `WEEKLY`   | Start of each ISO week (Monday) |
| `MONTHLY`  | Start of each month             |
| `YEARLY`   | Start of each year              |
| `LIFETIME` | Never                           |

Windows are calendar-based in UTC. A daily limit resets at 00:00 UTC, not on a rolling 24-hour basis. When a window rolls over, usage starts fresh automatically.

<Expandable title="Restricting a limit to certain transactions (advanced)">
  Spend and count limits accept an optional `filter` so the limit only counts transactions that match it. This lets you cap one slice of spend without affecting the rest. The filter narrows by channel, by merchant, or both (a transaction must match every dimension present).

  Cap ATM cash to \$300 a day without limiting other spend:

  ```json theme={null}
  {
    "type": "SPEND_LIMIT",
    "scope": { "type": "CARD", "id": "<cardId>" },
    "name": "Daily ATM cash cap",
    "config": {
      "window": { "type": "CALENDAR", "period": "DAILY" },
      "maxAmount": 300,
      "filter": { "channels": ["ATM"] }
    }
  }
  ```

  A filtered limit tracks its own usage, independent of any unfiltered limit on the same card and window. The `merchant` filter takes the same shape as a [merchant restriction](#merchant-restriction)'s `match`.
</Expandable>

### How usage is counted

Spend and count limits track usage as transactions are authorized. Usage mostly only goes up, but a few later events adjust it.

* **Approved transactions** add to usage: a spend limit by the authorized amount, a count limit by one.
* **Declined transactions** never count.
* **Reversals release usage.** When the network reverses an authorization before it settles, a full reversal frees both the amount and the transaction from the window. A partial reversal frees only the reversed amount, and the transaction still counts toward a count limit because it did occur.
* **Expired or voided authorizations** that never settle are released the same way as a full reversal.
* **Refunds do not restore usage.** A refund is a separate credit that can arrive days or weeks later, so it does not add headroom back to the window. Spending `$1,000` and later receiving a `$1,000` refund still leaves only the original headroom for that window.

Usage reflects the amount authorized. If a transaction later settles for more than was authorized (a restaurant tip or a fuel pump hold, for example), the limit was already evaluated at authorization and the difference is not re-checked.

## Common use cases

Each policy type maps to real controls you can ship. The examples below are grouped by who the control serves: the cardholder configuring their own card, and the program enforcing rules across cardholders. Every payload is a complete `POST /policies` body.

### Cardholder-driven controls

Controls a cardholder sets on their own card, usually exposed through your app. These attach at the `CARD` scope.

<Expandable title="Let a cardholder set their own daily spend limit">
  A cardholder caps their own card at `$200` a day. Editing the amount later with `PUT /policies/{id}/config` keeps the day's recorded spend.

  ```json theme={null}
  {
    "type": "SPEND_LIMIT",
    "scope": { "type": "CARD", "id": "<cardId>" },
    "name": "My daily limit",
    "config": {
      "window": { "type": "CALENDAR", "period": "DAILY" },
      "maxAmount": 200
    }
  }
  ```
</Expandable>

<Expandable title="Lock online payments on a card">
  A cardholder turns off card-not-present spend while keeping in-store and ATM use. Re-enabling it later is a single `POST /policies/{id}/disable`.

  ```json theme={null}
  {
    "type": "CHANNEL_RESTRICTION",
    "scope": { "type": "CARD", "id": "<cardId>" },
    "name": "Online payments off",
    "config": { "channels": ["ECOMMERCE"] }
  }
  ```
</Expandable>

<Expandable title="Cap the size of any single purchase">
  A cardholder blocks any transaction over `$300` on their card, leaving the daily total uncapped.

  ```json theme={null}
  {
    "type": "TRANSACTION_AMOUNT_LIMIT",
    "scope": { "type": "CARD", "id": "<cardId>" },
    "name": "Max $300 per purchase",
    "config": { "maxAmount": 300 }
  }
  ```
</Expandable>

### Program-driven controls

Rules you enforce across the program or per cardholder, independent of what the cardholder sets. Restrictions can attach at the `PROJECT` scope to cover every card; spend and count limits attach per cardholder (`USER`) or per card (`CARD`).

<Expandable title="Block prohibited merchant categories across every card">
  A program-wide restriction blocking gambling and dating merchants on every card. Attaching at the `PROJECT` scope means new cards inherit it automatically.

  ```json theme={null}
  {
    "type": "MERCHANT_RESTRICTION",
    "scope": { "type": "PROJECT" },
    "name": "Block gambling and dating",
    "config": {
      "match": { "dimension": "MCC", "codes": ["7995", "7273"] }
    }
  }
  ```
</Expandable>

<Expandable title="Disable ATM withdrawals across the program">
  No card in the program can withdraw cash. To allow it on a specific card, leave this off and apply ATM rules per card instead.

  ```json theme={null}
  {
    "type": "CHANNEL_RESTRICTION",
    "scope": { "type": "PROJECT" },
    "name": "No ATM withdrawals",
    "config": { "channels": ["ATM"] }
  }
  ```
</Expandable>

<Expandable title="Cap a cardholder's monthly spend across all their cards">
  A `$5,000` monthly cap at the `USER` scope counts the combined spend of every card the cardholder holds, not each card on its own.

  ```json theme={null}
  {
    "type": "SPEND_LIMIT",
    "scope": { "type": "USER", "id": "<userId>" },
    "name": "Monthly cardholder cap",
    "config": {
      "window": { "type": "CALENDAR", "period": "MONTHLY" },
      "maxAmount": 5000
    }
  }
  ```
</Expandable>

<Expandable title="Cap daily transaction counts across the whole program">
  A program-wide ceiling on how many transactions each card can make per day is a useful guardrail against runaway or automated charges, applied uniformly without configuring each card.

  Count limits cannot attach at the `PROJECT` scope through the API, so this is not something you can set up yourself. Contact the Reap team and we will configure a program-wide transaction-count limit for you.
</Expandable>

For capping one slice of spend on its own (such as ATM cash), see [restricting a limit to certain transactions](#windows).

## Next

* [Scopes](/spend-policies/scopes): where each of these attaches and how overlapping policies resolve.
