Runframe
GuidesIntegrations

Custom Webhook

Create Runframe incidents from any HTTP source using custom webhooks. Payload format, HMAC signing, deduplication, and examples.

Custom Webhook

Create incidents from any HTTP source — custom scripts, CI/CD pipelines, Terraform, Zapier, n8n, or any tool that can make an HTTP POST.


Setup

  1. Navigate to Integrations Hub
  2. Click Set up webhook next to Custom Webhook
  3. Copy the unique webhook URL (format: https://api.runframe.io/webhooks/{routingKey})
  4. Configure your tool to POST JSON to this URL

Payload format

Required fields

FieldTypeDescription
titlestringBrief incident summary (max 500 chars)
service_idstringService ID to route the incident to (e.g., SER-00001)

Optional fields

FieldTypeDescription
descriptionstringDetailed description (max 5000 chars)
severitystringSEV0, SEV1, SEV2, SEV3, or SEV4 (default: uses fallback chain)
statusstringnew, investigating, or resolved (default: new)
source_urlstringLink back to the source (dashboard, CI run, etc.)
dedup_keystringDeduplication key — same key = same incident (max 255 chars)
metadataobjectKey-value pairs for additional context (max 10 keys)

Examples

Minimal

{
  "title": "Server is down",
  "service_id": "SER-00001"
}

Complete

{
  "title": "Database connection pool exhaustion",
  "service_id": "SER-00002",
  "description": "Database connections exhausted. API returning 500 errors.",
  "severity": "SEV1",
  "status": "new",
  "source_url": "https://grafana.example.com/dashboard/db",
  "dedup_key": "db-pool-prod-001",
  "metadata": {
    "environment": "production",
    "region": "us-east-1"
  }
}

curl

curl -X POST https://api.runframe.io/webhooks/YOUR_ROUTING_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "title": "High memory usage on production servers",
    "service_id": "SER-00001",
    "description": "Memory usage above 90% on 3 servers",
    "severity": "SEV1"
  }'

Deduplication

  • If dedup_key is provided, subsequent POSTs with the same key update the existing incident instead of creating a new one
  • If dedup_key is omitted, every POST creates a new incident

HMAC signature verification (optional)

For stronger security beyond the routing key, enable HMAC-SHA256 signing:

  1. Generate a signing secret in the integration settings
  2. Include two headers with each request:
X-Runframe-Signature: sha256=<hex HMAC of timestamp.body>
X-Runframe-Timestamp: <unix seconds>

The signature is computed as HMAC-SHA256(signingSecret, "${timestamp}.${body}").

Runframe rejects requests with timestamps older than 5 minutes to prevent replay attacks.

curl with HMAC signing

TIMESTAMP=$(date +%s)
BODY='{"title":"Deploy failed","service_id":"SER-00002","severity":"SEV2"}'
SIGNATURE=$(echo -n "${TIMESTAMP}.${BODY}" | openssl dgst -sha256 -hmac "your-signing-secret" | awk '{print $2}')

curl -X POST https://api.runframe.io/webhooks/YOUR_ROUTING_KEY \
  -H "Content-Type: application/json" \
  -H "X-Runframe-Signature: sha256=${SIGNATURE}" \
  -H "X-Runframe-Timestamp: ${TIMESTAMP}" \
  -d "${BODY}"

Python with HMAC signing

import hmac, hashlib, time, json, requests, os

webhook_url = os.environ['RUNFRAME_WEBHOOK_URL']
signing_secret = os.environ['RUNFRAME_SIGNING_SECRET']

payload = {"title": "High memory usage", "service_id": "SER-00001", "severity": "SEV2"}
body = json.dumps(payload)
timestamp = str(int(time.time()))
signature = hmac.new(
    signing_secret.encode(),
    f"{timestamp}.{body}".encode(),
    hashlib.sha256
).hexdigest()

response = requests.post(webhook_url, data=body, headers={
    'Content-Type': 'application/json',
    'X-Runframe-Signature': f'sha256={signature}',
    'X-Runframe-Timestamp': timestamp
})

Signing is optional

If no signing secret is configured, the routing key alone authenticates requests. HMAC signing adds an extra layer for environments where URL secrecy is harder to guarantee.


Testing

curl -X POST https://api.runframe.io/webhooks/YOUR_ROUTING_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Test webhook",
    "service_id": "SER-00001",
    "description": "Testing webhook integration"
  }'

Verify the incident appears in Runframe with the correct title, service, and severity.