Skip to main content

Alerts API

Create alert rules to get notified when traffic anomalies occur.

Overview

The Alerts API allows you to:

  • Create rules for traffic anomaly detection
  • Configure notification channels (email, webhook)
  • View alert history and statistics
  • Acknowledge and manage triggered alerts

Base path: /alerts


Alert Rules

List Alert Rules

GET /alerts/rules?site_id={site_id}

Query Parameters:

ParameterTypeDescription
site_idstringRequired. Site ID
include_inactivebooleanInclude disabled rules

Response:

{
"rules": [
{
"id": 1,
"site_id": "acme",
"name": "Traffic Drop Alert",
"description": "Alert when traffic drops significantly",
"metric": "entrances",
"condition": "decrease",
"threshold_percent": 25,
"comparison_period": "previous_week",
"notification_channels": ["email", "webhook"],
"is_active": true,
"last_triggered_at": "2025-01-05T10:30:00Z",
"created_at": "2024-12-01T10:00:00Z"
}
],
"total": 1
}

Create Alert Rule

POST /alerts/rules?site_id={site_id}

Request Body:

{
"name": "Revenue Drop",
"description": "Alert when revenue drops more than 30%",
"metric": "revenue",
"condition": "decrease",
"threshold_percent": 30,
"comparison_period": "previous_week",
"filters": {
"utm_medium": "cpc"
},
"notification_channels": ["email"],
"email_recipients": ["alerts@company.com"],
"webhook_endpoint_id": "550e8400-e29b-41d4-a716-446655440000"
}
FieldTypeRequiredDescription
namestringYesRule name (1-255 chars)
descriptionstringNoRule description
metricenumYesMetric to monitor
conditionenumYesincrease or decrease
threshold_percentnumberYesThreshold percentage (1-100)
comparison_periodenumYesComparison period
filtersobjectNoFilter conditions
notification_channelsstring[]Yesemail, webhook, or both
email_recipientsstring[]NoEmail addresses for notifications
webhook_endpoint_iduuidNoWebhook endpoint to notify

Available Metrics

MetricDescription
entrancesSession starts
page_viewsTotal pageviews
conversionsConversion count
revenueTotal revenue
bounce_rateBounce rate percentage
engaged_entrancesEngaged sessions

Comparison Periods

PeriodDescription
previous_daySame time yesterday
previous_weekSame day last week
previous_monthSame day last month
previous_yearSame day last year

Response (201 Created):

{
"id": 2,
"site_id": "acme",
"name": "Revenue Drop",
"metric": "revenue",
"condition": "decrease",
"threshold_percent": 30,
"comparison_period": "previous_week",
"is_active": true,
"created_at": "2025-01-10T14:30:00Z"
}

Get Alert Rule

GET /alerts/rules/{rule_id}?site_id={site_id}

Update Alert Rule

PATCH /alerts/rules/{rule_id}?site_id={site_id}

Request Body:

{
"name": "Updated Name",
"threshold_percent": 40,
"is_active": false
}

All fields are optional. Only provided fields are updated.


Delete Alert Rule

DELETE /alerts/rules/{rule_id}?site_id={site_id}

Test Alert

Test Alert Rule

POST /alerts/rules/{rule_id}/test?site_id={site_id}

Test a rule without triggering actual notifications.

Request Body (optional):

{
"send_notification": true
}

Set send_notification: true to send a real test notification.

Response:

{
"would_trigger": true,
"current_value": 650,
"comparison_value": 1000,
"change_percent": -35.0,
"threshold_percent": 25,
"message": "Rule would trigger: entrances decreased 35% vs previous week",
"notification_sent": false
}

Alert History

Get Alert History

GET /alerts/history?site_id={site_id}

Query Parameters:

ParameterTypeDescription
site_idstringRequired. Site ID
rule_idintFilter by specific rule
statusstringFilter by status
limitintMax results (default: 50)
offsetintPagination offset

Alert Statuses

StatusDescription
triggeredAlert fired, awaiting acknowledgment
acknowledgedUser acknowledged the alert
resolvedAlert condition no longer active
dismissedUser dismissed without action

Response:

{
"alerts": [
{
"id": 123,
"rule_id": 1,
"rule_name": "Traffic Drop Alert",
"status": "triggered",
"metric": "entrances",
"current_value": 650,
"comparison_value": 1000,
"change_percent": -35.0,
"threshold_percent": 25,
"triggered_at": "2025-01-10T10:30:00Z",
"acknowledged_at": null,
"acknowledged_by": null,
"notes": null
}
],
"total": 45
}

Acknowledge Alert

PATCH /alerts/history/{alert_id}?site_id={site_id}

Request Body:

{
"status": "acknowledged",
"notes": "Investigating the traffic drop"
}
FieldTypeDescription
statusenumacknowledged, resolved, or dismissed
notesstringOptional notes about the action taken

Response:

{
"id": 123,
"status": "acknowledged",
"acknowledged_at": "2025-01-10T14:30:00Z",
"acknowledged_by": "user@company.com",
"notes": "Investigating the traffic drop"
}

Statistics

Get Alert Statistics

GET /alerts/stats?site_id={site_id}

Response:

{
"total_rules": 5,
"active_rules": 4,
"alerts_last_7_days": 12,
"alerts_last_30_days": 45,
"by_status": {
"triggered": 3,
"acknowledged": 5,
"resolved": 30,
"dismissed": 7
},
"by_metric": {
"entrances": 25,
"revenue": 15,
"conversions": 5
}
}

Code Examples

Python - Create and Monitor Alerts

import requests

API_KEY = "sm_your_api_key"
BASE_URL = "https://my.sealmetrics.com/api/v1"
ACCOUNT_ID = "my-account"

def create_alert_rule(name: str, metric: str, threshold: int) -> dict:
"""Create a new alert rule."""
response = requests.post(
f"{BASE_URL}/alerts/rules",
headers={"X-API-Key": API_KEY},
params={"site_id": ACCOUNT_ID},
json={
"name": name,
"metric": metric,
"condition": "decrease",
"threshold_percent": threshold,
"comparison_period": "previous_week",
"notification_channels": ["email"],
"email_recipients": ["alerts@company.com"]
}
)
response.raise_for_status()
return response.json()

def get_active_alerts() -> list:
"""Get all triggered alerts."""
response = requests.get(
f"{BASE_URL}/alerts/history",
headers={"X-API-Key": API_KEY},
params={
"site_id": ACCOUNT_ID,
"status": "triggered"
}
)
response.raise_for_status()
return response.json()["alerts"]

def acknowledge_alert(alert_id: int, notes: str):
"""Acknowledge an alert."""
response = requests.patch(
f"{BASE_URL}/alerts/history/{alert_id}",
headers={"X-API-Key": API_KEY},
params={"site_id": ACCOUNT_ID},
json={
"status": "acknowledged",
"notes": notes
}
)
response.raise_for_status()

# Usage
rule = create_alert_rule("Traffic Alert", "entrances", 25)
print(f"Created rule: {rule['id']}")

alerts = get_active_alerts()
for alert in alerts:
print(f"Alert: {alert['rule_name']} - {alert['change_percent']}%")

JavaScript - React Hook for Alerts

import { useState, useEffect } from 'react';

function useAlerts(accountId) {
const [alerts, setAlerts] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
async function fetchAlerts() {
const response = await fetch(
`${BASE_URL}/alerts/history?site_id=${accountId}&status=triggered`,
{ headers: { 'X-API-Key': API_KEY } }
);
const data = await response.json();
setAlerts(data.alerts);
setLoading(false);
}

fetchAlerts();
const interval = setInterval(fetchAlerts, 60000); // Poll every minute

return () => clearInterval(interval);
}, [accountId]);

const acknowledgeAlert = async (alertId, notes) => {
await fetch(
`${BASE_URL}/alerts/history/${alertId}?site_id=${accountId}`,
{
method: 'PATCH',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ status: 'acknowledged', notes })
}
);
// Refresh alerts
setAlerts(alerts.filter(a => a.id !== alertId));
};

return { alerts, loading, acknowledgeAlert };
}

Best Practices

1. Start with Conservative Thresholds

Begin with higher thresholds to avoid alert fatigue:

{
"threshold_percent": 40
}

Adjust lower as you understand normal traffic patterns.

2. Use Filters for Specific Segments

Create targeted alerts for important traffic sources:

{
"name": "Paid Traffic Drop",
"filters": {
"utm_medium": "cpc"
}
}

3. Combine with Webhooks

Integrate with Slack or other tools:

  1. Create a webhook endpoint
  2. Reference it in alert rules:
{
"notification_channels": ["webhook"],
"webhook_endpoint_id": "550e8400-..."
}

4. Review and Resolve Alerts

Don't let alerts pile up:

# Auto-resolve old alerts
old_alerts = get_alerts(status="triggered", older_than_days=7)
for alert in old_alerts:
acknowledge_alert(alert["id"], "Auto-resolved after 7 days")