---
title: "Webhooks"
description: "Subscribe to publish events instead of polling, and verify each delivery with the signature."
section: "Core concepts"
url: https://dravo.dev/docs/concepts/webhooks
---
# Webhooks

## What you can subscribe to

Rather than polling the publish history, register an endpoint and Dravo will
POST events to it. Available events:

| Event | Fires when |
| --- | --- |
| `post.published` | A job delivered to at least one account. |
| `post.failed` | A job failed for every account. |
| `post.queued` | A job entered the queue (optional notification). |
| `connection.revoked` | A connected account was revoked or needs reconnect. |

Register endpoints in the dashboard or with
[POST /v1/webhooks](/docs/api/webhooks). The signing secret is returned once at
creation.

## The payload

Dravo sends a JSON body describing the event:

```json
{
  "event_type": "post.published",
  "timestamp": "2026-06-23T10:15:30Z",
  "data": {
    "job_id": "job_2a7f93",
    "account_id": "acc_8f2c1d",
    "provider": "x",
    "platform_post_id": "1890123456789",
    "status": "published"
  }
}
```

## Verifying the signature

Every delivery carries a `Dravo-Signature` header so you can confirm it came
from Dravo and was not tampered with. The header has the form
`t=timestamp,v1=signature`, where the signature is an HMAC-SHA256 of
`timestamp + "." + raw_body` using your endpoint signing secret.

```js

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(",").map((kv) => kv.split("="))
  );
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(parts.v1)
  );
}
```

Compute the HMAC over the raw request body, before any JSON parsing, or the
bytes will not match.

## Testing

Send a sample event to any endpoint with
[`POST /v1/webhooks/{webhook_id}/test`](/docs/api/webhooks). The response includes
the HTTP status your endpoint returned and the attempt count, so you can confirm
your receiver works before relying on it.
