Skip to content
LinkdashLinkdash
Esc
navigateopen⌘Jpreview
On this page

Webhooks

HTTPS endpoints for link.visit, link.download, and link.play, delivered by Svix.

HTTPS endpoints. HTTPS only. No localhost or private IPs. Up to 10 per account.

Events: link.visit, link.download, link.play. Secret is whsec_…, shown once on create/rotate. Keep it. Never put it in the JSON body.

CLI

linkdash webhooks create --url https://example.com/hooks
linkdash webhooks list
linkdash webhooks get <id>
linkdash webhooks rotate <id>
linkdash webhooks delete <id>

list and get return secretHint only (whsec_…xxxx).

HTTP

curl https://api.linkdash.dev/v1/webhooks \
  -X POST \
  -H "Authorization: Bearer ldash_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hooks"}'

GET /webhooks, POST /webhooks, GET /webhooks/:id, DELETE /webhooks/:id, POST /webhooks/:id/rotate.

Payload

{
  "type": "link.visit",
  "timestamp": "2026-08-17T16:00:00.000Z",
  "data": { "id": "deck", "kind": "file", "country": "DE", "referrer": "…" }
}

Headers on every delivery (Svix retries reuse the same id):

  • svix-id
  • svix-timestamp (unix seconds)
  • svix-signature (v1,<base64 hmac>)

Signed content: {id}.{timestamp}.{raw body} HMAC-SHA256. Secret format whsec_ + base64.

Verify

Deliveries are sent by Svix and follow the Standard Webhooks spec. Verify with the svix package (same as Clerk and Resend).

npm i svix
import { Webhook, WebhookVerificationError } from "svix";

const wh = new Webhook(process.env.LINKDASH_WEBHOOK_SECRET); // whsec_… shown once

try {
  const event = wh.verify(rawBody, {
    "svix-id": headers["svix-id"],
    "svix-timestamp": headers["svix-timestamp"],
    "svix-signature": headers["svix-signature"],
  });
  // event.type is "link.visit" | "link.download" | "link.play"
} catch (err) {
  if (err instanceof WebhookVerificationError) {
    // 400 — do not process
  }
  throw err;
}

Was this page helpful?