Skip to content
Documentation menu

Build on it

Webhooks

Receive DL2App events (clicks, installs, opens, link changes, health alerts) as signed HTTPS requests. Signature format, retries and automatic disabling.

A webhook sends an HTTPS POST to your server when something happens. Create one in the dashboard, choose the events, and optionally limit it to one project, link or tag. Each webhook has its own signing secret, a delivery log, and a button to send a test event.

Events

TypeSent when
link.createdOne link was created in the dashboard or through the API. Imports and bulk creates send links.imported instead.
link.updatedA link's destination, routing, tags or status changed.
link.archivedA link was archived. It stops redirecting and keeps its slug.
link.flaggedAbuse review or destination scanning flagged a link, so it no longer redirects.
links.importedA CSV import or a bulk API call finished. One event for the whole batch, with counts and the ids of the links it made.
link.clickedSomeone followed a link. Only people by default; a webhook can opt in to bots and email scanners. Never contains an IP address.
app.installedThe SDK reported a first open after an install. match says whether, how and how surely we tied it to a click.
app.openedThe app was opened by a link, either straight away or after an install.
app.eventYour app reported an event through the SDK, such as a purchase or a sign-up.
health.failedScheduled monitoring found a failing check on a project that was passing before. Sent once, not on every run.
health.recoveredEvery check that was failing passes again.
domain.verifiedA custom link domain or a web domain passed verification.
alert.createdA new alert appeared on the Alerts page: a health failure, a traffic anomaly, a flagged link, a webhook that was turned off. Alerts about the team as a whole (billing, for example) go to team-wide webhooks only.

Events that come from link traffic (link.clicked, app.installed, app.opened, app.event) are collected about once a minute, so they arrive shortly after they happen, not instantly. Bulk actions and imports send events too.

The request

POST /your/endpoint
Content-Type: application/json
DL2-Signature: t=1791000000,v1=5f2b…

{
  "id": "…",
  "type": "link.clicked",
  "api_version": "2026-10-01",
  "created_at": "2026-10-10T14:03:22.000Z",
  "team_id": "…",
  "project_id": "…",
  "test": false,
  "data": { … }
}

The payload version changes only for breaking changes; new fields can appear at any time, so ignore fields you do not know.

Verify the signature

The DL2-Signature header holds a Unix timestamp t and one or more v1 values. Each v1 is the HMAC-SHA256, in hex, of <t>.<raw body> using the webhook’s secret. Accept the request if any v1 matches and t is within 5 minutes of now.

Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody, header, secret) {
  const parts = header.split(",").map((p) => p.split("="));
  const t = parts.find(([k]) => k === "t")?.[1];
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(t + "." + rawBody).digest();
  return parts
    .filter(([k]) => k === "v1")
    .some(([, v]) => v.length === 64 && timingSafeEqual(Buffer.from(v, "hex"), expected));
}

Use the raw request body, before any JSON parsing. When you rotate a secret, deliveries carry a signature for both the old and the new one for 24 hours, so you can switch without dropping events.

Delivery and retries

  • Answer with any 2xx status within 10 seconds. Do the real work after responding.
  • A failed delivery is retried with growing gaps, up to 10 attempts over about 24 hours.
  • After 20 deliveries in a row have failed, the webhook is switched off and the team is told. Fix the endpoint and switch it back on.
  • Deliveries can arrive more than once and out of order. Use the event id to ignore repeats.
  • The delivery log keeps 30 days of attempts with the response your server gave, and any delivery can be sent again from there.
  • Webhook URLs must be https and may not point at private network addresses.
Webhooks · Docs · DL2App