External Beat Triggers
External Beat Triggers let a page ingest event payloads from outside StatiBeat and turn selected fields into Beat state transitions. The ingest endpoint is intentionally generic: GCP, AWS, Azure, Elastic, Datadog, home-grown jobs, and future providers can all send JSON into the same inbox.
The admin workflow is:
- create an ingest endpoint
- send events to that endpoint's ingest URL
- open an inbox event and inspect the redacted payload
- click a field and build an IFTTT-style trigger rule
- preview the rule against historical inbox events
- attach it to an existing Beat or Beat Group, or create a new external-event Beat for the trigger
- keep public posting in draft/review mode until the preview is trustworthy
In the UI, open Beats -> External Beat Triggers.
What This Is For
Use External Beat Triggers when another system is already producing the signal you trust, but you want StatiBeat to own the customer-facing status workflow.
Good examples include:
- GCP Cloud Monitoring alerts for database readiness
- Datadog monitor notifications for a hosted dependency
- Elastic alerting events for ingest lag
- AWS Health or CloudWatch events routed through a small bridge
- internal deploy, canary, or queue-health jobs
The feature does not require a provider-specific integration before you start. The UI creates generic ingest endpoints; provider names only appear in examples, optional payload fields, or infrastructure-as-code metadata.
Ingest Endpoints And Tokens
Each endpoint is page-scoped and has one active ingest token. The full token is returned only when the endpoint is created or rotated.
The public ingest route is:
POST https://status.example.com/api/v1/external-events/ingest
Content-Type: application/json
X-External-Event-Token: {INGEST_TOKEN}
You can also provide the token in Authorization: Bearer {INGEST_TOKEN}. For webhook tools that cannot set custom headers, use the tokenized URL that is shown when the endpoint is created or rotated:
POST https://status.example.com/api/v1/external-events/ingest/{INGEST_TOKEN}
Content-Type: application/json
StatiBeat accepts a JSON object up to the configured external-event payload limit. Incoming payloads are stored as raw JSON for rule evaluation, and redacted previews are shown in the inbox. Keys that look like secrets, tokens, passwords, private keys, or authorization headers are redacted before they appear in previews, Slack, assistant summaries, or MCP resources.
Token handling guidance:
- store the ingest token like any other webhook secret
- rotate the token when a provider setup is copied to a new owner or environment
- disable the endpoint when the upstream system should stop sending events
- do not put ingest tokens in Terraform output, docs, screenshots, or public issue comments
- use separate endpoints for production, staging, and rule ownership boundaries
Existing ingest tokens and tokenized URLs are never returned by endpoint list, detail, or Terraform export. Endpoint rows still show the stable header-auth URL and token prefix. Rotate the token when you need to reveal a new full tokenized URL. Rotation can expire the current token immediately, after 1 hour, after 24 hours, or after 7 days so upstream webhook changes can overlap during transition windows.
Terraform can create an ingest endpoint through the statuspage_external_event_source resource and receive the one-time token in state, but exported brownfield config intentionally includes only endpoint metadata.
Rule Shape
A trigger rule has four important parts:
conditions: the fields that must matchstage_mapping: how the incoming event maps towarning,critical, orhealthyoutput_mapping: which payload fields become Beat evidenceassociations: the Beat or Beat Group target
Paths can point at:
- JSON payload fields, for example
$.incident.metric.labels.host - request headers, for example
headers.User-Agent - event metadata, for example
event.received_at
Supported condition operators are:
existsequalsoreqnot_equalsorneqcontainsregexingreater_than,greater_or_equal,less_than,less_or_equalafterbefore
Conditions can be nested with all and any groups:
{
"all": [
{
"path": "$.version",
"operator": "equals",
"value": "1.2"
},
{
"path": "$.incident.metric.labels.host",
"operator": "equals",
"value": "runtime-backend.statibeat.com"
},
{
"any": [
{
"path": "$.incident.policy_name",
"operator": "contains",
"value": "database readiness"
},
{
"path": "$.incident.condition_name",
"operator": "contains",
"value": "readiness"
}
]
}
]
}
For GCP Cloud Monitoring's incident payload, the common direct mapping is:
{
"state_path": "$.incident.state",
"values": {
"open": "warning",
"closed": "healthy"
},
"default_stage": "warning"
}
healthy is the Beat recovery stage. A trigger can still label the preview outcome as recovery when the mapped stage is healthy.
Output mapping usually starts small:
{
"fingerprint_path": "$.incident.incident_id",
"summary_path": "$.incident.summary",
"error_message_path": "$.incident.condition_name",
"region_path": "$.incident.resource.labels.location"
}
Use a stable fingerprint for the same underlying incident. For GCP, incident.incident_id is usually the right first choice. Do not also map external_event_id_path to that same incident ID, because fire and recovery notifications share it and would be treated as duplicates. If a provider sends a unique notification ID, map that to external_event_id_path; otherwise let StatiBeat derive a per-stage event ID from the fingerprint, trigger, target stage, and observed time.
Preview And Backtesting
Preview evaluates a draft or saved trigger against historical inbox events without mutating Beat state. It does not create Beat events, public actions, incidents, notifications, Slack messages, or public posts.
Use preview before enabling a rule to answer:
- which old events would have matched
- whether firing and recovery would have paired correctly
- whether duplicate messages would have been suppressed
- whether the rule is too broad
- whether the rule appears to flap
- which Beat or Beat Group actions would have been created
- whether the setup includes auto-post risk
Preview warnings are intentionally conservative. A rule that matches every inbox event, lacks a recovery mapping, or marks public posting as automatic should be reviewed by an operator before it is enabled.
GCP Cloud Monitoring Setup
Google Cloud documents two automation-friendly notification paths for Cloud Monitoring: Webhooks and Pub/Sub. Their notification-channel docs also note that webhook endpoints must be public and recommend Pub/Sub when an endpoint is not public or needs an intermediary service. See Google's Cloud Monitoring notification options.
Use direct Webhooks when:
- the StatiBeat page domain is publicly reachable over HTTPS
- you are comfortable placing the ingest token in the webhook URL or header
- you want the lowest operational overhead
Use Pub/Sub plus a small customer-owned or provider-owned bridge when:
- the provider needs IAM-controlled delivery
- you want to normalize provider-specific payloads
- you want to add provider-side filtering, signing, or enrichment
- you expect the same pattern to support AWS, Azure, Elastic, or Datadog later
Direct Webhook
- Create an ingest endpoint named
GCP Cloud Monitoring. - Copy the endpoint ingest URL. Use the stable URL with
X-External-Event-Token, or use the one-time tokenized URL when the upstream webhook cannot set headers. - In Google Cloud Console, open
Monitoring -> Alerting -> Edit notification channels. - Add a Webhook notification channel with the StatiBeat ingest URL.
- Use Google's test connection to verify the event appears in the External Beat Triggers inbox.
- Open the received event, select
$.incident.metric.labels.hostor another stable provider field, and build the trigger. - Preview the rule against the inbox.
- Attach the trigger to an external-event Beat and leave draft/review mode enabled.
Sample direct payloads:
Pub/Sub Bridge
Cloud Monitoring Pub/Sub notifications are useful when you want a provider-owned queue in front of StatiBeat. A minimal bridge should:
- receive the Pub/Sub push request
- base64-decode
message.data - parse the decoded JSON
- optionally normalize provider fields
- POST the JSON object to the StatiBeat ingest URL
Example bridge handler:
export async function monitoringBridge(req, res) {
const encoded = req.body?.message?.data;
if (!encoded) {
res.status(400).send("missing Pub/Sub message.data");
return;
}
const payload = JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
const response = await fetch(process.env.STATIBEAT_INGEST_URL, {
method: "POST",
headers: {
"content-type": "application/json",
"x-external-event-token": process.env.STATIBEAT_INGEST_TOKEN,
},
body: JSON.stringify(payload),
});
if (!response.ok) {
res.status(502).send(`StatiBeat ingest failed: ${response.status}`);
return;
}
res.status(204).send();
}
For multi-provider expansion, keep the bridge normalization boring and explicit. A good normalized envelope has a provider name, a provider event ID, a stable fingerprint, a state, a host or service key, an observed time, and the original provider payload under raw.
Additional Provider Examples
The examples below are intentionally provider-shaped, not provider-locked. Use them to get a first event into the inbox, then open the received payload and let the UI build the exact rule paths from the fields your account sends.
Datadog Monitors
Datadog webhooks send a POST request when a monitor notification includes @webhook-<name>. Datadog also supports custom headers and a custom JSON payload using monitor variables such as alert ID, alert cycle key, transition, scope, title, type, priority, metric, and message. See Datadog's Webhooks integration.
Recommended setup:
- Create an ingest endpoint named
Datadog monitors. - In Datadog, create a webhook with the stable StatiBeat ingest URL.
- Add
X-External-Event-Tokenas a custom header if your plan/settings allow custom headers. Otherwise use the one-time tokenized URL. - Use a custom JSON payload that normalizes tags you care about, especially
host,service, andenv. - Add
@webhook-<name>to the Datadog monitor notification. - Trigger a test notification, open it in the inbox, and preview the trigger against any monitor events already received.
Sample Datadog files:
AWS CloudWatch And EventBridge
CloudWatch publishes alarm state-change events to EventBridge, including the alarm name, current state, previous state, reason, region, resources, and metric configuration. EventBridge API destinations can invoke HTTPS endpoints as rule targets and can pass matching event payloads to StatiBeat. See AWS docs for CloudWatch alarm events and EventBridge API destinations.
Recommended setup:
- Create an ingest endpoint named
AWS CloudWatch alarms. - Create an EventBridge rule matching
source = "aws.cloudwatch"anddetail-type = "CloudWatch Alarm State Change". - Use an API destination target with
POSTto the stable StatiBeat ingest URL. - Set
X-External-Event-Tokenthrough the EventBridge connection or target header parameters when possible. If that is awkward in your account, use a small Lambda bridge and keep the token in Secrets Manager. - Send the original EventBridge event or a small normalized wrapper that keeps
detail.state.value,detail.alarmName,resources[0],region, and the dimensions you want to route on.
Sample AWS files:
Azure Monitor
Azure Monitor action groups can call webhooks. For most alert types, enable the common alert schema so metric, log, and activity alerts have a consistent envelope with data.essentials, data.alertContext, and optional data.customProperties. See Microsoft's docs for action group webhooks and the common alert schema.
Recommended setup:
- Create an ingest endpoint named
Azure Monitor alerts. - Add a webhook action to the Azure Monitor action group.
- Use the tokenized URL if the action group cannot send the StatiBeat token as a custom header.
- Enable the common alert schema for the webhook action.
- Put routing fields such as
service,environment, orhostin action group custom properties or in metric dimensions. - Preview both
FiredandResolvedevents before enabling the trigger.
Sample Azure files:
Elastic / Kibana Alerting
Kibana webhook connectors can send a JSON body to a request URL using rule/action variables, and can include custom HTTP headers. This is a good fit for a normalized envelope because you control the connector body. See Elastic's Webhook connector and action.
Recommended setup:
- Create an ingest endpoint named
Elastic alerting. - Create a Kibana webhook connector with
POSTto the stable StatiBeat ingest URL. - Add
X-External-Event-Tokenas a secret header. - In the action body, send a compact JSON object with provider, rule, alert, context, and tags fields.
- Configure a recovery action that sends the same fingerprint with a recovered status.
- Use preview to confirm active and recovered events pair under the same fingerprint.
Sample Elastic files:
Terraform Usage
Terraform can manage:
statuspage_external_event_sourcestatuspage_external_beat_triggerstatuspage_synthetic_monitorwithtype = "external_event"
The safest pattern is to attach the trigger to the Beat that already represents the customer-facing service. If you do not already have one, create an external-event Beat first, give it draft-only public action policies, then attach an External Beat Trigger.
The Terraform schema still uses source_id because it models the API resource, but it represents the ingest endpoint selected in the UI.
resource "statuspage_external_event_source" "prod_alerts" {
external_id = "prod-alerts"
name = "GCP Cloud Monitoring"
description = "Production Cloud Monitoring alert notifications"
provider_type = "generic"
enabled = true
}
resource "statuspage_synthetic_monitor" "runtime_backend_readiness" {
external_id = "runtime-backend-db-readiness"
name = "Runtime backend database readiness"
type = "external_event"
enabled = true
interval_seconds = 60
timeout_ms = 10000
regions = []
component_ids = [statuspage_hierarchy_item.runtime_backend.id]
target_json = jsonencode({
kind = "external_event"
})
threshold_policies_json = jsonencode({})
action_policies_json = jsonencode({
warning = {
admin_banner = true
public_post = true
public_post_mode = "draft_only"
incident_status = "degraded"
}
recovery = {
admin_banner = true
public_post = true
public_post_mode = "draft_only"
}
})
}
resource "statuspage_external_beat_trigger" "runtime_backend_readiness" {
external_id = "gcp-runtime-backend-db-readiness"
source_id = statuspage_external_event_source.prod_alerts.id
name = "Runtime backend database readiness from GCP"
enabled = false
draft = true
conditions_json = jsonencode({
all = [
{
path = "$.version"
operator = "equals"
value = "1.2"
},
{
path = "$.incident.metric.labels.host"
operator = "equals"
value = "runtime-backend.statibeat.com"
},
{
path = "$.incident.policy_name"
operator = "contains"
value = "database readiness"
}
]
})
stage_mapping_json = jsonencode({
state_path = "$.incident.state"
values = {
open = "warning"
closed = "healthy"
}
default_stage = "warning"
})
output_mapping_json = jsonencode({
fingerprint_path = "$.incident.incident_id"
summary_path = "$.incident.summary"
error_message_path = "$.incident.condition_name"
region_path = "$.incident.resource.labels.location"
})
safety_settings_json = jsonencode({
public_post_mode = "draft_only"
})
associations_json = jsonencode([
{
monitor_id = statuspage_synthetic_monitor.runtime_backend_readiness.id
role = "primary"
}
])
}
Set enabled = true only after the inbox preview shows the expected firing, duplicate, evidence-update, and recovery behavior.
Terraform export includes endpoint metadata and trigger rules, but it does not export existing ingest secrets.
Slack, Assistant, And MCP Behavior
When an external trigger creates a reviewable Beat action, Slack review prompts include:
- ingest endpoint name
- matched trigger name
- target stage
- fingerprint
- redacted matched payload preview
- Review Draft and admin navigation links
The assistant and MCP operational summaries expose external-trigger context so operators can ask what fired, which endpoint received it, which inbox event matched, and where to review the draft. Hosted MCP exposes the external trigger context on pending Beat actions, recent Beat events, and recent Beat failures with fields such as source ID/name/external ID/provider, inbox event ID, trigger ID/name/external ID, fingerprint, target stage, and admin path. It does not currently include the redacted payload preview in Hosted MCP resources.
Safe Rollout
Start with draft/review mode:
- create the ingest endpoint
- ingest real provider events for a few cycles
- build the trigger from an inbox event
- preview against history
- attach to a Beat or Beat Group with
public_post_mode = "draft_only" - enable the trigger
- review Slack and admin drafts
- only consider auto-posting after the rule has proven stable through at least one firing and recovery
External Beat Triggers are intentionally page-scoped. Endpoints, events, rules, previews, Beat state, Slack prompts, Terraform export, assistant summaries, and MCP resources all stay tied to the current page context.