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

# Dismissing many rule alerts at once

> Find and dismiss data rule alerts in bulk using the Mangrove API.

This cookbook explains how to dismiss many data rule alerts in a single API call, with one shared reason.

<Card title="Example Scenario">
  A data rule has flagged dozens of records — for example, a "Negative Temp Alert" firing on a winter's worth of ambient-temperature readings. After reviewing them with your site engineer, you've confirmed they're expected and want to dismiss them all at once with a single reason, while preserving the audit trail.
</Card>

<Note>
  Dismissing an alert only changes how it is surfaced — it never edits the underlying datapoint or model run. If the record is recalculated and the rule still matches, a fresh alert can be raised. See [Managing alerts](/data-rules/manage-alerts) for the full alert lifecycle.
</Note>

## How it works

Every rule alert is backed by a **rule result** with its own friendly ID:

| Result type            | ID prefix | Raised by                |
| ---------------------- | --------- | ------------------------ |
| Data point rule result | `dpres_`  | Event Data rules         |
| Model run rule result  | `mrres_`  | Batch Calculations rules |

The [Bulk dismiss rule results](/api-reference/data-rules/bulk-dismiss) endpoint takes a list of these IDs plus one `reason`, and dismisses them in a single transaction. You can mix `dpres_` and `mrres_` IDs in the same request.

<Warning>
  Pass **rule-result** IDs (`dpres_...`, `mrres_...`) — not data point (`in_...`), event (`evt_...`), or model run (`mr_...`) IDs. The rule-result ID is the `id` on each entry in a record's `rule_results` array.
</Warning>

The call is **all-or-nothing**: if the reason is blank, the list is empty, or any ID is unknown to the project or points at a *passing* result, nothing is dismissed and the API returns `422`. Already-dismissed results are a no-op, so retrying a request is safe.

## Dismissing alerts with code

<Steps>
  <Step title="Prerequisites">
    Before starting, make sure you have:

    * A Mangrove API token with Data Rules access for the project
    * The rules engine feature enabled on your account (the endpoint returns `403` otherwise)
    * The project ID containing the alerts
  </Step>

  <Step title="Collect the rule-result IDs to dismiss">
    List the results for the rule you want to triage and filter to the alerts (`status=fail`), then read the `id` of each failing result.

    ```bash curl theme={null}
    curl "https://app.gomangrove.com/api/v1/projects/prj_W55PYc6xVeXb2iuT/rules/rule_Qb3k9TzdL0pWnXyz/results?status=fail&page_size=100" \
      -H "Authorization: YOUR_API_TOKEN"
    ```

    Each entry's `id` (e.g. `dpres_8XF1QtGs79oX9A6k`) is what you collect.

    <Warning>
      Re-list right before dismissing. Recreating or re-saving a rule regenerates its rule-result friendly IDs, so IDs cached from an earlier session can become "Unknown result ids" (`422`). Always work from a fresh list.
    </Warning>
  </Step>

  <Step title="Dismiss them in one call">
    Send all the IDs and a single reason to the bulk dismiss endpoint.

    ```bash curl theme={null}
    curl -X POST "https://app.gomangrove.com/api/v1/projects/prj_W55PYc6xVeXb2iuT/rule_results/bulk_dismiss" \
      -H "Authorization: YOUR_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "result_ids": [
          "dpres_8XF1QtGs79oX9A6k",
          "dpres_7nxaDUf65c36v6mz",
          "mrres_AIKqFEtr5OpAqram"
        ],
        "reason": "Reviewed with site engineer — sensor recalibrated, readings are expected."
      }'
    ```

    The response returns every targeted result with its final state, so dismissed entries come back with `status: dismissed` and the `dismissal_reason`, `dismissed_by`, and `dismissed_at` fields populated.
  </Step>
</Steps>

## End-to-end example

This script lists a rule's failing results, collects their IDs, and dismisses them in one request.

