> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowsbuilt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks Overview

> Receive real-time churn alerts via HTTP POST to your server.

## How it works

When a watched user's churn risk crosses their threshold, ChurnKit sends a signed HTTP POST to the webhook URL you registered with `watch()`.

```
User's score crosses threshold
          ↓
ChurnKit signs payload with HMAC-SHA256
          ↓
POST https://yourapp.com/hooks/churn-alert
          ↓
Your server verifies signature → processes alert
```

## Webhook payload

```json theme={null}
{
  "event": "churn_risk_alert",
  "userId": "user_123",
  "score": 0.84,
  "tier": "high",
  "signals": ["no_login_7d", "support_spike", "export_all_data"],
  "recommendation": "This user is at high risk. Reach out immediately.",
  "triggeredAt": "2024-06-01T14:22:00Z"
}
```

## Event types

| Event              | When                                     |
| ------------------ | ---------------------------------------- |
| `churn_risk_alert` | User's score crossed the watch threshold |

## HTTP headers

| Header                 | Value                    |
| ---------------------- | ------------------------ |
| `Content-Type`         | `application/json`       |
| `X-ChurnKit-Signature` | `sha256=<hmac_hex>`      |
| `X-ChurnKit-Timestamp` | Unix timestamp (seconds) |

## Responding to webhooks

Return a `2xx` status code to acknowledge receipt. ChurnKit retries failed deliveries (non-2xx or timeout) with exponential backoff for up to 72 hours.

```typescript theme={null}
// Always return 200 quickly — process async if needed
export async function POST(req: Request) {
  const body = await req.text()

  // Verify first
  const valid = await verifyWebhookSignature(
    body,
    req.headers.get('x-churnkit-signature') ?? '',
    process.env.CHURNKIT_WEBHOOK_SECRET!
  )
  if (!valid) return new Response('Unauthorized', { status: 401 })

  // Acknowledge immediately, process async
  const payload = JSON.parse(body)
  processAlertAsync(payload) // don't await

  return Response.json({ ok: true })
}
```

## Getting your webhook secret

Your webhook signing secret is shown in the [FlowsBuilt Console](https://console.flowsbuilt.com/dashboard/keys) under API Keys. Add it to your environment:

```bash theme={null}
CHURNKIT_WEBHOOK_SECRET=whsec_your_secret_here
```

<Warning>
  Always verify signatures. Never process a webhook payload before confirming its authenticity.
</Warning>

## Next steps

<Card title="Verify Signature" icon="shield-check" href="/churnkit/webhooks/verify-signature">
  Step-by-step guide to signature verification in Node.js, Next.js, and Express.
</Card>
