Skip to content

Documentation

Add a webhook endpoint

POST/v1/webhooksWebhooks

Starts sending the chosen events to an https address. Every delivery is a POST of { "id", "type", "created_at", "data" }, signed as the Standard Webhooks spec describes (webhook-id, webhook-timestamp, webhook-signature headers), so its libraries verify it. Answer with any 2xx within 10 seconds; anything else is retried for about 28 hours. The answer carries the signing secret, the only time it is shown. Free holds 2; Pro holds 20 endpoints; past that, create answers 429 quota_exceeded (details.reason webhook_limit).

Request body

JSON, sent with Content-Type: application/json.

FieldTypeRequiredDescription
urlstringrequired
eventslink.created | link.updated | link.deleted | link.clicked | link.failing | link.recovered | page.changed[]requiredlink.created: A link was made, through any door. link.updated: A link's destination, ending, title, rules, schedule or state changed. link.deleted: A link was deleted. link.clicked: Visits, sent in batches of up to 100 every few seconds. link.failing: A link's destination stopped answering (two failed checks in a row). link.recovered: A failing destination answers again. page.changed: A watched page's words changed.
descriptionstring, nulloptional

Example request

curl -s -X POST "https://snip.link/v1/webhooks" \
  -H "Authorization: Bearer $SNIP_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Example response

{
  "webhook": {
    "id": "5c2e7a10-3f4b-4d8e-9a61-2b7c0d4e8f13",
    "url": "https://example.com/hooks/snip",
    "description": "Orders service",
    "events": [
      "link.created",
      "link.clicked"
    ],
    "enabled": true,
    "disabled_reason": null,
    "disabled_at": null,
    "failing_since": null,
    "last_success_at": "2026-10-24T09:12:03.000Z",
    "waiting": 0,
    "created_at": "2026-10-20T12:00:00.000Z",
    "updated_at": "2026-10-20T12:00:00.000Z"
  }
}

Response fields

FieldTypeDescription
webhookWebhook
webhook.idstring
webhook.urlstringWhere deliveries go: https, a public domain, the standard port.
webhook.descriptionstring, null
webhook.eventslink.created | link.updated | link.deleted | link.clicked | link.failing | link.recovered | page.changed[]
webhook.enabledbooleanFalse while paused, or after three days in which every delivery failed.
webhook.disabled_reasonpaused | failing | nullpaused by the account, or failing: switched off after three days of failures.
webhook.disabled_atstring, null
webhook.failing_sincestring, nullWhen the current run of failed deliveries began; null while the last one worked.
webhook.last_success_atstring, null
webhook.waitingintegerDeliveries queued or waiting for a retry.
webhook.created_atstring
webhook.updated_atstring
secretstringThe signing secret (whsec_...). Shown here and nowhere else: store it where your endpoint reads it.

Errors

StatusMeaning
400The body or query is invalid. details names each field.
401The API key is missing, malformed or revoked.
429Either the key exceeded its requests-per-second limit (honor Retry-After), or a daily or plan quota is used up (details.reason).

Back to getting started