# LaunchDarkly Webhooks

## When to Use This Skill

* How do I receive LaunchDarkly webhooks?
* How do I verify the LaunchDarkly `X-LD-Signature` header?
* Why is my LaunchDarkly webhook signature verification failing?
* How do I handle feature flag change events (`kind: "flag"`)?
* Why are my LaunchDarkly webhook deliveries unsigned?

## Verification (core)

Signing is **optional** in LaunchDarkly. Only if the webhook has a secret (check **Sign this webhook**, or set `secret` via the API) does LaunchDarkly send `X-LD-Signature`: the **HMAC-SHA256 hex digest of the raw request body**, keyed with the secret. There is no timestamp and no prefix. **Set a secret, or deliveries are unsigned**, and your handler should refuse to run without one.

Node:

```javascript
const crypto = require('crypto');

function verify(rawBody, signatureHeader, secret) {
  if (!signatureHeader || !secret) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  try {
    return crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
  } catch {
    return false; // different lengths
  }
}

```

Python:

```python
import hmac, hashlib

def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
    if not signature_header or not secret:
        return False
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature_header, expected)

```

> **For complete handlers with route wiring, event dispatch, and tests**, see:
> 
> * [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/launchdarkly-webhooks/examples/express/)
> * [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/launchdarkly-webhooks/examples/nextjs/)
> * [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/launchdarkly-webhooks/examples/fastapi/)

## Event Types

LaunchDarkly has no event-type header. The payload is an audit log entry, so dispatch on the body's `kind` field (and `accesses[].action` for the specific change).

| `kind` | Description |
| --- | --- |
| `flag` | Feature flag changes (the default webhook scope is flags in production) |
| `segment` | Segment changes |
| `project` | Project changes |
| `environment` | Environment changes |

Other fields: `_id`, `date` (ms epoch), `accesses` (`action` + `resource`, e.g. `updateName` on `proj/alexis:env/test`, or `createApprovalRequest`), `name`, `description`, `title`, `titleVerb`, `member`, `target`. Which events are sent is controlled by the webhook's policy (`actions`/`resources` statements).

> **For full details**, see [LaunchDarkly webhooks](https://launchdarkly.com/docs/home/infrastructure/webhooks) and the [Webhooks API](https://launchdarkly.com/docs/api/webhooks).

## Important Headers

| Header | Description |
| --- | --- |
| `X-LD-Signature` | HMAC-SHA256 hex digest of the raw body (only when a secret is set) |

## Environment Variables

```bash
LAUNCHDARKLY_WEBHOOK_SECRET=your_webhook_secret   # The webhook's secret (auto-generated or your own)

```

## Local Development

```bash
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 launchdarkly --path /webhooks/launchdarkly

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/launchdarkly-webhooks/references/overview.md) - LaunchDarkly webhook concepts and payload
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/launchdarkly-webhooks/references/setup.md) - Configuration guide
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/launchdarkly-webhooks/references/verification.md) - Signature verification details