Skip to content

Webhooks

SUPERWISE Chat webhooks are inbound: your monitoring and alerting tools (PagerDuty, Datadog, or any custom system) POST alert payloads to a registered channel. SUPERWISE Chat verifies the request signature, normalizes the payload, and delivers the alert into a conversation you choose — so alerts land where your team is already working and can be triaged in context. Every inbound alert is checked for safety on the way in, the same way a message from a person is.

This is a reference. For other ways to call the API, see the Gateway API reference and Authentication. For a broader integration overview, see Integrate.

DirectionInbound only — you send events to SUPERWISE Chat
TransportHTTPS POST, JSON body
Authentication (ingest)Per-channel HMAC-SHA256 signature in X-Webhook-Signature
Authentication (management)Bearer JWT with the webhook.manage capability
ProvidersPagerDuty · Datadog · Custom
DestinationA conversation you map at registration time
MethodPathAuthPurpose
POST/v1/webhooks/registerJWT + webhook.manageRegister a channel and receive its signing secret (once)
POST/v1/webhooks/{channel_id}HMAC signatureIngest an alert
GET/v1/webhooks/{channel_id}/infoJWT + webhook.manageCheck a channel’s registration status

All paths are relative to your API base URL (see the Gateway API reference).

A channel_id is your identifier for the channel. It must match ^[a-zA-Z0-9_-]{1,64}$ — 1 to 64 characters, letters, digits, hyphens, and underscores only. Other characters are rejected with 400.

Registration mints the HMAC secret used to sign every inbound alert and binds the channel to a destination conversation.

Request

POST /v1/webhooks/register
Authorization: Bearer <JWT>
Content-Type: application/json
{
"channel_id": "ops-alerts",
"conversation_id": "conv-abc123"
}
FieldTypeRequiredNotes
channel_idstringyes1–64 chars, see format above
conversation_idstringyesAn existing conversation owned by your tenant

Response — 201 Created

{
"channel_id": "ops-alerts",
"conversation_id": "conv-abc123",
"webhook_url": "/v1/webhooks/ops-alerts",
"secret": "<64-char-hex-secret>",
"signature_header": "X-Webhook-Signature",
"message": "Webhook registered successfully. Use HMAC-SHA256 with this secret to sign requests."
}

The secret is a 32-byte random value rendered as a 64-character hex string.

Errors

StatusWhen
400Missing channel_id/conversation_id, or an invalid channel_id format
403Caller lacks the webhook.manage capability
404The conversation_id does not exist for your tenant
409The channel is already registered — delete it first to re-register

Point your monitoring tool at the channel’s URL and sign each request.

Request

POST /v1/webhooks/{channel_id}
X-Webhook-Signature: <hmac-sha256-hex>
X-Webhook-Provider: pagerduty
Content-Type: application/json
{ ...provider payload... }
HeaderRequiredDescription
X-Webhook-SignatureyesHMAC-SHA256 of the request body, hex-encoded (see Signing requests)
X-Webhook-Providernopagerduty, datadog, or custom. If omitted, the provider is inferred from the payload shape, defaulting to custom
X-Webhook-TimestampnoUnix epoch milliseconds. When present, requests older than 5 minutes are rejected as replays

When X-Webhook-Provider is absent, the gateway infers the provider from the body:

  • A top-level event object → PagerDuty
  • A top-level alert_id field → Datadog
  • Otherwise → Custom

Setting X-Webhook-Provider explicitly is recommended for predictable normalization.

Response — 200 OK

A successful ingest returns status: "success" along with the IDs you can use to find the alert later:

{
"status": "success",
"message": "Webhook received and processed",
"alert_id": "<alert id from your payload, or generated>",
"message_id": "<id of the message created in the conversation>",
"trace_id": "<reference id for support>"
}

Errors

StatusWhen
400Invalid channel_id format, or a body that fails validation
401Missing X-Webhook-Signature, an invalid signature, or an expired X-Webhook-Timestamp
404The channel is not registered, or has no conversation mapping
429The channel exceeded its ingest rate limit

The gateway normalizes each provider into a common alert with severity, description, alert_id, triggered_at, and provider metadata. You send the provider’s native shape; SUPERWISE Chat does the mapping.

