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

# Frequency Caps

> Control delivery volume with per-channel, per-category, and per-offer limits.

<Note>
  **See also**: [Frequency Caps concept and configuration](/decisioning/frequency-caps) for what this API powers, when to call it, and how it is configured.
</Note>

## Overview

Frequency caps limit how many recommendations or deliveries can occur within a time period. They operate at three scopes:

* **Channel**: Max emails/day, max push notifications/week
* **Category**: Max mandatory communications/week
* **Offer**: Max deliveries of a specific offer/month

***

## List Frequency Caps

```http theme={null}
GET /api/v1/frequency-caps
```

Returns all frequency caps for the tenant, ordered by creation date (newest first).

### Response

```json theme={null}
{
  "data": [
    {
      "id": "fc_001",
      "tenantId": "tenant_001",
      "name": "Email Campaign Daily Cap 10K",
      "scope": "channel",
      "scopeId": "ch_email",
      "maxVolume": 10000,
      "period": "daily",
      "enabled": true,
      "currentCount": 3245,
      "resetAt": "2026-03-31T00:00:00.000Z",
      "createdAt": "2026-03-15T10:00:00.000Z",
      "updatedAt": "2026-03-30T08:00:00.000Z"
    }
  ],
  "total": 3
}
```

***

## Create Frequency Cap

```http theme={null}
POST /api/v1/frequency-caps
```

### Request Body

| Field       | Type    | Required | Description                             |
| ----------- | ------- | -------- | --------------------------------------- |
| `name`      | string  | Yes      | Human-readable name                     |
| `scope`     | string  | Yes      | `"offer"`, `"category"`, or `"channel"` |
| `scopeId`   | string  | Yes      | ID of the scoped entity                 |
| `maxVolume` | integer | Yes      | Maximum count per period (minimum: 1)   |
| `period`    | string  | Yes      | `"daily"`, `"weekly"`, or `"monthly"`   |
| `enabled`   | boolean | No       | Default: `true`                         |

### Example

```json theme={null}
{
  "name": "Email Campaign Daily Cap 10K",
  "scope": "channel",
  "scopeId": "ch_email",
  "maxVolume": 10000,
  "period": "daily",
  "enabled": true
}
```

### Response `201`

Returns the created cap. The `currentCount` starts at `0` and `resetAt` is auto-computed based on the period.

```json theme={null}
{
  "id": "fc_001",
  "name": "Email Campaign Daily Cap 10K",
  "scope": "channel",
  "scopeId": "ch_email",
  "maxVolume": 10000,
  "period": "daily",
  "enabled": true,
  "currentCount": 0,
  "resetAt": "2026-03-31T00:00:00.000Z"
}
```

### Error codes

| Code  | Reason                                                               |
| ----- | -------------------------------------------------------------------- |
| `400` | Validation error or duplicate cap (same scope, scopeId, and period). |

***

## Update Frequency Cap

```http theme={null}
PUT /api/v1/frequency-caps
```

Update an existing cap. Include `id` in the body. Only provided fields are updated.

### Request Body

| Field       | Type    | Required | Description                                                          |
| ----------- | ------- | -------- | -------------------------------------------------------------------- |
| `id`        | string  | Yes      | Frequency cap ID                                                     |
| `name`      | string  | No       | Updated name                                                         |
| `scope`     | string  | No       | Updated scope                                                        |
| `scopeId`   | string  | No       | Updated scope ID                                                     |
| `maxVolume` | integer | No       | Updated max volume                                                   |
| `period`    | string  | No       | Updated period (resets `currentCount` to 0 and recomputes `resetAt`) |
| `enabled`   | boolean | No       | Enable or disable                                                    |

<Note>
  Changing the `period` automatically resets the `currentCount` to 0 and recomputes the `resetAt` timestamp.
</Note>

### Response `200`

Returns the updated cap.

### Error codes

| Code  | Reason                                                  |
| ----- | ------------------------------------------------------- |
| `400` | Validation error.                                       |
| `404` | Frequency cap not found (wrong ID or different tenant). |

***

## Delete Frequency Cap

```http theme={null}
DELETE /api/v1/frequency-caps?id={id}
```

### Query Parameters

| Parameter | Type   | Required | Description                |
| --------- | ------ | -------- | -------------------------- |
| `id`      | string | Yes      | Frequency cap ID to delete |

### Response `204`

Empty body on success.

### Error codes

| Code  | Reason                   |
| ----- | ------------------------ |
| `400` | Missing `id` parameter.  |
| `404` | Frequency cap not found. |

***

## How Frequency Caps Work

1. When a batch run executes, each delivery increments the `currentCount` for matching caps.
2. If `currentCount >= maxVolume`, further deliveries for that scope are blocked.
3. Counters reset automatically at the start of each period:
   * **daily**: Midnight UTC
   * **weekly**: Monday midnight UTC
   * **monthly**: First day of the month, midnight UTC
4. Frequency caps are checked AFTER qualification and contact policy filtering.

***

## Role requirements

| Method | Minimum role |
| ------ | ------------ |
| GET    | `viewer`     |
| POST   | `editor`     |
| PUT    | `editor`     |
| DELETE | `admin`      |

***

## Example: Insurance Email Campaign

```json theme={null}
// Max 10,000 emails per day (budget control)
{
  "name": "Email Daily Cap",
  "scope": "channel",
  "scopeId": "email-channel-id",
  "maxVolume": 10000,
  "period": "daily"
}

// Max 5,000 mandatory communications per week
{
  "name": "Mandatory Weekly Cap",
  "scope": "category",
  "scopeId": "mandatory-category-id",
  "maxVolume": 5000,
  "period": "weekly"
}

// Max 2,000 Early Renewal offers per month
{
  "name": "Early Renewal Monthly Cap",
  "scope": "offer",
  "scopeId": "early-renewal-offer-id",
  "maxVolume": 2000,
  "period": "monthly"
}
```