<CodeGroup>
  ```python Python theme={null}
  import requests

  API_TOKEN = "YOUR_API_TOKEN"
  BASE_URL = "https://app.gomangrove.com/api/v1"
  PROJECT_ID = "prj_W55PYc6xVeXb2iuT"
  RULE_ID = "rule_Qb3k9TzdL0pWnXyz"
  REASON = "Reviewed with site engineer — sensor recalibrated, readings are expected."

  headers = {
      "Authorization": API_TOKEN,
      "Content-Type": "application/json",
  }

  # 1. Collect the failing rule-result IDs (re-list right before dismissing).
  result_ids = []
  page = 1
  while True:
      resp = requests.get(
          f"{BASE_URL}/projects/{PROJECT_ID}/rules/{RULE_ID}/results",
          headers=headers,
          params={"status": "fail", "page": page, "page_size": 100},
      )
      resp.raise_for_status()
      body = resp.json()
      result_ids += [r["id"] for r in body["data"]]
      if page >= body["info"]["total_pages"]:
          break
      page += 1

  if not result_ids:
      print("No alerts to dismiss.")
  else:
      # 2. Dismiss them all in one call.
      resp = requests.post(
          f"{BASE_URL}/projects/{PROJECT_ID}/rule_results/bulk_dismiss",
          headers=headers,
          json={"result_ids": result_ids, "reason": REASON},
      )
      resp.raise_for_status()
      dismissed = resp.json()["data"]
      print(f"Dismissed {len(dismissed)} results.")
  ```

  ```javascript Node.js theme={null}
  const API_TOKEN = 'YOUR_API_TOKEN';
  const BASE_URL = 'https://app.gomangrove.com/api/v1';
  const PROJECT_ID = 'prj_W55PYc6xVeXb2iuT';
  const RULE_ID = 'rule_Qb3k9TzdL0pWnXyz';
  const REASON = 'Reviewed with site engineer — sensor recalibrated, readings are expected.';

  const headers = {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  };

  async function dismissAlerts() {
    // 1. Collect the failing rule-result IDs (re-list right before dismissing).
    const resultIds = [];
    let page = 1;
    while (true) {
      const params = new URLSearchParams({ status: 'fail', page, page_size: '100' });
      const res = await fetch(
        `${BASE_URL}/projects/${PROJECT_ID}/rules/${RULE_ID}/results?${params}`,
        { headers }
      );
      if (!res.ok) throw new Error(`List failed: ${res.status}`);
      const body = await res.json();
      resultIds.push(...body.data.map((r) => r.id));
      if (page >= body.info.total_pages) break;
      page += 1;
    }

    if (resultIds.length === 0) {
      console.log('No alerts to dismiss.');
      return;
    }

    // 2. Dismiss them all in one call.
    const res = await fetch(
      `${BASE_URL}/projects/${PROJECT_ID}/rule_results/bulk_dismiss`,
      {
        method: 'POST',
        headers,
        body: JSON.stringify({ result_ids: resultIds, reason: REASON }),
      }
    );
    if (!res.ok) throw new Error(`Dismiss failed: ${res.status} ${await res.text()}`);
    const { data } = await res.json();
    console.log(`Dismissed ${data.length} results.`);
  }

  dismissAlerts();
  ```
</CodeGroup>

## Troubleshooting

| Response                                  | Meaning                                                                                   | What to do                                                                              |
| ----------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `403 Rules engine feature is not enabled` | The rules engine feature is off for the account.                                          | Contact your Mangrove account team to enable it.                                        |
| `404 record not found`                    | The project ID is wrong, or the route isn't reachable for this token.                     | Double-check the `project_id` in the path and that the token is scoped to that project. |
| `422 Unknown result ids: ...`             | One or more IDs don't belong to the project — often stale IDs after a rule was recreated. | Re-list the rule's results and rebuild the ID set from the fresh response.              |
| `422 Cannot dismiss passing results: ...` | The batch includes a result whose status is `pass`.                                       | Filter to `status=fail` (or `dismissed`) before collecting IDs.                         |
| `422 Dismissal reason can't be blank`     | The `reason` was empty or whitespace.                                                     | Provide a non-empty reason — it's stored on the audit trail.                            |

<Tip>
  The split between `404` and `422` is diagnostic: a `404` points at the path or record lookup (wrong `project_id`, route not reachable), while a `422` is business validation (blank reason, empty list, unknown or passing IDs). If a previously working call starts returning `404`, suspect a routing or scoping issue rather than your payload.
</Tip>
