OpsGenie Provider¶
Opt-in feature flag
OpsGenie is not compiled into the default acteon-server build. Enable it with cargo build -p acteon-server --features opsgenie, or use --features extras-alerting to enable all opt-in messaging providers at once.
Acteon ships with a first-class OpsGenie provider that creates, acknowledges, and closes incidents through the OpsGenie Alert API v2. Operators use it for any workflow that maps to an Acteon Action — on-call alerting, deployment notifications, approval callbacks inside chains, scheduled reminders, and anything else that fits the create/acknowledge/close shape the Alert API exposes.
Like Acteon's other native providers, acteon-opsgenie:
- Supports both US (
api.opsgenie.com) and EU (api.eu.opsgenie.com) data residency regions. - Accepts
ENC[...]encrypted API keys in TOML configuration. - Propagates W3C Trace Context (
traceparent/tracestate) headers to downstream API calls. - Maps HTTP 429 → retryable
RateLimited; 401/403 → non-retryableConfiguration. - Uses the server's shared HTTP client, so it participates in circuit breaking, provider health checks, and per-provider metrics out of the box.
TOML configuration¶
OpsGenie is the first provider to use Acteon's nested provider config pattern: every OpsGenie-specific setting lives under an opsgenie.* key rather than a flat opsgenie_* prefix at the top level. This keeps the top-level [[providers]] schema tractable as more providers land.
[[providers]]
name = "opsgenie-prod"
type = "opsgenie"
opsgenie.api_key = "ENC[AES256_GCM,data:abc123...]"
opsgenie.region = "us" # or "eu"
opsgenie.default_team = "platform-oncall"
opsgenie.default_priority = "P3"
opsgenie.default_source = "acteon"
# opsgenie.scope_aliases = true # default — see "Multi-tenant isolation" below
# opsgenie.message_max_length = 130 # default — raise if OpsGenie lifts the cap
| Field | Required | Description |
|---|---|---|
name | Yes | Unique provider name used when dispatching actions |
type | Yes | Must be "opsgenie" |
opsgenie.api_key | Yes | Integration API key (the value that becomes Authorization: GenieKey {key}). Supports ENC[...] for encrypted storage. The plaintext is wrapped in a SecretString so it is zeroized on drop. |
opsgenie.region | No | "us" (default) or "eu". Accounts are pinned to one region at provisioning; picking the wrong one produces 401/403. |
opsgenie.default_team | No | Team responder used when a payload omits responders. |
opsgenie.default_priority | No | Default alert priority (P1..=P5). Falls back to P3. |
opsgenie.default_source | No | Default source label shown on the alert UI. |
opsgenie.scope_aliases | No | Whether to auto-prefix user-supplied aliases with {namespace}:{tenant}: for multi-tenant isolation. Defaults to true. See below. |
opsgenie.message_max_length | No | Client-side message truncation cap. Defaults to 130 (the current OpsGenie API limit). |
opsgenie.api_base_url | No | Override the API base URL. Tests only — do not set in production. |
Multi-tenant isolation¶
Alerts dispatched by Acteon come from (namespace, tenant) scopes, but OpsGenie has no native tenant concept. On a shared OpsGenie integration key (common in large orgs), that means two tenants that both pick the raw alias web-01-high-cpu would otherwise collide — and Tenant A could close Tenant B's alert simply by guessing the alias.
By default (opsgenie.scope_aliases = true, which is the default), the provider rewrites every alias to {namespace}:{tenant}:{raw_alias} before sending it to OpsGenie. The prefix is applied identically on create, acknowledge, and close so all three resolve to the same incident, but two tenants can never refer to each other's alerts.
Set opsgenie.scope_aliases = false only if:
- Every Acteon namespace/tenant has its own dedicated OpsGenie integration key, or
- You genuinely need cross-tenant alias coordination (e.g., a platform team closing a customer alert from a shared runbook).
Payload shape¶
Dispatch actions target the provider by name and carry an event_action in the payload that tells the provider which Alert API endpoint to hit:
event_action | Endpoint | Required fields |
|---|---|---|
"create" | POST /v2/alerts | message |
"acknowledge" | POST /v2/alerts/{alias}/acknowledge?identifierType=alias | alias |
"close" | POST /v2/alerts/{alias}/close?identifierType=alias | alias |
Create¶
{
"event_action": "create",
"message": "High error rate on checkout-api",
"alias": "checkout-api-5xx",
"description": "5xx rate crossed SLO threshold for 5 minutes.",
"priority": "P2",
"tags": ["checkout", "5xx", "slo-breach"],
"responders": [
{ "name": "checkout-oncall", "type": "team" }
],
"details": {
"runbook": "https://wiki.example.com/runbook/checkout-5xx",
"service": "checkout-api",
"env": "production"
},
"source": "prometheus"
}
| Field | Type | Notes |
|---|---|---|
message | string | Required. Short alert title. Truncated client-side to 130 characters (the API's max). |
alias | string | Client-side deduplication key. Later acknowledge/close events use the same alias to target the same incident. |
description | string | Long-form description shown in the alert detail view. |
priority | string | "P1".."P5". Falls back to opsgenie_default_priority. |
responders | array | List of responder objects ({name, type} or {id, type}). Falls back to a single-element list built from opsgenie_default_team when omitted. |
visible_to | array | Same shape as responders. Controls who can view the alert. |
actions | string[] | Pre-defined actions (e.g. ["ping", "reboot"]). |
tags | string[] | Free-form tags used for downstream routing. |
details | object | Arbitrary key-value metadata shown in the alert UI. |
entity | string | Domain entity the alert is about (e.g. "web-01"). |
source | string | Source label. Falls back to opsgenie_default_source. |
user | string | Username to attribute the creation to. |
note | string | Operator note attached to the alert. |
Acknowledge¶
{
"event_action": "acknowledge",
"alias": "checkout-api-5xx",
"user": "oncall-alice",
"note": "Investigating — rolled back deploy #4823"
}
Close¶
{
"event_action": "close",
"alias": "checkout-api-5xx",
"user": "oncall-alice",
"note": "Rollback confirmed; 5xx rate back below threshold."
}
Both acknowledge and close require alias because the provider always looks up alerts by alias (identifierType=alias), not by the numeric alert ID. This keeps the create/ack/close sequence stable across process restarts and across alert-correlation chains.
Rule integration¶
Because OpsGenie is just another named provider, every routing primitive Acteon already has works with it:
- Reroute high-priority alerts to OpsGenie:
- Dedup noisy alerts: use Acteon's deduplication with the alert's
aliasas the dedup key — OpsGenie then collapses the incident server-side through its own alias mechanism. - Silence maintenance-window alerts: silences apply before the provider dispatch, so an OpsGenie dispatch never leaves the gateway during an active silence.
- Quota-bound an OpsGenie account: add a per-provider tenant quota scoped to
provider: "opsgenie-prod"to cap burst traffic independent of tenant-wide quotas.
Outcome body¶
On success the provider returns an Executed outcome whose body carries the OpsGenie response:
The request_id is the handle you can use to poll the OpsGenie request-status endpoint if you need to confirm the eventual alert ID. Acteon treats the initial 202 Accepted as success (alert creation is asynchronous in OpsGenie's API).
Error mapping¶
| HTTP status | ProviderError | Retryable? |
|---|---|---|
| 2xx | Executed (success) | — |
| 401 / 403 | Configuration(...) | No |
| 429 | RateLimited | Yes |
| 4xx (other) | ExecutionFailed(...) | No |
| 5xx | ExecutionFailed(...) | No |
| Transport failure | Connection(...) | Yes |
Invalid payloads (missing message on create, missing alias on ack/close, unknown event_action) map to Serialization and are not retryable — retrying a malformed payload never succeeds.
Simulation example¶
A full end-to-end demo that walks through the create → acknowledge → close lifecycle plus rule-based P1 rerouting is in crates/simulation/examples/opsgenie_simulation.rs:
The simulation uses a recording provider, so it runs offline with no real OpsGenie credentials.