# dbt Cloud Webhooks

## When to Use This Skill

* How do I receive dbt Cloud webhooks?
* How do I verify dbt Cloud webhook signatures?
* How do I handle `job.run.completed` or `job.run.errored` events?
* Why is my dbt Cloud webhook signature verification failing?
* Why am I getting two notifications for one failed dbt Cloud run?

## Verification (core)

dbt Cloud has no `Signature` header and no scheme prefix. The **`Authorization`**
header carries the bare lowercase hex **HMAC-SHA256 of the raw request body**,
keyed with the webhook's secret (`hmac_secret` in the API, shown once in the UI
when you save the webhook). Use the secret as a raw UTF-8 string and the **raw
body** (don't `JSON.parse` first). There is no timestamp, so dedupe on `eventId`.

```javascript
const crypto = require('crypto');

function verifyDbtCloudSignature(rawBody, authHeader, secret) {
  if (!authHeader) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  const a = Buffer.from(authHeader.trim());
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

```

> **For complete handlers with route wiring, event dispatch, and tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/dbt-cloud-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/dbt-cloud-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/dbt-cloud-webhooks/examples/fastapi/).

## Common Event Types

| Event | Triggered When |
| --- | --- |
| `job.run.started` | A job run starts |
| `job.run.completed` | A run finishes, succeeded or failed (fires after metadata and artifacts are ingested) |
| `job.run.errored` | A run errors (fires immediately; artifacts may not be available yet) |

`job.run.errored` is a subset of `job.run.completed`: subscribe to both and an errored run notifies you twice.

> **For the full event reference**, see [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/dbt-cloud-webhooks/references/overview.md) and [dbt's webhook documentation](https://docs.getdbt.com/docs/deploy/webhooks).

## Environment Variables

```bash
# hmac_secret returned when the webhook is created (raw string, no decoding)
DBT_CLOUD_WEBHOOK_SECRET=your_dbt_cloud_webhook_secret_here

```

## Local Development

```bash
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 dbt-cloud --path /webhooks/dbt-cloud

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/dbt-cloud-webhooks/references/overview.md) - What dbt Cloud webhooks are, events, payload fields
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/dbt-cloud-webhooks/references/setup.md) - Creating a webhook in the UI or API, getting the secret
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/dbt-cloud-webhooks/references/verification.md) - Signature verification details and gotchas