# LeadFast webhook V1

LeadFast sends a signed POST when a relevant public Reddit post matches your product. Delivery is at least once. LeadFast never posts to Reddit.

## Endpoint

- One public HTTPS URL on port 443.
- Respond with any 2xx status within 10 seconds.
- Redirects are not followed.
- The same body and `LeadFast-Delivery` value may arrive more than once.

## Headers

- `LeadFast-Event`: `webhook.test`, `reddit.post.matched`, or `product.understanding.updated`
- `LeadFast-Delivery`: stable UUID for deduplicating retries
- `LeadFast-Signature`: `t=UNIX_SECONDS,v1=HEX_HMAC`

## Verify the signature

Read the exact raw body bytes before JSON parsing. Compute:

`HMAC-SHA256(secret, UTF8(timestamp + "." + delivery_id + ".") || raw_body)`

Compare the hexadecimal digest to `v1` in constant time. Reject timestamps outside the five-minute tolerance window. Keep the signing secret on the server. A secret has no automatic expiration; explicit regeneration invalidates it immediately and pauses delivery until a new test succeeds.

## Matched-post payload

```json
{
  "event": "reddit.post.matched",
  "version": 1,
  "test": false,
  "sent_at": "2026-08-29T18:03:00.000Z",
  "post": {
    "id": "1abc234",
    "title": "How do you find relevant Reddit posts early?",
    "excerpt": "We keep arriving after the discussion is over...",
    "url": "https://www.reddit.com/r/SaaS/comments/1abc234/",
    "subreddit": "SaaS",
    "published_at": "2026-08-29T18:01:00.000Z"
  },
  "match": {
    "score": 86,
    "band": "strong",
    "reason": "The author has a current late-discovery problem."
  },
  "suggested_reply": "We make LeadFast to surface relevant Reddit posts while the conversation is still fresh.",
  "post_age_seconds": 120
}
```

`suggested_reply` is short, product-aware source material generated during scoring. LeadFast never publishes it. Your system may show it to a human or pass it to a separately authorized workflow.

## Product-understanding changes

The distinct `product.understanding.updated` event contains `version: 1`, `test: false`, `sent_at`, `previous_version`, `product_version`, and a `differences` array. It is emitted only after effective monitoring changes are verified. Use the same signature validation and delivery deduplication.

## cURL request shape

The signature below is a placeholder. Use the Test action in LeadFast to send an authentic signed request.

```bash
curl --request POST 'https://your-domain.example/leadfast' \
  --header 'Content-Type: application/json' \
  --header 'LeadFast-Event: webhook.test' \
  --header 'LeadFast-Delivery: 00000000-0000-4000-8000-000000000000' \
  --header 'LeadFast-Signature: t=TIMESTAMP,v1=HMAC_SHA256' \
  --data '{"event":"webhook.test","version":1,"test":true,"sent_at":"2026-08-29T18:03:00.000Z"}'
```

## Copy-paste setup prompt

```text
Configure my backend to receive LeadFast webhook V1 events.

Use the contract at https://leadfast.vip/docs/webhooks.md.

First inspect the existing backend, its framework conventions, deployment model, raw-body handling, environment configuration, and test setup. Reuse those boundaries instead of adding a parallel service.

Create one public HTTPS POST endpoint on port 443. Preserve the exact raw request bytes. Verify LeadFast-Signature as HMAC-SHA256 using my server-side LeadFast signing secret, the LeadFast-Delivery header, and the timestamp from the signature. Reject signatures outside the five-minute tolerance window, compare digests in constant time, and deduplicate retries by LeadFast-Delivery. Return a 2xx response quickly after validation, then process the event asynchronously.

For product.understanding.updated, persist previous_version, product_version and differences. This event reports an effective monitoring change and requires no action.

For reddit.post.matched, persist the post, match, suggested_reply, and delivery ID. Do not post to Reddit automatically. Expose suggested_reply as optional source material for a human or a separately authorized workflow.

Read the signing secret from an environment variable named LEADFAST_WEBHOOK_SECRET. Never put it in browser code, logs, commits, or this prompt. Add tests for a valid signature, a changed body, an expired timestamp, and a duplicate delivery.

Do not deploy, create external resources, change DNS, or expose a public endpoint unless the current task explicitly authorizes that action. Return the implemented endpoint path, required environment variable, tests run, and exact remaining deployment configuration. If deployment is explicitly authorized, deploy through the repository's existing path and return the verified public endpoint.
```
