# Exclusions API

> List, create, update and delete the exclusion rules that stop matching traffic, such as health checks, from being captured by ApiTraffic.

Source: https://www.apitraffic.io/docs/api-reference/exclusions

An exclusion rule tells your SDK not to capture requests that match its criteria, for example load-balancer health checks or internal traffic. Excluded requests are never sent to ApiTraffic, so they are not stored and do not count toward usage. Rules apply to the buckets and environments you choose. See [Exclusions](https://www.apitraffic.io/docs/data/exclusions) for doing this in the app.

**Permissions:** any member can list and read rules. Creating, changing and deleting a rule needs an owner or admin, or an `administrator` API token. **Limit:** the number of rules an account can create depends on its plan.

Connected SDKs receive rule changes without a restart.

## The exclusion object

- **sid (string, required)**:
  The rule's identifier (`xcl_` followed by 27 letters and digits).

- **accountSid (string, required)**:
  The account.

- **description (string | null)**:
  A short description.

- **criteria (string | null, required)**:
  Which requests the rule applies to, in the [search syntax](https://www.apitraffic.io/docs/traffic/search), for example `url_path == "/health"`. Empty on a body omission rule that applies to all traffic in its buckets and environments.

- **action (string)**:
  What a match does (see [Rule actions](#rule-actions)): `exclude` (the default) or `omit_request_body`, `omit_response_body`, `omit_bodies`.

- **buckets (string[])**:
  The buckets the rule applies to, or `["*"]` for all.

- **environments (string[])**:
  The environments the rule applies to, or `["*"]` for all.

- **enabled (boolean)**:
  Whether the rule is active. Default `true`.

- **warnings (object[])**:
  Present only when there is something to say. Each has a `code`, the `path` it is about (`criteria`) and a `message`. `criteria-rule-sent-disabled`: the rule is enabled, but it is sent to your servers turned off, so it leaves nothing out, because its criteria were saved before the API refused criteria SDKs read differently from what was written (see [Criteria SDKs read differently](#criteria-sdks-read-differently)). Change the criteria to turn it back on.

- **createdAt (string)**:
  When the rule was created (ISO 8601).

- **updatedAt (string | null)**:
  When it was last changed.

## List exclusions

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/exclusions`

Returns every exclusion rule in the account.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Response

- **hasMore (boolean, required)**:
  Always `false`: every rule is returned in one response.

- **records (object[], required)**:
  The rules, as [exclusion objects](#the-exclusion-object).

```bash cURL
curl https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/exclusions \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/exclusions`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { records } = await response.json();
```

```json 200
{
  "hasMore": false,
  "records": [
    {
      "sid": "xcl_2zX4cV6bN8mA1sD3fG5hJ7kL9qP",
      "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
      "description": "Load balancer health checks",
      "criteria": "url_path == \"/health\"",
      "buckets": ["*"],
      "environments": ["*"],
      "enabled": true,
      "createdAt": "2026-03-02T16:05:00.000Z",
      "updatedAt": null
    }
  ]
}
```

## Get exclusion

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/exclusions/{exclusionSid}`

Returns one exclusion rule.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **exclusionSid (path, string, required)**:
  The rule's identifier (`xcl_…`).

### Response

An [exclusion object](#the-exclusion-object).

```bash cURL
curl https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/exclusions/xcl_2zX4cV6bN8mA1sD3fG5hJ7kL9qP \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const exclusionSid = 'xcl_2zX4cV6bN8mA1sD3fG5hJ7kL9qP';
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/exclusions/${exclusionSid}`,
  { headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` } },
);
const rule = await response.json();
```

```json 200
{
  "sid": "xcl_2zX4cV6bN8mA1sD3fG5hJ7kL9qP",
  "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
  "description": "Load balancer health checks",
  "criteria": "url_path == \"/health\"",
  "buckets": ["*"],
  "environments": ["*"],
  "enabled": true,
  "createdAt": "2026-03-02T16:05:00.000Z",
  "updatedAt": null
}
```

## Create exclusion

`POST https://api.apitraffic.io/v1/accounts/{accountSid}/exclusions`

Creates an exclusion rule.

**Permissions:** owner or admin, or an `administrator` API token. **Limit:** past the plan's exclusion rule limit, the API answers `409` with code `2213`.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Body parameters

- **criteria (body, string)**:
  Which requests the rule applies to. Required when `action` is `exclude`; a body omission rule may leave it empty to apply to all traffic in its buckets and environments.

- **action (body, string)**:
  `exclude` (the default), `omit_request_body`, `omit_response_body` or `omit_bodies`. See [Rule actions](#rule-actions).

- **description (body, string | null)**:
  A short description.

- **buckets (body, string[])**:
  Bucket sids, or `["*"]` for every bucket.

- **environments (body, string[])**:
  Environment sids, or `["*"]` for every environment.

- **enabled (body, boolean, default true)**:
  Whether the rule is active.

### Response

The new [exclusion object](#the-exclusion-object).

```bash cURL
curl -X POST https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/exclusions \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "CORS preflight requests",
    "criteria": "method == \"OPTIONS\"",
    "buckets": ["k3m9p2x"],
    "environments": ["*"],
    "enabled": true
  }'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/exclusions`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    description: 'CORS preflight requests',
    criteria: 'method == "OPTIONS"',
    buckets: ['k3m9p2x'],
    environments: ['*'],
    enabled: true,
  }),
});
const rule = await response.json();
```

```json 200
{
  "sid": "xcl_2mN4bV6cX8zL1kJ3hG5fD7sA9qE",
  "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
  "description": "CORS preflight requests",
  "criteria": "method == \"OPTIONS\"",
  "buckets": ["k3m9p2x"],
  "environments": ["*"],
  "enabled": true,
  "createdAt": "2026-10-20T09:40:00.000Z",
  "updatedAt": null
}
```

## Update exclusion

`PUT https://api.apitraffic.io/v1/accounts/{accountSid}/exclusions/{exclusionSid}`

Replaces an exclusion rule. Send the whole rule, with the same fields as [Create exclusion](#create-exclusion). To pause a rule, send it with `enabled: false`.

**Permissions:** owner or admin, or an `administrator` API token.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **exclusionSid (path, string, required)**:
  The rule's identifier.

### Body parameters

The same as [Create exclusion](#create-exclusion): `criteria` is sent (it may be empty only for a body omission rule); `action`, `description`, `buckets`, `environments` and `enabled` are optional, and a left-out `action` keeps the rule's current one. `criteria` is checked as on create, even when it is unchanged, so a rule saved before a check existed (with ` OR `, criteria the SDK can't parse, more than 4,096 characters, more than 256 spaces in a row, or criteria SDKs read differently) can't be updated, paused included, until its criteria pass: replace ` OR ` with ` AND ` to keep what such a rule does (it has always run as AND), or [delete the rule](#delete-exclusion).

### Response

The updated [exclusion object](#the-exclusion-object).

```bash cURL
curl -X PUT https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/exclusions/xcl_2zX4cV6bN8mA1sD3fG5hJ7kL9qP \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Health and readiness checks",
    "criteria": "url_path like \"^/(health|ready)$\"",
    "buckets": ["*"],
    "environments": ["*"],
    "enabled": true
  }'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const exclusionSid = 'xcl_2zX4cV6bN8mA1sD3fG5hJ7kL9qP';
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/exclusions/${exclusionSid}`,
  {
    method: 'PUT',
    headers: {
      Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      description: 'Health and readiness checks',
      criteria: 'url_path like "^/(health|ready)$"',
      buckets: ['*'],
      environments: ['*'],
      enabled: true,
    }),
  },
);
const rule = await response.json();
```

```json 200
{
  "sid": "xcl_2zX4cV6bN8mA1sD3fG5hJ7kL9qP",
  "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
  "description": "Health and readiness checks",
  "criteria": "url_path like \"^/(health|ready)$\"",
  "buckets": ["*"],
  "environments": ["*"],
  "enabled": true,
  "createdAt": "2026-03-02T16:05:00.000Z",
  "updatedAt": "2026-10-20T09:45:00.000Z"
}
```

## Delete exclusion

`DELETE https://api.apitraffic.io/v1/accounts/{accountSid}/exclusions/{exclusionSid}`

Deletes an exclusion rule. Matching requests are captured again from then on.

**Permissions:** owner or admin, or an `administrator` API token.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **exclusionSid (path, string, required)**:
  The rule's identifier.

### Response

- **sid (string, required)**:
  The deleted rule's identifier.

- **deleted (boolean, required)**:
  `true`.

```bash cURL
curl -X DELETE https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/exclusions/xcl_2mN4bV6cX8zL1kJ3hG5fD7sA9qE \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const exclusionSid = 'xcl_2mN4bV6cX8zL1kJ3hG5fD7sA9qE';
await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/exclusions/${exclusionSid}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
```

```json 200
{
  "sid": "xcl_2mN4bV6cX8zL1kJ3hG5fD7sA9qE",
  "deleted": true
}
```

## Rule actions

| `action` | Effect |
|---|---|
| `exclude` (default) | The request is not sent to ApiTraffic at all. |
| `omit_request_body` | The request is logged without its request body. |
| `omit_response_body` | The request is logged without its response body. |
| `omit_bodies` | The request is logged without either body. |

A body left out by a rule is never stored, but its size is still recorded, so `request_size` and `response_size` stay accurate. The request's `omittedBodies` field (`{ "request": "xcl_…", "response": null }`) names the rule, and the request view says the body was not logged.

Body omission rules are enforced by your SDK and again by ApiTraffic before anything is stored, so their criteria are limited to what both read the same way: besides the checks below, no `endpoint` conditions, no `>` `<` `>=` `<=` on a header, query parameter or tag, and no `like` pattern with a lookaround or backreference. Other criteria are refused with a `400`.

## Regular expressions in criteria

An exclusion's `criteria` is a query such as `url_path like "^/health" AND method == "GET"`. The value of each `like` condition is a regular expression: one leading `*` is removed, and the rest is compiled as `new RegExp(value)` (no flags, so it is case-sensitive) and tested against the request field inside your application.

Because that runs on every captured request in your servers, each `like` pattern is checked when the exclusion is created or updated. The request is refused with `400` (code `1000`) if a pattern does not compile, is longer than **512 characters**, or can backtrack catastrophically (for example `(a+)+$`, `(\w+\s?)+` or an unanchored `.*\.png$`). SDK releases before the criteria parser update read `\"` and `\\` in a quoted value literally (a backslash, and the quote dropped), so a pattern is checked as they read it too; the message then says so. The message names the condition and the fix:

```json
{
  "message": "criteria: condition \"url_path like (a+)+$\": Pattern nests one repetition inside another, which can take exponential time. Remove the inner or outer quantifier, or start each repeated group with a character the group cannot otherwise match (for example \"(?:\\.[a-z]+)*\").",
  "code": 1000,
  "moreInformation": "https://apitraffic.io/api/errors/1000",
  "data": {}
}
```

The SDK also bounds what it runs: each pattern is compiled once, an invalid pattern never matches (it never throws), and only the first **2,048 characters** of a value are tested. A match that lies entirely beyond that is not seen, and a `$` anchor applies to the end of those 2,048 characters for longer values.

## Criteria SDKs read differently

Exclusions run in your servers, on whatever SDK release each one runs, so criteria that SDKs read differently from the [search syntax](https://www.apitraffic.io/docs/traffic/search) are refused with `400` (code `1000`):

- **A leading `-` or `!` on a condition.** SDK releases before the current one ignore it, so `-method == "OPTIONS"` would leave out the `OPTIONS` requests instead of everything else. Write the opposite condition: `method != "OPTIONS"`.
- **`>`, `>=`, `<` or `<=` on a value the SDK holds as text:** `request_header`, `response_header`, `query_param`, `tag`, `request_size` and `response_size` (read from the `Content-Length` header), `waf_score`, and text fields such as `url_path` or `method`. SDK releases before the current one compare those as text (`"999"` is greater than `"1000"`); the current release compares headers, query parameters, tags and `waf_score` as numbers, but the rule is the same for every SDK version. Ordered comparisons on `status_code`, `duration`, the APM rollups and the server fields (`concurrency`, `event_loop_delay_ms`) compare numbers and are accepted.
- **Any condition on `received`,** whatever the operator. SDK releases before the current one never read the time a request was received, so a condition on it never matches there (the rule leaves nothing out), and `received != …` matches every request (the rule leaves out everything). To exclude requests for a period, enable the rule at its start and disable it at its end ([Update exclusion](#update-exclusion)).
- **Any condition on `capture`.** It marks [captures](https://www.apitraffic.io/docs/traffic/request-log#captures), requests sent to the bucket's capture URL, which never pass through an SDK, so every request an exclusion sees is `capture == false`. SDK releases before the current one read no value for it: `capture == false` never matches there, and `capture != false` matches every request. The current release does not accept it.

```json
{
  "message": "criteria: criteria \"-method == OPTIONS\": \"-method == OPTIONS\": SDKs before the current release ignore a leading - or ! and would leave out the requests that match what follows instead; write the opposite condition without it (method != GET, not -method == GET).",
  "code": 1000,
  "moreInformation": "https://apitraffic.io/api/errors/1000",
  "data": {}
}
```

A rule saved with such criteria before the API refused them is sent to your servers turned off (it leaves nothing out), and carries a `criteria-rule-sent-disabled` [warning](#the-exclusion-object). It can be deleted, or updated once its criteria pass.

## Common exclusion criteria

| To leave out | `criteria` |
| --- | --- |
| Health checks | `url_path == "/health"` |
| Health and readiness checks | `url_path like "^/(health\|ready)$"` |
| CORS preflight requests | `method == "OPTIONS"` |
| Static assets | `url_path like "^/static/"` |
| Calls your API makes to one internal service | `direction == "out" AND host == "inventory.acme-internal.example"` |
| A monitoring agent | `request_header:user-agent like "^acme-lb-healthcheck/"` |

## Errors

| Status | Code | Meaning |
| --- | --- | --- |
| `400` | `1000` | A field is missing or invalid, including a `criteria` that cannot be parsed or a `like` pattern that fails the checks above. |
| `403` | `2010` | Creating, changing or deleting a rule without owner, admin or `administrator` access. |
| `404` | `4000` | No rule with that `exclusionSid` in this account. |
| `409` | `2213` | The plan's exclusion rule limit is reached. |

## Related

- [Exclusions](https://www.apitraffic.io/docs/data/exclusions):
    Create and test exclusion rules in the app.

- [Search and filter requests](https://www.apitraffic.io/docs/traffic/search):
    Every field and operator you can use in `criteria`.
