---
title: "Register a webhook for story events"
method: POST
path: "/api/webhooks"
---

# Register a webhook for story events

`POST /api/webhooks`

## Request

- Base URL: `https://techsnif.com`
- URL: `https://techsnif.com/api/webhooks`
- Auth: none declared

Registers an https URL to receive story.new and story.updated events as the pipeline publishes them (runs every 30 minutes). Registration performs a challenge handshake so this API cannot be used to send traffic to third parties: TechSnif POSTs { "type": "webhook.verify", "challenge": "<uuid>" } to the url, and the endpoint must respond with a 2xx status and include the challenge string anywhere in its response body within 10 seconds, otherwise registration fails with 422. The 201 response includes the signing secret exactly once. Deliveries are POSTs of { "events": [...] } where each event has type, id, at, and story (a StorySummary object); the id field is stable and usable for deduplication. Every delivery carries an X-TechSnif-Signature header of the form sha256=<hex HMAC-SHA256 of the raw request body, computed with the secret>. Verify a delivery by recomputing the HMAC over the exact raw body bytes and comparing hex digests. Subscriptions are disabled after 10 consecutive delivery failures. Only https URLs on the default port are accepted (no localhost, no raw IP hosts), topics is limited to 20 slugs, and per-host and global registration caps apply.

## Request body

- object
  - `url` string, uri, required: Public https URL on the default port. http, localhost, raw IP hosts, and non-443 ports are rejected.
  - `topics` string[]: Topic slugs (e.g. ai, security). Empty or omitted means all topics.
  - `tier` integer: Minimum headline tier to deliver (3 = top stories only). Omitted means all tiers.

## Response `201`

Subscription created. The secret is returned only in this response.

- object
  - `id` string
  - `url` string, uri
  - `topics` string[]
  - `minTier` integer, nullable
  - `secret` string: 64 hex characters. Shown once; used to sign deliveries as X-TechSnif-Signature.
  - `note` string

## Other responses

- `400`: Invalid request parameters
- `409`: This url is already registered. DELETE it (with the secret) to re-register.
- `422`: Challenge verification failed: the endpoint did not answer 2xx with the challenge string echoed in its response body within 10 seconds.
- `429`: Registration caps reached (global active subscription limit, or per-host limit of 5).

---

[API](https://skmtc.dev/techsnif/apis/techsnif-api.md) · [All operations](https://skmtc.dev/techsnif/apis/techsnif-api/llms.txt) · [OpenAPI document](https://skmtc.dev/techsnif/apis/techsnif-api/revisions/7404c46acbb0?raw)
