# Dwolla Webhooks

## When to Use This Skill

* How do I receive Dwolla webhooks?
* How do I verify the `X-Request-Signature-SHA-256` header on a Dwolla webhook?
* How do I handle `customer_created` or `customer_transfer_completed` events?
* Why is my Dwolla webhook signature verification failing?
* How do I deduplicate Dwolla webhooks by event ID?

## Verification (core)

Dwolla computes an HMAC-SHA256 of the **raw request body**, keyed with the `secret` you supplied when creating the webhook subscription (used as a raw string), and sends the lowercase hex digest in `X-Request-Signature-SHA-256`. There is no timestamp and no prefix. Dwolla has no webhook-verification SDK helper, so verify manually. IP allowlisting is not supported because Dwolla's IPs are dynamic.

Node:

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

function verify(rawBody, signature, secret) {
  if (!signature) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  try {
    return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  } catch {
    return false; // different lengths
  }
}

```

Python:

```python
import hmac, hashlib

def verify(raw_body: bytes, signature: str, secret: str) -> bool:
    if not signature:
        return False
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature, expected)

```

Never re-encode the JSON before verifying; Dwolla's docs warn that re-encoded bodies produce a different signature.

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

## Common Event Types

The event type is in the payload's `topic` field (also sent in the `X-Dwolla-Topic` header).

| Topic | Description |
| --- | --- |
| `customer_created` | A Customer was created |
| `customer_verified` | A Customer was verified |
| `customer_funding_source_added` | A funding source was added to a Customer |
| `customer_funding_source_verified` | A funding source was verified |
| `customer_transfer_created` | A transfer was created for a Customer |
| `customer_transfer_completed` | A Customer transfer succeeded |
| `customer_transfer_failed` | A Customer transfer failed |
| `customer_bank_transfer_completed` | A bank transfer for a Customer succeeded |

> **For the full topic list**, see [Dwolla Webhook Events](https://developers.dwolla.com/docs/webhook-events).

## Payload and Headers

Payload: `id` (event ID), `resourceId`, `topic`, `timestamp`, and `_links` (`self`, `account`, `resource`, `customer`). Fetch the resource through `_links.resource.href` for current state.

| Header | Description |
| --- | --- |
| `X-Request-Signature-SHA-256` | Hex HMAC-SHA256 of the raw body |
| `X-Dwolla-Topic` | Event topic (e.g. `customer_created`) |

Respond with a 2xx within 10 seconds. Dwolla retries up to 8 times over 72 hours and pauses the subscription after 400 consecutive failures (with 24 hours since the last success). Deduplicate on the event `id`, not `resourceId` or `topic`, and return 200 for duplicates.

## Environment Variables

```bash
DWOLLA_WEBHOOK_SECRET=your_subscription_secret   # The "secret" sent when creating the webhook subscription

```

## Local Development

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

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/dwolla-webhooks/references/overview.md) - Dwolla webhook concepts and events
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/dwolla-webhooks/references/setup.md) - Creating a webhook subscription
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/dwolla-webhooks/references/verification.md) - Signature verification details