Skip to content

Alerts

Alert Lifecycle

Alga follows the Opsgenie deduplication model:

  1. Firing → Alert is active and needs attention
  2. Acknowledged → Someone is looking into it
  3. Resolved → Alert is no longer active

Key concepts:

  • Fingerprint is a dedup key, not a unique identifier. Multiple resolved alerts can share the same fingerprint.
  • Alert Number is the true unique identifier for each alert, assigned sequentially via the counters table.
  • Resolved alerts are never reopened automatically by the system, but they can be manually reopened via the API (POST /api/v1/alerts/{alert_number}/reopen) or the UI. Reopening resets the alert from resolved back to firing and can revive a terminal investigation (except promoted — a promoted investigation is irreversible). A new firing alert with the same fingerprint creates a fresh alert record.

Alert Fields

FieldDescription
alert_numberSequential unique identifier (from counters table)
fingerprintDedup key for correlating related alerts
statusfiring or resolved
acknowledgedWhether the alert has been acknowledged
silencedWhether the alert is silenced
labelsKey-value label map (e.g., alertname, severity, namespace)
annotationsKey-value annotation map (e.g., summary, description)
valuesMetric values associated with the alert
starts_atWhen the alert started firing
ends_atWhen the alert was resolved
generator_urlLink back to the source (e.g., Grafana)
triage_result_idLinked triage result (if triaged)
enrichmentEnriched metadata from triage or agents
triage_categoryCategory assigned by triage
severity_classifiedSeverity determined by triage
deleted_atSoft-delete tombstone timestamp (null if active)

Soft Delete

Alerts use a soft delete model: deleting an alert sets the deleted_at timestamp rather than removing the row. Soft-deleted alerts are excluded from normal queries but remain in the database for audit and retention purposes.

Partial Unique Index

A partial unique index enforces one open alert per fingerprint: only one alert with a given fingerprint may exist where status != resolved AND deleted_at IS NULL. This prevents duplicate firing alerts for the same source while allowing historical resolved records to accumulate.

Resolve Cascade

Resolving an incident automatically resolves all linked firing alerts associated with that incident.

Ingestion

Send alerts to Alga via webhook:

POST /webhooks/alerts
Authorization: Bearer YOUR_WEBHOOK_TOKEN
Content-Type: application/json

Payload Format

Alga accepts Grafana-compatible alert payloads:

json
{
  "alerts": [
    {
      "status": "firing",
      "labels": {
        "alertname": "HighCPU",
        "severity": "critical",
        "namespace": "production",
        "pod": "api-server-7d4f8b"
      },
      "annotations": {
        "summary": "CPU usage above 90%",
        "description": "Pod api-server-7d4f8b has been at 95% CPU for 5 minutes"
      },
      "startsAt": "2026-05-05T10:00:00Z",
      "generatorURL": "http://grafana:3000/alerting/list"
    }
  ],
  "commonLabels": {
    "alertname": "HighCPU"
  },
  "commonAnnotations": {},
  "externalURL": "http://grafana:3000",
  "receiver": "alga-webhook",
  "status": "firing",
  "groupKey": "{}/{}/{}:{alertname=\"HighCPU\"}"
}

Authentication

Include the webhook token as either:

  • Authorization: Bearer alga_... header
  • ?token=alga_... query parameter

Grafana Setup

  1. In Alga, go to Settings → Webhook Tokens and create a token
  2. In Grafana, navigate to Alerting → Contact points → Add contact point
  3. Set type to Webhook
  4. Set URL to: http://your-alga-host:8080/webhooks/alerts?token=alga_YOUR_TOKEN
  5. Optional: Set HTTP method to POST
  6. Save and test the contact point

Manual Alert Creation

Create alerts directly from the UI or API with extended fields:

json
POST /api/v1/alerts
{
  "summary": "Manual alert",
  "source": "manual",
  "labels": {
    "alertname": "DiskFull",
    "severity": "warning",
    "namespace": "staging"
  },
  "annotations": {
    "description": "Disk usage at 85% on staging-db-01"
  }
}

The source field defaults to grafana for webhook alerts. Manual alerts use manual or a custom source string. Labels and annotations follow the same format as Grafana payloads and are used by routing rules and correlation.

Alert Actions

