Skip to main content

Webhooks

Webhooks let QA Hub notify external systems when key events occur — such as a test run completing, a bug being resolved, or a retest being required.

Supported events

EventFired when
test_run.completedA test run status changes to COMPLETED
test_run_result.failedA result is marked FAILED in a run
bug.resolvedA linked Linear bug reaches the done status
retest.requiredA test case is flagged for retest

Create a webhook

Go to Settings → Developer → WebhooksAdd webhook:

  1. Enter the endpoint URL (must be HTTPS in production)
  2. Select which events to subscribe to
  3. Optionally add a secret for signature verification
  4. Click Save

Payload format

All webhook deliveries share the same envelope:

{
"event": "test_run.completed",
"timestamp": "2026-05-13T12:00:00.000Z",
"tenant_id": "cltenant001",
"data": {
// event-specific payload
}
}

test_run.completed payload

{
"event": "test_run.completed",
"data": {
"run_id": "clrun001",
"run_name": "Sprint 24 regression",
"project_id": "clxyz123",
"environment": "staging",
"total": 48,
"passed": 44,
"failed": 3,
"broken": 1,
"skipped": 0
}
}

bug.resolved payload

{
"event": "bug.resolved",
"data": {
"bug_ticket_key": "LIN-42",
"test_case_code": "TC-017",
"test_case_id": "clcase017",
"resolved_at": "2026-05-13T11:45:00.000Z"
}
}

Signature verification

Each delivery includes an X-QaHub-Signature header:

X-QaHub-Signature: sha256=<hex-encoded HMAC-SHA256>

Verify it in your endpoint using the secret configured when creating the webhook:

import crypto from 'crypto';

function verify(secret: string, payload: string, signature: string): boolean {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}

Retry behavior

Failed deliveries (non-2xx response or timeout) are retried up to 3 times with exponential backoff. After 3 failures, the delivery is marked as failed and no further retries occur.

Manage via API

Webhooks can also be managed via the internal API (session-authenticated):

GET /api/webhooks — List subscriptions
POST /api/webhooks — Create subscription
PATCH /api/webhooks/{id} — Update subscription
DELETE /api/webhooks/{id} — Delete subscription