---
title: "Subscribe to events"
method: POST
path: "/api/v1/webhooks"
---

# Subscribe to events

`POST /api/v1/webhooks`

## Request

- Base URL: `https://lyreleads.com`
- URL: `https://lyreleads.com/api/v1/webhooks`
- Auth: HTTP bearer

Push instead of poll. The event worth subscribing to is signal.detected: a business you already hold changed, which happens weeks after your last request and is the thing polling handles badly. Job events exist too, though polling a jobId you were handed is perfectly reasonable.

The URL must be https on a publicly routable address. We refuse private and reserved ranges, cloud metadata addresses, localhost and hostnames that resolve to any of those, and we re-check at delivery time as well as at registration, because a hostname can be repointed afterwards.

The response carries a signing secret, once. Every delivery arrives with X-Lyre-Timestamp and X-Lyre-Signature: sha256=<hex>, where the digest is HMAC-SHA256 of "{timestamp}.{raw body}" under that secret. Compare it before trusting a payload, and reject timestamps far from now to stop replays.

Delivery retries five times with widening backoff (1m, 5m, 25m, 2h, 10h). A subscription that fails 20 times in a row is switched off rather than retried forever, and stays visible so you can see why. Maximum 10 webhooks per account.

## Request body

- object
  - `url` string, required: https endpoint on a public address.
  - `events` string[]: Defaults to ["signal.detected"].
  - `description` string

## Response `200`

id, url, events, and the signing secret (shown once)

## Other responses

- `400`: URL refused, unknown event type, or the 10-webhook limit

---

[API](https://skmtc.dev/lyreleads/apis/lyre-leads-api.md) · [All operations](https://skmtc.dev/lyreleads/apis/lyre-leads-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lyreleads/apis/lyre-leads-api/revisions/1c7c73cc355f?raw)
