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

# Visitor suppression

> Stop spending credits and firing automations on traffic you do not want

Suppressed visitors are still identified. They consume no credits and trigger no webhooks or integrations.

Rules apply to your whole organization, across every pixel. There is no cap on how many rules you can store.

## Start with the industries endpoint

An `industry` rule matches the enriched company industry exactly, case-insensitive. A value that never appears in your data suppresses nothing, silently, and you keep paying for those visitors. `Ed Tech` does not match `Higher Education`.

Call the industries endpoint first and copy each `value` verbatim into your rules.

```bash theme={null}
GET /v1/data/suppression-rules/industries?limit=4
X-API-Key: YOUR_API_KEY
```

```json theme={null}
{
  "data": [
    { "value": "Information Technology & Services", "visitors": 22, "suppressed": false },
    { "value": "Venture Capital And Private Equity Principals", "visitors": 8, "suppressed": false },
    { "value": "Banking", "visitors": 4, "suppressed": false },
    { "value": "Business Consulting And Services", "visitors": 4, "suppressed": false }
  ],
  "meta": { "visitorsWithoutIndustry": 120, "suppressedIndustryRules": 1, "limit": 4 }
}
```

`visitors` is how many identified visitors carry that industry, so you can see what a rule would actually cost you. `suppressed` tells you a rule already exists.

`meta.visitorsWithoutIndustry` counts identified visitors with no company industry at all. No industry rule can reach them. Suppress those by domain or email instead.

The `email`, `domain`, and `company_domain` types do not have this problem. They are normalized on both sides, so an exact-match mistake is not possible in the same way.

## Rule types

| Type             | Matches                                      |
| ---------------- | -------------------------------------------- |
| `email`          | One person's email address                   |
| `domain`         | The email domain of the identified person    |
| `company_domain` | The website domain of the identified company |
| `industry`       | The enriched company industry, exactly       |

## Values are normalized before storage

Values are lowercased. Domains lose their scheme, `www.`, path, and port. Submitting `https://www.acme-partners.example/pricing` stores `acme-partners.example`, and that normalized value is what you get back when you read the list. This surprises people reconciling an upload against a source file.

Because normalization is deterministic, re-uploading the same list is a no-op. Retries are safe and no `Idempotency-Key` is needed.

## Append or replace

Use `POST` to add rules on top of what is already stored. This is the normal upload path.

Use `PUT` when a file is your source of truth. It deletes every existing rule and replaces it with what you submit, in one transaction, so re-posting the whole list on every sync run keeps the stored list matching the file exactly.

Pass `types` on `PUT` to scope the replace to certain rule types and leave the rest untouched — sync your `email` list without disturbing industry rules. Send an empty `rules` array together with `types` to clear a category.

Both endpoints accept up to 25,000 rules per call. A list longer than that cannot be replaced atomically, so build it up with `POST` instead.

## One bad row does not fail the batch

Rows that fail validation come back in `rejected`. Every other row is still applied, so a 5,000-row CSV does not fail on one bad cell.

```bash theme={null}
POST /v1/data/suppression-rules
X-API-Key: YOUR_API_KEY
```

```json theme={null}
{
  "rules": [
    { "type": "company_domain", "value": "https://www.acme-partners.example/pricing" },
    { "type": "domain", "value": "acme-partners.example" },
    { "type": "email", "value": "procurement@bigco.example" },
    { "type": "industry", "value": "Higher Education" },
    { "type": "domain", "value": "not a domain" }
  ]
}
```

```json theme={null}
{
  "data": {
    "added": 4,
    "removed": 0,
    "duplicates": 0,
    "rejectedCount": 1,
    "rejected": [
      { "index": 4, "type": "domain", "value": "not a domain", "reason": "Invalid domain" }
    ],
    "total": 4
  }
}
```

`index` is the position of the row in the array you submitted. `rejected` carries detail for the first 100 failures; `rejectedCount` is the true total. `duplicates` counts rows skipped because they were already stored or repeated inside the same request.

## Rules take effect going forward

Suppression is forward-only. A new rule applies from the next sync cycle onward, and visitors you were already charged for are not refunded. Removing a rule works the same way: it stops suppressing from the next cycle.

## Reading the list back

```bash theme={null}
GET /v1/data/suppression-rules?limit=3
X-API-Key: YOUR_API_KEY
```

```json theme={null}
{
  "data": {
    "rules": [
      { "id": "db7bac6c-...", "type": "industry", "value": "higher education", "createdAt": "2026-07-24T21:29:08.089Z" },
      { "id": "6d691a6b-...", "type": "domain", "value": "acme-partners.example", "createdAt": "2026-07-24T21:29:08.089Z" },
      { "id": "5a09ef03-...", "type": "company_domain", "value": "acme-partners.example", "createdAt": "2026-07-24T21:29:08.089Z" }
    ],
    "counts": { "email": 1, "domain": 1, "company_domain": 1, "industry": 1 },
    "total": 4,
    "filteredTotal": 4,
    "limit": 3,
    "offset": 0,
    "hasMore": true
  }
}
```

Rules come back newest first. `limit` defaults to `500` and caps at `5000`. `counts` and `total` always describe the whole list, not the page you requested, so use them to drive pagination rather than counting rows.

## Removing rules

Delete in bulk by rule id, by `type` and `value`, or both at once. Values are normalized the same way as on upload, so you can delete using the exact rows you uploaded without ever tracking ids. Unknown ids and values are ignored.

```bash theme={null}
DELETE /v1/data/suppression-rules
X-API-Key: YOUR_API_KEY
```

```json theme={null}
{ "rules": [{ "type": "domain", "value": "acme-partners.example" }] }
```

```json theme={null}
{ "data": { "deleted": 1, "total": 3 } }
```

Use `DELETE /v1/data/suppression-rules/{ruleId}` when you already hold the id of a single rule.

## Limits

| Limit                         | Value                                                                                     |
| ----------------------------- | ----------------------------------------------------------------------------------------- |
| Rate limit                    | `30` requests per minute per IP, lower than the `60` per minute on the rest of `/v1/data` |
| Rules per request             | `25,000`                                                                                  |
| Rules stored per organization | No cap                                                                                    |
| Credits consumed              | None. Suppression reduces credit usage                                                    |
