Webhooks
Webhooks let your application receive real-time notifications when events occur in Qarion, eliminating the need to poll the API for changes. Instead of your application asking "has anything changed?" repeatedly, Qarion pushes an HTTP POST request to your endpoint whenever something happens that you've subscribed to.
This push-based approach is more efficient, more timely, and consumes no API rate limit quota — making webhooks the preferred integration pattern for event-driven architectures, alerting pipelines, and external system synchronization.
Setup
Register a Webhook
To start receiving events, register a webhook by providing the URL of your receiving endpoint, the list of events you want to subscribe to, and a secret key that will be used for signature verification:
POST /webhooks
{
"url": "https://your-app.com/webhooks/qarion",
"events": ["quality.check.failed", "issue.created"],
"secret": "your-webhook-secret"
}
The secret is never sent in webhook payloads — it's used only to compute the HMAC signature that accompanies each delivery, so your handler can verify that the payload genuinely came from Qarion.
Event Types
Qarion emits events across several domains. Each event type follows a domain.action naming convention:
| Event | Description |
|---|---|
quality.check.passed | Quality check succeeded |
quality.check.failed | Quality check failed |
quality.alert.created | New alert triggered |
issue.created | Issue opened |
issue.resolved | Issue closed |
product.created | New product registered |
product.updated | Product metadata changed |
request.submitted | Access request submitted |
request.approved | Access request approved |
request.rejected | Access request rejected |
meeting.scheduled | Meeting created |
contract.violated | SLA breach detected |
Wildcard Events
If you want to subscribe to all events within a domain without listing each one individually, use a wildcard pattern:
{
"events": ["quality.*", "issue.*"]
}
You can also subscribe to all events across the entire platform — which is useful for audit logging or data lake ingestion — by using a single wildcard:
{
"events": ["*"]
}
Payload Format
Standard Structure
Every webhook delivery follows the same top-level structure, regardless of event type. The payload includes a unique event ID, the event type, a creation timestamp, and a data object whose contents vary by event type:
{
"id": "evt_abc123",
"type": "quality.check.failed",
"created_at": "2026-01-15T10:30:00Z",
"data": {
"check_id": "...",
"check_name": "Freshness Check",
"product_id": "...",
"product_name": "Customer Events",
"space_id": "...",
"details": {
"expected": "24 hours",
"actual": "36 hours"
}
}
}
Issue Created
When an issue is created, the payload includes the issue title, priority, and references to the associated product and reporter:
{
"id": "evt_def456",
"type": "issue.created",
"created_at": "2026-01-15T11:00:00Z",
"data": {
"issue_id": "...",
"title": "Missing transactions",
"priority": "high",
"product_id": "...",
"reporter_id": "...",
"space_id": "..."
}
}
Access Request Approved
Approval events include references to the requester, the product, the role granted, and the approver:
{
"id": "evt_ghi789",
"type": "request.approved",
"created_at": "2026-01-15T14:00:00Z",
"data": {
"request_id": "...",
"requester_id": "...",
"product_id": "...",
"role_id": "...",
"approver_id": "..."
}
}
Verification
Signature Validation
Every webhook delivery includes a X-Qarion-Signature header containing an HMAC-SHA256 signature computed from the payload using your webhook secret. You should always verify this signature before processing the event to ensure the payload hasn't been tampered with and genuinely originates from Qarion:
X-Qarion-Signature: sha256=abc123...
Python Verification
import hmac
import hashlib
def verify_webhook(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
provided = signature.replace("sha256=", "")
return hmac.compare_digest(expected, provided)
# In your webhook handler
@app.post("/webhooks/qarion")
def handle_webhook(request):
payload = request.body.decode()
signature = request.headers.get("X-Qarion-Signature")
if not verify_webhook(payload, signature, WEBHOOK_SECRET):
return Response(status=401)
event = json.loads(payload)
process_event(event)
return Response(status=200)
JavaScript Verification
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
const provided = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(provided)
);
}
Note the use of hmac.compare_digest (Python) and crypto.timingSafeEqual (Node.js) — these constant-time comparison functions prevent timing attacks that could otherwise be used to forge signatures.
Retry Policy
If your endpoint doesn't respond with a 2xx status code within 5 seconds, Qarion considers the delivery failed and retries it with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 12 hours |
After 6 consecutive failures, the webhook is automatically disabled to prevent further delivery attempts to an apparently unreachable endpoint. You can re-enable it from the API once the underlying issue is resolved.
Managing Webhooks
List Webhooks
Retrieve all webhooks registered for your account:
GET /webhooks
Update Webhook
Modify the event subscriptions or URL of an existing webhook:
PATCH /webhooks/{id}
{
"events": ["quality.*", "issue.*", "request.*"]
}
Disable Webhook
Temporarily disable a webhook without deleting it. This is useful during maintenance windows when your endpoint might not be available:
PATCH /webhooks/{id}
{
"active": false
}
Delete Webhook
Permanently remove a webhook registration:
DELETE /webhooks/{id}
Best Practices
Your webhook handler should respond to deliveries as quickly as possible — ideally within a few hundred milliseconds and no more than 5 seconds. If processing an event takes longer than that, return a 200 response immediately and queue the event for asynchronous background processing. This ensures that delivery timeouts don't cause retries and duplicate processing.
Because the retry mechanism means events may be delivered more than once, your handler should be idempotent — processing the same event twice should produce the same result as processing it once. Use the event id field to detect and deduplicate repeat deliveries.
Always validate the X-Qarion-Signature header before processing a webhook payload. Without signature verification, an attacker could send fabricated events to your endpoint and trigger unintended actions in your system.
Finally, log every incoming webhook event, including whether it was processed successfully or skipped. This audit trail is invaluable for debugging integration issues, understanding event ordering, and diagnosing failed deliveries.