# Webhooks A webhook delivers alert hits to your own endpoint, one POST per hit. Use it to put hits into your CRM, your database, or a Slack app you built yourself. ## Setting one up Register the endpoint first. A webhook belongs to your team and can be used by any of its alerts. ```bash curl -X POST -H "Authorization: Bearer $SPUTNIK_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "CRM relay", "url": "https://example.com/hooks/sputnik"}' \ "https://sputnikintelligence.com/api/v1/webhooks" ``` The response carries the signing secret. Then point an alert at it. ```bash curl -X POST -H "Authorization: Bearer $SPUTNIK_TOKEN" \ -H "Content-Type: application/json" \ -d '{"webhook": ""}' \ "https://sputnikintelligence.com/api/v1/alerts//destinations" ``` Registering an endpoint on its own delivers nothing. An alert has to point at it. ## The payload ```json { "event_id": "4821", "event_type": "alert.hit", "project": { "slug": "...", "name": "Acme" }, "alert": { "slug": "...", "name": "Acme brand mentions", "url": "https://..." }, "matched_searches": ["Brand"], "post": { "id": 91823, "slug": "...", "title": "The one where we argue about pricing", "url": "https://example.com/episodes/214", "published_at": "2026-08-12T09:00:00+00:00", "source": "The Example Show", "type": "podcast" }, "snippet": "...the matched passage..." } ``` **Dedupe on `event_id`.** It is the hit id. A retry sends the same id, so your handler can be idempotent. The payload has no full text or transcript in it. Fetch those from the API using the post slug. ## Verifying the signature We sign with the Standard Webhooks scheme, so any library for that will verify it. ``` webhook-id: webhook-timestamp: webhook-signature: v1, ``` The key is the base64-decoded secret with its `whsec_` prefix stripped. > **Verify against the raw body** > > Verify before you parse. Decoding the JSON and re-encoding it changes the bytes, and the signature will fail. This is the mistake most people make once. > > Check the timestamp as well, and reject anything more than a few minutes old, so an old request cannot be replayed at you. The secret is returned on every read of the webhook, so you can look it up again. Endpoints that cannot verify signatures, such as Zapier, can ignore it. ## When your endpoint fails We retry. After repeated failures the webhook switches itself off, and `deactivated_reason` says why. While it is off, any alert destination pointing at it reports `is_delivering: false`. Watch that field. An alert can look healthy while its webhook has stopped delivering. Fix the endpoint, then PATCH the webhook with `is_active: true`. That also clears the failure count, so it gets a fresh run of attempts. ## Deleting You cannot delete a webhook while an alert still delivers to it. Deleting would silently mute those alerts. Set `is_active: false` instead, which is reversible.