# Webhook payloads

QACrow delivers events to your endpoint via `POST` with a JSON body.

## Request

```http
POST /your/endpoint HTTP/1.1
Content-Type: application/json
QACrow-Signature: t=1713350000,v1=8f4c2e...
QACrow-Event: run.completed
QACrow-Delivery: dlv_01H...

{
  "id": "evt_01H...",
  "type": "run.completed",
  "createdAt": "2026-04-18T12:34:56Z",
  "data": {
    "run": { /* Run object — see API reference */ }
  }
}
```

## Signature verification

The `QACrow-Signature` header contains a timestamp `t` and one or more `v1` HMAC-SHA256 hex digests of `t + "." + body` keyed with your webhook signing secret. Reject requests where the timestamp is older than 5 minutes or the digest doesn't match.

## Event types

| Event | When it fires |
| --- | --- |
| `run.started` | A run transitions to `running`. |
| `run.completed` | A run reaches a terminal state. |
| `run.failed` | A run ends with `failed`, `blocked`, or `timed_out`. |
| `issue.created` | A new issue is recorded for a run. |
| `issue.critical` | A `critical` severity issue is recorded. |
| `schedule.triggered` | A scheduled run has been queued. |
| `credits.low` | Workspace balance fell below the auto-top-up threshold. |

## Delivery

Endpoints have **10 seconds** to respond. Any non-2xx response (or a timeout) triggers an exponential-backoff retry up to 6 times over ~24 hours.