{
"event": {
"event_type": "incident.triggered",
"id": "evt-001",
"created_on": "2026-06-13T10:00:00Z",
"data": {
"id": "inc-42",
"title": "API latency high",
"description": "p99 latency exceeded 2s",
"urgency": "high",
"status": "triggered"
}
}
}
Source fieldMaps to
event.data.urgency (highhigh, else medium)severity
event.data.description (falls back to title)description
event.idalert id (generated if absent)
event.created_ontriggered-at (now, if absent)
{
"alert_id": "dd-7781",
"alert_title": "Disk usage critical",
"alert_status": "Triggered",
"alert_transition": "Triggered",
"alert_severity": "critical",
"body": "host db-01 at 95% disk",
"last_updated": "2026-06-13T10:05:00Z"
}
Source fieldMaps to
alert_severity (criticalcritical, errorhigh, warningmedium, else low)severity
body (falls back to alert_title)description
alert_idalert id
last_updatedtriggered-at

For any other system, send your own structured payload:

{
"alert_type": "security_incident",
"severity": "high",
"description": "Unusual login pattern detected",
"affected_entities": [
{ "entity_type": "user", "entity_id": "user-99" }
],
"alert_id": "my-system-12345",
"triggered_at": "2026-06-13T10:10:00Z",
"metadata": { "region": "us-east" }
}
FieldTypeNotes
alert_typestringOne of quota_threshold, usage_anomaly, compliance_violation, security_incident; defaults to security_incident
severitystringlow, medium, high, or critical
descriptionstringThe alert text shown in the conversation
affected_entitiesarrayOptional { entity_type, entity_id }; entity_type is user, project, conversation, or tenant
alert_idstringOptional; generated if omitted
triggered_atstringOptional ISO 8601 timestamp; defaults to now
metadataobjectOptional free-form context

Compute an HMAC-SHA256 over the request body using your channel secret, hex-encode it, and send it in X-Webhook-Signature. The gateway recomputes the signature and compares it in constant time.

const crypto = require('crypto');
// `body` is the exact JSON string you send as the request body.
function sign(body, secret) {
return crypto.createHmac('sha256', secret).update(body).digest('hex');
}
const payload = JSON.stringify({ alert_type: 'usage_anomaly', severity: 'medium', description: 'Spike detected' });
const signature = sign(payload, process.env.WEBHOOK_SECRET);
await fetch('https://<your-host>/v1/webhooks/ops-alerts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Provider': 'custom',
'X-Webhook-Signature': signature,
},
body: payload,
});

Include X-Webhook-Timestamp as the current Unix time in milliseconds. Requests whose timestamp is more than 5 minutes from server time are rejected with 401. The header is optional, but enabling it on your sender hardens the channel against replayed requests.

Confirm a channel is registered and mapped before you wire up a sender.

GET /v1/webhooks/{channel_id}/info
Authorization: Bearer <JWT>

Response — 200 OK

{
"channel_id": "ops-alerts",
"registered": true,
"has_conversation_mapping": true,
"conversation_id": "conv-abc123",
"webhook_url": "/v1/webhooks/ops-alerts"
}

Unknown channels — and channels that belong to another tenant — return 404 so the endpoint cannot be used to probe for existing channels.

There is no in-place rotation. To rotate a secret or change the destination conversation, delete the registration and register the channel again — the re-registration mints a fresh secret. A channel can only be registered once; re-registering an existing channel returns 409.

  1. Register the channel and copy the returned secret:
    Terminal window
    curl -X POST https://<your-host>/v1/webhooks/register \
    -H "Authorization: Bearer $JWT" \
    -H "Content-Type: application/json" \
    -d '{"channel_id": "ops-alerts", "conversation_id": "conv-abc123"}'
  2. In PagerDuty, add a webhook on the service and set the URL to https://<your-host>/v1/webhooks/ops-alerts.
  3. Configure PagerDuty to send the secret as an HMAC-SHA256 signature in X-Webhook-Signature, and (recommended) set X-Webhook-Provider: pagerduty.
  4. Trigger a test incident. The alert appears as a message in conv-abc123, ready for your team to triage.