Inbound Webhooks
Create or update events from signed inbound HTTP requests.
Inbound webhooks let external systems create and update incident events on your status dashboards without manual entry in the admin console. Monitoring tools, CI pipelines, and incident platforms send signed HTTPS POST requests; StatusDashboard validates the signature and queues the payload for processing.
Create signing keys on Inbound webhooks. The sections below cover authentication, trigger and update payloads, idempotency, code examples, and webhook logs.
Endpoint
Inbound webhooks let external tools automatically open and update incident events on your StatusDashboard pages. No polling, no manual entry, and no third-party integration middleware required.
| Method | Endpoint |
|---|---|
POST | https://api.statusdashboard.com/public/webhooks/inbound |
Authentication
Every request must include a valid signing key. Signing keys are created on Inbound webhooks. Each key has a Key ID and a Signing Secret.
The signing secret is shown exactly once when the key is created. Store it securely in your secrets manager — it cannot be retrieved after the creation dialog is closed.
Request headers
| Header | Value |
|---|---|
Content-Type | application/json |
X-SD-Key-Id | Your signing key ID (e.g. wk_a1b2c3d4e5f6a7b8) |
X-SD-Signature | HMAC-SHA256 signature (see format below) |
Signature format
The X-SD-Signature header must be formatted as:
t=<unix_timestamp>,v1=<hmac_hex>Where:
<unix_timestamp>is the current Unix timestamp in seconds (e.g.1712345678)<hmac_hex>is an HMAC-SHA256 hex digest computed over the string<unix_timestamp>.<raw_request_body>, using your signing secret as the key
StatusDashboard validates the signature and rejects requests with a timestamp older than 5 minutes to prevent replay attacks.
200 { "ok": true }. This is intentional — returning 4xx on auth failure would allow an attacker to enumerate whether a Key ID exists. If events aren't appearing, verify that the Key ID and signing secret match what is shown in the dashboard.Payload reference
The request body must be a JSON object. The action field determines which operation is performed.
Trigger action — create a new incident
Use action: "trigger" to open a new incident event.
| Field | Type | Required | Description |
|---|---|---|---|
action | "trigger" | Yes | Identifies this as a trigger operation |
title | string | Yes | Incident title (1–250 characters) |
description | string | Yes | Incident description (1–5000 characters) |
impactAnalysis | string | No | Optional customer and service impact details. Rich text field. See Rich text fields. Max 5,000 characters. |
severity | string | Yes | Event-level severity label (must match a configured severity, e.g. "Major Outage"). Applied uniformly to every component in componentIds. |
componentIds | string[] | Yes | UUIDs of the affected components (1–20 IDs). Obtain IDs from GET /app/components. |
statusLabel | string | No | Workflow phase label to start at (e.g. "Investigating"). Defaults to the first non-final incident phase. |
initialMessage | string | No | First timeline message (1–5000 characters). Defaults to "Incident opened via inbound webhook." when omitted. |
idempotencyKey | string | No | Optional dedupe key for this trigger (1–128 characters). Prevents duplicate incidents when your tool retries the same delivery. See Avoiding duplicate incidents below. |
notifications | boolean | No | Whether to send subscriber email notifications when the incident is created. Defaults to true. |
segmentNotification | object | No | Target notifications to specific subscriber segments. Requires the segments feature on your plan. |
segmentNotification.enabled | boolean | — | When true, applies segment filtering to notification recipients. |
segmentNotification.mode | "include" | "exclude" | — | include sends only to subscribers in the selected segments; exclude suppresses them. |
segmentNotification.segmentIds | string[] (UUID) | — | Segment IDs from GET /app/segments. At least one required when enabled is true and mode is include. |
attributes | array | No | Custom key/value attributes on the event (max count per plan). Each item: { "key": string, "value": string, "isPublic": boolean }. |
severity for the whole incident. That severity is applied to every listed component — you cannot assign a different severity per component in one webhook payload.segmentNotification requires the segments feature. If your plan does not include segments, requests that include this field fail with a processing_failed webhook log outcome.Update action — advance an existing incident
Use action: "update" to add a timeline entry and advance the workflow phase of an existing incident.
impactAnalysis is not accepted on update actions. Set it on trigger, or use PATCH /app/events/{id} to change it later.
| Field | Type | Required | Description |
|---|---|---|---|
action | "update" | Yes | Identifies this as an update operation |
eventId | string (UUID) | Yes | The ID of the event to update |
statusLabel | string | Yes | The workflow phase label to advance to (e.g. "Resolved") |
message | string | Yes | The timeline message for this update (1–5000 characters) |
notifications | boolean | No | Update whether future notifications are sent for this event. |
segmentNotification | object | No | Update segment notification targeting (same shape as trigger). Requires the segments feature. |
attributes | array | No | Replace event attributes (same shape as trigger). |
Status updates always enqueue a timeline notification when notifications is true on the event after processing.
Response
| Status | Meaning |
|---|---|
200 | Request queued for processing (also returned for authentication failures — see note above). Check webhook logs for the final processed or processing_failed outcome. |
400 | Invalid request body — malformed JSON or schema validation error |
429 | Rate limit exceeded — slow down your request rate |
Rate limiting
Each org has a configurable inbound webhook rate limit (requests per minute). If the limit is reached, the server returns 429. The rate limit only applies after authentication succeeds, so a 429 confirms that the Key ID and signature were valid.
Avoiding duplicate incidents
Monitoring tools and scripts often retry webhook requests when a connection times out or the response is slow. A 200 response means your request was queued, not that the incident already exists — so retries can accidentally open the same incident more than once if you do not deduplicate on your side.
For action: "trigger", you can send an optional idempotency key so repeated deliveries with the same key reuse the original incident instead of creating another one.
| How to send it | Example |
|---|---|
| JSON field (recommended) | "idempotencyKey": "pagerduty-incident-48291" |
| Request header | X-SD-Idempotency-Key: pagerduty-incident-48291 |
Use a value that uniquely identifies the specific outage or alert — for example your monitoring system's incident ID, or a hash of the alert fingerprint. If you omit a key, each accepted trigger creates a new incident (same as today).
Good practices:
- Generate a new key for each distinct incident; do not reuse a generic label like
"api-down"across unrelated outages. - Include the key in the signed JSON body so it is covered by your HMAC signature.
- If the body field and header are both sent, they must match.
Keys are remembered for 3 days, then expire automatically. After that window, the same key can open a new incident if you send it again.
eventId from your first successful trigger when sending timeline updates.Code examples
Store your Key ID and Signing Secret in environment variables — never hard-code credentials.
Beyond the required fields, you may optionally include notifications, segmentNotification, and attributes on both trigger and update payloads. Omit any you do not need — defaults apply (notifications defaults to true on trigger).
# Required fields only
BODY='{"action":"trigger","title":"Database high latency","description":"Queries taking >5s","severity":"Major Outage","componentIds":["b2c3d4e5-f6a7-8901-bcde-f12345678901"]}'
# Or include optional notification, segment, and attribute fields:
# BODY='{"action":"trigger","title":"Database high latency","description":"Queries taking >5s","severity":"Major Outage","componentIds":["b2c3d4e5-f6a7-8901-bcde-f12345678901"],"notifications":true,"segmentNotification":{"enabled":true,"mode":"include","segmentIds":["<segment-uuid>"]},"attributes":[{"key":"runbook_url","value":"https://wiki.example.com/db-latency","isPublic":true}]}'
TS=$(date +%s)
SIG=$(echo -n "${TS}.${BODY}" | openssl dgst -sha256 -hmac "$SD_SIGNING_SECRET" | awk '{print $2}')
curl -X POST https://api.statusdashboard.com/public/webhooks/inbound \
-H "Content-Type: application/json" \
-H "X-SD-Key-Id: $SD_KEY_ID" \
-H "X-SD-Signature: t=${TS},v1=${SIG}" \
-d "$BODY"Webhook logs
StatusDashboard records an entry for every authenticated inbound webhook request. Logs appear below the signing keys on the inbound webhooks page (10 entries per page; use Prev/Next to browse older entries).
What is logged
| Outcome | When |
|---|---|
accepted | The payload passed schema validation and was queued for async processing |
processed | The worker successfully created or updated an incident |
processing_failed | The payload was valid JSON but failed semantic validation (unknown severity, component, or workflow phase; plan limits; non-incident update; etc.) |
rate_limited | Authentication succeeded but the org rate limit was exceeded |
validation_failed | Authentication succeeded but the payload failed JSON parsing or schema validation |
Authentication failures (bad Key ID, bad signature, stale timestamp) are not logged — the Key ID must be valid and the signature must pass before a log entry is written.
200 { "ok": true } response means the request was queued, not that an event was created. Always check webhook logs for the terminal processed or processing_failed outcome.Log details
Each log entry shows:
- Outcome —
accepted,processed,processing_failed,rate_limited, orvalidation_failed - Action — the
actionfield from the payload (e.g.trigger,update), orunknownif the payload could not be parsed - Key ID — which signing key was used
- Received at — timestamp of the request
- Reason — for failures, a short description of why processing failed
- Event ID — present on
processedoutcomes; links to the created or updated incident - Payload — the raw request body, up to 16 KB
Click any log row to open the detail view, which shows the full parsed payload and a copy button.
Retention
Webhook logs are retained for 30 days and then automatically deleted. They are not part of your audit log.

