Create Metric Alert Rule
Creates a threshold rule the evaluator worker will check on each cycle. A rule combines a metric, an operator, a numeric threshold, and a sliding window. When the observed value crosses the threshold the rule transitions to firing and the worker sends one notification per configured channel — subject to cooldown_seconds to suppress repeats.
Endpoint scope is optional: omit endpoint_uuid to evaluate across every endpoint owned by the caller; supply one to scope the metric to a single endpoint.
Plan-gated: requires the metric_alerts entitlement (403 without it).
Request body
name string Req
Free-form label. Max 255 chars.
description string
Optional. Free-form context (e.g. who gets paged, what to do).
metric string Req
One of:
request_rate (req/s), error_rate_pct (% of 4xx+5xx), p95_latency_ms, p99_latency_ms, bandwidth_in_bps, bandwidth_out_bps.operator string Req
Comparison against the threshold. One of:
>, >=, <, <=.threshold number Req
Threshold value in the metric's native unit (req/s, percent, ms, bytes/s).
window_seconds int Req
Aggregation window. Must be between 60 and 86400 (1 minute to 24 hours).
endpoint_uuid string (uuid)
Optional. Scope the metric to a single endpoint. Omit for account-wide.
cooldown_seconds int
Minimum gap between consecutive notifications while the rule stays firing. 0–86400.
enabled boolean
Defaults to
true. Disabled rules are persisted but skipped by the evaluator.notify_channels array<Channel> Req
At least one channel. Each channel has
type + target (and optional secret). Supported types: email (target must contain @); webhook (target must be an https:// URL; may include a secret the worker uses to HMAC-SHA256-sign the POST body as X-Ngris-Signature); slack (target is a Slack Incoming Webhook https://hooks.slack.com/... URL); discord (target is a Discord webhook https://discord.com/api/webhooks/... URL). Slack/Discord carry no secret — the URL itself is the credential.Response (201 Created)
The newly-created rule with assigned uuid and resolved endpoint_id. status starts at unknown until the first evaluator cycle.
Errors
400 Bad Request
Validation failure: missing name/metric/operator, out-of-range window or cooldown, unknown metric, no notification channels, or an invalid channel target.
400 endpoint not found
The supplied
endpoint_uuid doesn't match an endpoint in the caller's tenant. Returned as a 400 field-error keyed to endpoint_uuid, not a 404.401 Unauthorized
Missing auth.
403 Forbidden
Plan doesn't include
metric_alerts.Request — error-rate alert
curl -X POST "https://api.ngris.com/v1/traffic/alerts" \
-H "X-API-KEY: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"name": "5xx spike on api",
"description": "Page on-call when api endpoint errors exceed 1%",
"metric": "error_rate_pct",
"operator": ">",
"threshold": 1.0,
"window_seconds": 300,
"endpoint_uuid": "<endpoint_uuid>",
"cooldown_seconds": 600,
"notify_channels": [
{"type": "email", "target": "ops@acme.dev"},
{"type": "webhook", "target": "https://hooks.acme.dev/ngris", "secret": "<hmac_secret>"}
]
}'
Request — account-wide p99 latency
curl -X POST "https://api.ngris.com/v1/traffic/alerts" \
-H "X-API-KEY: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"name": "p99 latency over 500ms",
"metric": "p99_latency_ms",
"operator": ">",
"threshold": 500,
"window_seconds": 300,
"cooldown_seconds": 900,
"notify_channels": [{"type": "email", "target": "sre@acme.dev"}]
}'
Response — 201 Created
{
"uuid": "0d3e9f8a-2b5c-4a7d-9f1a-1a2b3c4d5e6f",
"name": "5xx spike on api",
"metric": "error_rate_pct",
"operator": ">",
"threshold": 1.0,
"window_seconds": 300,
"endpoint_id": 99,
"cooldown_seconds": 600,
"enabled": true,
"status": "unknown",
"notify_channels": [
{"type": "email", "target": "ops@acme.dev"},
{"type": "webhook", "target": "https://hooks.acme.dev/ngris"}
],
"created_at": "2026-05-21T12:00:00Z",
"updated_at": "2026-05-21T12:00:00Z"
}