Webhooks
Two distinct flows:
- Outbound webhooks — RuleForge sends events to a URL of yours when something happens (validation finishes, version publishes, etc.). Endpoints
/platform/organizations/{id}/webhooks/*. - Inbound webhooks — Git providers (GitHub, GitLab, Gitea) send push events to RuleForge, which triggers binding auto-import. Endpoints
/webhooks/git/*.
Outbound — endpoint table
| Method | Path | Permission |
|---|---|---|
| POST | /platform/organizations/{organization_id}/webhooks | integration:manage |
| GET | /platform/organizations/{organization_id}/webhooks | Session |
| GET | /platform/organizations/{organization_id}/webhooks/{webhook_id} | Session |
| PATCH | /platform/organizations/{organization_id}/webhooks/{webhook_id} | integration:manage |
| DELETE | /platform/organizations/{organization_id}/webhooks/{webhook_id} | integration:manage |
| GET | /platform/organizations/{organization_id}/webhooks/{webhook_id}/deliveries | Session |
| POST | /platform/organizations/{organization_id}/webhooks/{webhook_id}/test | integration:manage |
Inbound — endpoint table
| Method | Path | Auth |
|---|---|---|
| POST | /webhooks/git/github | HMAC SHA-256 |
| POST | /webhooks/git/gitlab | Secret token |
| POST | /webhooks/git/gitea | HMAC SHA-256 |
Outbound
POST /.../webhooks
Registers an outbound webhook.
Request body (WebhookCreateRequest):
{
"url": "https://webhooks.acme.com/ruleforge",
"events": [
"validation.completed",
"regression.failed",
"version.published"
],
"secret": "a-secret-string-with-16-plus-chars",
"description": "SOC team channel"
}
url— 8–2048 chars, must behttp://orhttps://. By default private/loopback IPs are blocked (operator-controlled viaNATIVE_WAZUH_WEBHOOK_BLOCK_PRIVATE_NETWORKS).events[]— at least 1 event, all must be valid values. See available events.secret— 16–256 chars. Used to sign the payload with HMAC SHA-256 in theX-RuleForge-Signatureheader.
Response 201 (WebhookRecord).
Supported events
validation.completed
logtest.completed
regression.completed
regression.passed
regression.failed
review.created
review.approved
review.changes_requested
review.rejected
version.created
version.published
publish.failed
feedback.created
api_key.created
api_key.revoked
api.quota.warning
Detailed description in Webhook events.
Delivered payload format
Each delivery is a POST to your endpoint:
POST /ruleforge HTTP/1.1
Host: webhooks.acme.com
Content-Type: application/json
X-RuleForge-Event: validation.completed
X-RuleForge-Delivery: 8e1f2c3a…
X-RuleForge-Signature: sha256=abc123…
User-Agent: RuleForge-Webhooks/1.0
{
"event": "validation.completed",
"delivery_id": "8e1f2c3a…",
"organization_id": "org_...",
"resource_type": "analysis",
"resource_id": null,
"payload": {
"ok": true,
"diagnostic_count": 0,
"total_rules": 8621,
"total_decoders": 623
},
"occurred_at": "2026-04-24T15:30:00Z"
}
Signature verification (Python example):
import hmac, hashlib
def verify(body: bytes, signature: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Response expectation
- Your endpoint must reply
2xxwithin 10 s (NATIVE_WAZUH_WEBHOOK_TIMEOUT_SECONDS, default 10). - Any
4xx/5xxis considered failure → RuleForge retries with exponential backoff. - If your service goes down,
failure_countrises; after repeated failures the webhook may be markedis_active=falseby the operator.
GET /.../webhooks
Lists webhooks.
Response 200: array of WebhookRecord:
{
"id": "wh_...",
"organization_id": "org_...",
"url": "https://webhooks.acme.com/ruleforge",
"target_host": "webhooks.acme.com",
"destination_type": "custom",
"events": ["validation.completed"],
"description": "SOC channel",
"is_active": true,
"delivery_count": 1423,
"failure_count": 12,
"last_delivery_at": "2026-04-24T15:30:00Z",
"secret_masked": "abc***xyz",
"created_at": "...",
"updated_at": "..."
}
PATCH /.../webhooks/{id}
Partial update. To swap the secret, send secret in the body; without it the current one is preserved.
DELETE /.../webhooks/{id}
Removes the webhook. Response 204.
GET /.../webhooks/{id}/deliveries
Delivery history (last N).
Response 200 (WebhookDeliveryRecord[]):
[
{
"id": "del_...",
"webhook_id": "wh_...",
"event_type": "validation.completed",
"status": "delivered",
"response_status": 200,
"duration_ms": 412.3,
"response_snippet": "{\"ok\":true}",
"error_message": null,
"attempt_count": 1,
"next_retry_at": null,
"delivered_at": "2026-04-24T15:30:01Z",
"created_at": "2026-04-24T15:30:00Z"
},
{
"id": "del_...",
"webhook_id": "wh_...",
"event_type": "version.published",
"status": "failed",
"response_status": 502,
"duration_ms": 8932.1,
"error_message": "Bad Gateway",
"attempt_count": 3,
"next_retry_at": "2026-04-24T15:40:00Z",
"created_at": "2026-04-24T15:20:00Z"
}
]
POST /.../webhooks/{id}/test
Triggers a test delivery with a synthetic payload. Useful to validate your endpoint without waiting for a real event.
Request body (optional): { "event_type": "validation.completed" }. Default is validation.completed.
Response 200:
{
"delivered": true,
"response_status": 200,
"duration_ms": 412.3
}
Inbound (Git)
Endpoints that receive Git-provider push events. They trigger auto-import for every binding pointing to repository@branch.
Do not call these manually — configure them as webhooks on the corresponding Git platforms.
POST /webhooks/git/github
Expected headers:
Content-Type: application/json
X-GitHub-Event: push
X-GitHub-Delivery: <uuid>
X-Hub-Signature-256: sha256=<hmac>
Payload: native GitHub Push Event format. Fields read:
ref(must start withrefs/heads/).repository.full_name.after(commit SHA).pusher.name.
Verification: HMAC SHA-256 of the body with the secret configured on the integration. The secret is generated in the UI when the webhook is created on GitHub.
Response 200:
{ "status": "ok", "bindings_triggered": 2 }
Response 401: invalid signature.
POST /webhooks/git/gitlab
Expected headers:
Content-Type: application/json
X-Gitlab-Event: Push Hook
X-Gitlab-Token: <secret>
Payload: GitLab Push Hook. Fields read: ref, project.path_with_namespace, checkout_sha.
Verification: comparison of X-Gitlab-Token with the configured secret.
POST /webhooks/git/gitea
Headers: similar to GitHub (X-Gitea-Event, X-Gitea-Signature).
Verification: HMAC SHA-256 of the body.
How RuleForge uses inbound webhooks
- Receives the push event.
- Verifies signature/token.
- Extracts
(provider, repository, branch, commit_sha). - Finds all active bindings with
sync_on_webhook=truethat match. - Queues a
git_syncjob for each binding. - Returns
200to the provider (processing is asynchronous).
Status of the triggered syncs is available at GET /.../git-bindings/{id}/runs.
Shared structures
WebhookRecord
Shown above.
WebhookDeliveryRecord
Shown above. status ∈ failed.
Related links
- Webhook events — full list with descriptions.
- Webhooks — operational guide
- Git and pipelines
- Organization endpoints — Git bindings.