This cookbook explains how to dismiss many data rule alerts in a single API call, with one shared reason.
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.
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 for the full alert lifecycle.
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 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.
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.
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
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
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.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.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.
Dismiss them in one call
Send all the IDs and a single reason to the bulk dismiss endpoint.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.
End-to-end example
This script lists a rule’s failing results, collects their IDs, and dismisses them in one request.
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.")
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();
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. |
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.