ActionEndpointDescription
ListGET /api/v1/alertsList with filters (status, severity, channel, provider, search, date range)
GetGET /api/v1/alerts/{alert_number}Get alert and active investigation
CreatePOST /api/v1/alertsCreate a manual alert
AcknowledgePOST /api/v1/alerts/{alert_number}/acknowledgeMark as acknowledged
ResolvePOST /api/v1/alerts/{alert_number}/resolveManually resolve
ReopenPOST /api/v1/alerts/{alert_number}/reopenReopen resolved alert
InvestigatePOST /api/v1/alerts/{alert_number}/investigateTrigger AI investigation
DeleteDELETE /api/v1/alerts/{alert_number}Delete alert (alerts:delete)
RelatedGET /api/v1/alerts/{alert_number}/relatedGet correlated alerts and linked incident

Agent endpoints use fingerprint-based routing — see Agent REST API.

Alert Events

Each alert tracks a timeline of events (acknowledge, resolve, reopen, investigate, etc.). Each event records:

FieldDescription
typeEvent type (e.g., acknowledged, resolved, reopened, investigation_started)
timestampWhen the event occurred
actor_typeWho performed the action (user, agent, system)
actor_idIdentifier of the actor
sourceOrigin of the event (e.g., api, webhook, scheduler)

Full-text search across alert summaries, labels, and annotations:

GET /api/v1/alerts?search=HighCPU&status=firing&limit=20

The search query parameter matches against alert summaries, label values, and annotation values. Combine with filters for status, severity, channel, provider, and date ranges (start_date, end_date).

Alert Threads

Each alert has a dedicated owner-thread for operator discussion. Thread messages support real-time updates via SSE.

MethodEndpointDescription
GET/api/v1/alerts/{alert_number}/threadGet thread with messages
POST/api/v1/alerts/{alert_number}/thread/messagesAdd a message to the thread
POST/api/v1/alerts/{alert_number}/thread/typingTyping indicator

New messages are pushed to connected clients over the SSE stream (GET /api/v1/events), so the thread UI updates in real time without polling.

View correlated alerts that were grouped into the same investigation:

GET /api/v1/alerts/{alert_number}/related

Returns related alerts sharing the same correlation key and the linked incident (if any). Useful for understanding blast radius during an active incident.

Alert Correlation

When CORRELATION_WINDOW is set (e.g., 5m), alerts that share the same correlation key (deployment name + alertname) within the window are grouped into a single investigation.

The correlator:

  1. Buffers incoming alerts by correlation key
  2. Waits for the window to expire
  3. Creates a single investigation covering all correlated alerts
  4. Honors CORRELATION_COOLDOWN_TTL (default 30m) to prevent duplicate investigations on the same key
VariableDefaultDescription
CORRELATION_WINDOW0 (disabled)Time window for grouping related alerts
CORRELATION_COOLDOWN_TTL30mCooldown before a new investigation opens on the same correlation key

Delivery Targets

Alerts track where they were delivered — Mattermost post IDs, Slack message timestamps, and other delivery references. This enables bidirectional sync: replies in Mattermost or Slack threads are reflected back into Alga, and Alga updates are pushed to the original channel post.

Each delivery target stores:

FieldDescription
providerDelivery provider (e.g., mattermost, slack)
channelChannel or conversation ID
post_idExternal post/message ID in the provider

Maintenance Window Suppression

Alerts that fire during an active maintenance window are suppressed. The alert is still stored in the database with its full labels and annotations, but no routing, notification, or investigation is triggered. When the maintenance window expires, subsequent alerts on the same fingerprint resume normal processing.

Configure maintenance windows under Routes → Maintenance Windows or via the API:

MethodEndpointDescription
GET/api/v1/maintenance-windowsList maintenance windows
POST/api/v1/maintenance-windowsCreate maintenance window
PUT/api/v1/maintenance-windows/{id}Update maintenance window
DELETE/api/v1/maintenance-windows/{id}Delete maintenance window

Each window has a start time, end time, and optional label selectors to scope suppression to specific alerts.

Stale Alert Sweep

A background sweeper detects firing alerts that have not been investigated within a configurable threshold and marks them as stale candidates for re-investigation.

VariableDefaultDescription
STALE_ALERT_THRESHOLD15mAlert age before the stale sweep considers it uninvestigated
STALE_ALERT_SWEEP_INTERVAL5mHow often the stale sweep runs

Data Retention

Resolved alerts are automatically pruned based on DATA_RETENTION_DAYS (default: 90 days). Set to 0 to keep alerts forever.

Manual Pruning

sh
# Dry run: count alerts that would be deleted
./alga data prune --dry-run

# Prune with custom retention
./alga data prune --days 30

# Prune using configured retention
./alga data prune

The retention scheduler runs hourly when DATA_RETENTION_DAYS > 0.

Released under the MIT License.