Webhook Event Design
Suggested payload model for downstream event processing.
- webhooks
- events
Omar Gate can emit webhook events to notify downstream systems about scan results. Configure a webhook URL and secret in your workflow or Sentinelayer dashboard.
Event Types
| Event Type | Trigger | Description |
|------------|---------|-------------|
| `scan.completed` | Every successful scan | Scan finished and gate decision was made (passed or blocked). |
| `scan.blocked` | Findings above gate threshold | Subset of `scan.completed` where `gate_status` is `blocked`. |
| `scan.failed` | Runtime or config error | Scan could not complete due to configuration, provider, or infrastructure issues. |
| `scan.skipped` | Rate limit or cooldown hit | Scan was skipped due to `max_daily_scans` or `min_scan_interval_minutes`. |
Common Payload Fields
Every webhook event includes these fields:
| Field | Type | Description |
|-------|------|-------------|
| `event_type` | string | One of the event types above. |
| `run_id` | string | Unique scan identifier. Use as idempotency key. |
| `timestamp` | string | ISO 8601 timestamp of the event. |
| `repo` | string | Full repository name (e.g. `acme/backend`). |
| `branch` | string | Branch or PR head ref that was scanned. |
| `commit_sha` | string | Commit SHA that was analyzed. |
| `pr_number` | integer or null | Pull request number, if applicable. |
| `gate_status` | string | `passed`, `blocked`, or `error`. |
| `severity_counts` | object | Counts by severity: `{ "P0": 0, "P1": 2, "P2": 3, "P3": 5, "info": 1 }`. |
| `total_findings` | integer | Total number of findings. |
| `artifact_links` | object | URLs to download artifacts from the Actions run. |
| `estimated_cost_usd` | string | Estimated LLM cost for this scan. |
Example: scan.completed
{
"event_type": "scan.completed",
"run_id": "run-20260223-001",
"timestamp": "2026-02-23T08:15:30Z",
"repo": "acme/backend",
"branch": "feature/auth",
"commit_sha": "a1b2c3d4e5f6",
"pr_number": 142,
"gate_status": "blocked",
"severity_counts": {
"P0": 0,
"P1": 2,
"P2": 3,
"P3": 5,
"info": 1
},
"total_findings": 11,
"artifact_links": {
"findings": "https://api.github.com/repos/acme/backend/actions/artifacts/12345/zip",
"summary": "https://api.github.com/repos/acme/backend/actions/artifacts/12346/zip"
},
"estimated_cost_usd": "0.0042"
}
Example: scan.failed
{
"event_type": "scan.failed",
"run_id": "run-20260223-002",
"timestamp": "2026-02-23T09:01:12Z",
"repo": "acme/backend",
"branch": "main",
"commit_sha": "b2c3d4e5f6a7",
"pr_number": null,
"gate_status": "error",
"error_code": 2,
"error_message": "Missing required input: sentinelayer_token",
"severity_counts": {},
"total_findings": 0,
"artifact_links": {},
"estimated_cost_usd": "0.00"
}
Webhook Security
Webhooks include an `X-Sentinelayer-Signature` header containing an HMAC-SHA256 signature of the payload body using your webhook secret. Always verify this signature before processing events.
Routing Recommendations
- **scan.blocked** → Slack incident channel or PagerDuty
- **scan.completed** → SIEM ingestion or dashboard update
- **scan.failed** → Ops alert channel for configuration review
- **scan.skipped** → Daily digest or ignore
Structured Answers
What should be event idempotency key?
Use run_id as the primary idempotency key. Each scan produces exactly one run_id that is unique across all events for that scan.
How do I verify webhook authenticity?
Check the X-Sentinelayer-Signature header against an HMAC-SHA256 of the raw payload body using your webhook secret. Reject any request where the signature does not match.
Which event should trigger a Slack alert?
Route scan.blocked to your incident response channel for immediate attention. Use scan.completed for informational updates and scan.failed for ops-level configuration alerts.