feat: add outbound webhook event framework

This commit is contained in:
Christian Krakau-Louis
2026-05-23 18:06:29 +02:00
parent aedd868a9c
commit d61a05bad0
17 changed files with 1674 additions and 14 deletions
+1 -1
View File
@@ -236,7 +236,7 @@ Goal: let DMARQ integrate cleanly into existing security and operations workflow
Planned:
- A stable, documented read-only API surface for posture and reporting queries. Delivered with scoped `reports:read`, `posture:read`, and `tls-reports:read` API tokens, public read-only endpoints, and per-token usage audit fields.
- Webhook event delivery for key events (new sender source, compliance drop, missing reports, alert lifecycle).
- Webhook event delivery for key events (new sender source, compliance drop, missing reports, alert lifecycle). Delivered with encrypted webhook endpoints, signed delivery headers, idempotency keys, retry/backoff state, test sends, and delivery inspection.
- Integration templates for SIEM and ticketing workflows (export formats, payload schemas, examples).
- Token/scoping model for API access that matches governance needs (service accounts, least privilege).
+34 -12
View File
@@ -510,17 +510,39 @@ The API uses versioning in the URL path (/api/v1/) to ensure backward compatibil
## Webhooks
DMARQ can notify your systems about events via webhooks:
DMARQ can notify downstream systems about operational events from
**Settings > Webhooks** or the admin API.
1. Navigate to **Settings** > **API Access** > **Webhooks**
2. Click **Add Webhook**
3. Configure:
- Destination URL
- Secret token (for verification)
- Events to subscribe to
| Endpoint | Purpose |
| --- | --- |
| `GET /api/v1/webhooks` | List endpoints and supported event types |
| `POST /api/v1/webhooks` | Create an endpoint |
| `PUT /api/v1/webhooks/{id}` | Update an endpoint |
| `DELETE /api/v1/webhooks/{id}` | Disable an endpoint while keeping delivery history |
| `POST /api/v1/webhooks/{id}/test` | Queue and attempt a test delivery |
| `GET /api/v1/webhooks/deliveries` | Inspect recent delivery attempts |
| `POST /api/v1/webhooks/deliveries/process` | Attempt due retries |
Supported events:
- `report.processed` - When a new report is processed
- `compliance.threshold` - When compliance falls below threshold
- `domain.added` - When a domain is added
- `domain.removed` - When a domain is removed
Supported event types:
- `dmarq.report.imported`
- `dmarq.sender.new`
- `dmarq.compliance.drop`
- `dmarq.reports.missing`
- `dmarq.alert.created`
- `dmarq.alert.resolved`
- `dmarq.webhook.test`
Deliveries are signed with HMAC-SHA256 using the endpoint signing secret.
Receivers should verify these headers:
| Header | Description |
| --- | --- |
| `X-DMARQ-Event` | Event type |
| `X-DMARQ-Delivery` | Delivery id |
| `X-DMARQ-Idempotency-Key` | Stable deduplication key |
| `X-DMARQ-Timestamp` | Unix timestamp used in the signature |
| `X-DMARQ-Signature` | `v1=<hex hmac>` over `timestamp.delivery_id.body` |
Non-2xx responses are retried with exponential backoff until the endpoint's
maximum attempt count is reached. Operators can inspect the delivery status,
last response code, error text, and response excerpt without reading logs.
+43
View File
@@ -135,6 +135,46 @@ and are never stored.
| last_used_ip | VARCHAR(64) | Source IP from the last successful API use |
| usage_count | INTEGER | Successful API use count |
### Webhook_Endpoints
The `webhook_endpoints` table stores outbound webhook destinations. Target
URLs and signing secrets are encrypted at rest.
| Column | Type | Description |
|--------|------|-------------|
| id | INTEGER | Primary key |
| name | VARCHAR(120) | Operator-facing endpoint name |
| url | TEXT | Encrypted destination URL |
| secret | TEXT | Encrypted signing secret |
| event_types | TEXT | Comma-separated event subscriptions, or `*` |
| enabled | BOOLEAN | Whether deliveries can be sent |
| max_attempts | INTEGER | Maximum attempts before a delivery fails |
| timeout_seconds | INTEGER | Per-request timeout |
| last_success_at | TIMESTAMP | Last successful delivery |
| last_failure_at | TIMESTAMP | Last failed delivery attempt |
| failure_count | INTEGER | Consecutive endpoint-level failures |
### Webhook_Deliveries
The `webhook_deliveries` table records delivery attempts and retry state.
| Column | Type | Description |
|--------|------|-------------|
| id | INTEGER | Primary key |
| endpoint_id | INTEGER | Foreign key to webhook_endpoints.id |
| event_type | VARCHAR(80) | Delivered event type |
| payload | TEXT | Event envelope JSON |
| idempotency_key | VARCHAR(160) | Stable deduplication key per endpoint |
| status | VARCHAR(24) | pending, delivered, failed, or abandoned |
| attempt_count | INTEGER | Attempts already made |
| max_attempts | INTEGER | Maximum attempts for this delivery |
| next_attempt_at | TIMESTAMP | Next retry time |
| last_attempt_at | TIMESTAMP | Last attempt time |
| delivered_at | TIMESTAMP | Successful delivery time |
| last_status_code | INTEGER | Last HTTP status code |
| last_error | TEXT | Last sanitized error |
| response_excerpt | TEXT | Truncated downstream response |
## DNS and Configuration Tables
### DNS_Records
@@ -243,6 +283,9 @@ The schema includes several indexes to optimize query performance:
- `ix_api_tokens_key_hash`: On api_tokens.key_hash
- `ix_api_tokens_key_prefix`: On api_tokens.key_prefix
- `ix_api_tokens_active_scope`: On api_tokens.active and api_tokens.scopes
- `ix_webhook_endpoints_enabled_events`: On webhook_endpoints.enabled and webhook_endpoints.event_types
- `ix_webhook_delivery_endpoint_idempotency`: Unique on webhook_deliveries.endpoint_id and idempotency_key
- `ix_webhook_delivery_due`: On webhook_deliveries.status and webhook_deliveries.next_attempt_at
- `idx_activity_logs_timestamp`: On activity_logs.timestamp
- `idx_activity_logs_user_id`: On activity_logs.user_id
- `idx_system_logs_timestamp`: On system_logs.timestamp
+15
View File
@@ -86,6 +86,21 @@ Apprise supports email, Slack, Teams, Discord, generic webhooks, and many other
targets through the same notification field. Add each destination on a separate
line.
## Webhooks
Use **Settings** > **Webhooks** when another system needs structured DMARQ
events instead of human-readable notifications.
1. Add a name and HTTPS endpoint URL.
2. Choose all events or one event type.
3. Save the endpoint.
4. Use **Test** to send a signed test event.
5. Inspect **Recent Deliveries** to see status, attempts, response codes, and errors.
DMARQ signs each delivery with `X-DMARQ-Signature` and includes
`X-DMARQ-Idempotency-Key` so receivers can reject replays and deduplicate
retries. Endpoint URLs and signing secrets are encrypted at rest.
## API Access
DMARQ provides an API for integration with other systems: