Skip to content
dhanu docs
Browse pages

Guides

Receive webhooks

Register an endpoint, verify every delivery, respond fast and process later, and test it all from your laptop with the CLI.

Webhooks tell your backend when something happened without polling: a staff member replied, a job finished, a video is ready, credits are low. This guide takes an endpoint from registration to a handler you can trust.

1. Register an endpoint

In the developer console (Developers → Webhooks) add an https URL and pick the events. The secret (whsec_…) is shown once, store it beside your API key as DHANU_WEBHOOK_SECRET. The full event list with a payload example each is on events.

2. Verify, acknowledge, then work

Verify the signature on the raw body before parsing anything, answer 2xx within a few seconds, and do the real work afterwards. A slow handler is retried as if it had failed, and a handler that trusts an unsigned body can be fed anything by whoever guesses your URL.

import express from "express";
import { Dhanu, WebhookSignatureError, type DhanuWebhookEvent } from "dhanu";

const dhanu = new Dhanu(process.env.DHANU_API_KEY!);
const app = express();

app.post("/hooks/dhanu", express.raw({ type: "application/json" }), async (req, res) => {
  let event: DhanuWebhookEvent;
  try {
    event = await dhanu.webhooks.verify(
      req.body.toString("utf8"),
      req.header("Dhanu-Signature"),
      process.env.DHANU_WEBHOOK_SECRET!,
    );
  } catch (err) {
    if (err instanceof WebhookSignatureError) return res.sendStatus(400);
    throw err;
  }
  res.sendStatus(200);
  await queue.add(event.type, event);
});
from flask import Flask, request, abort
from dhanu import Dhanu, WebhookSignatureError

dhanu = Dhanu(os.environ["DHANU_API_KEY"])
app = Flask(__name__)

@app.post("/hooks/dhanu")
def hooks():
    try:
        event = dhanu.webhooks.verify(
            request.get_data(as_text=True),
            request.headers.get("Dhanu-Signature"),
            os.environ["DHANU_WEBHOOK_SECRET"],
        )
    except WebhookSignatureError:
        abort(400)
    queue.enqueue(process, event)
    return "", 200

3. Handle each event once

Deliveries can arrive twice, a retry after a timeout, a resend from the console. Key your processing on event.id and skip one you have seen.

4. Test from your laptop

Dhanu delivers only to public https URLs, so during development point the endpoint at a tunnel or your staging server and let the CLI replay what it receives on your machine:

dhanu webhooks listen --endpoint <endpointId> --forward-to localhost:3000/hooks/dhanu --secret $DHANU_WEBHOOK_SECRET
dhanu trigger task.completed --endpoint <endpointId>

listen re-posts every new delivery to your local handler with a Dhanu-Signature computed from the secret you pass, so the verification above runs for real; trigger fires a test event of any type.

5. Rotate without downtime

Rotating the secret keeps the old one valid for 24 hours, and every delivery in that window carries two v1 signatures. Deploy the new secret, then rotate.