# Lago Webhooks

## When to Use This Skill

* How do I receive Lago webhooks?
* How do I verify the `X-Lago-Signature` header?
* Why is my Lago webhook signature verification failing?
* How do I handle `invoice.created`, `subscription.terminated`, or `customer.created` events?

## Scope: HMAC mode only (not the JWT default)

Lago lets you pick a signature algorithm when you create a webhook endpoint: `hmac` or `jwt`. **Lago's default is `jwt`** (an RS256 JWT checked with the public key from `/api/v1/webhooks/json_public_key`). **This skill covers `hmac` only.** Choose HMAC when you create the endpoint (dashboard: Developers > Webhooks > Add an endpoint, or `"signature_algo": "hmac"` in `POST /api/v1/webhook_endpoints`). Every delivery carries `X-Lago-Signature-Algorithm`; the examples reject anything other than `hmac`.

## Verification (core)

`X-Lago-Signature` is the **base64** HMAC-SHA256 of the **raw request body**, keyed with your organization's **HMAC Signature Token** (Developers > Webhooks). There is no timestamp in the signed content. Lago has no official webhook-verification helper for HMAC, so verify manually.

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

function verifyLagoSignature(rawBody, signatureHeader, secret) {
  if (!signatureHeader || !secret) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('base64');
  const a = Buffer.from(signatureHeader);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

```

Read the body as raw bytes (`express.raw({ type: '*/*' })` so any content type verifies); never `JSON.parse` before verifying.

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

## Payload and Headers

```json
{ "webhook_type": "invoice.created", "object_type": "invoice", "organization_id": "...", "invoice": { } }

```

The object is under the key named by `object_type`. Headers: `X-Lago-Signature`, `X-Lago-Signature-Algorithm` (`hmac`), `X-Lago-Unique-Key` (idempotency key, process each key once).

## Common Event Types

Dispatch on `webhook_type`:

| Event | Description |
| --- | --- |
| `invoice.created` | Invoice finalized |
| `invoice.payment_status_updated` | Payment status of an invoice changed |
| `subscription.started` | Subscription started |
| `subscription.terminated` | Subscription terminated |
| `customer.created` | Customer created |
| `wallet.depleted_ongoing_balance` | Prepaid wallet ongoing balance is 0 or negative |

> **For the full event list**, see [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/lago-webhooks/references/overview.md) and the [Lago webhook messages reference](https://docs.getlago.com/api-reference/webhooks/messages).

## Environment Variables

```bash
LAGO_HMAC_KEY=your_organization_hmac_signature_token

```

This is the organization-wide HMAC Signature Token, not your Lago API key.

## Local Development

```bash
npx hookdeck-cli listen 3000 lago --path /webhooks/lago

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/lago-webhooks/references/overview.md) — Lago webhook concepts, events, retries
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/lago-webhooks/references/setup.md) — Create an HMAC endpoint, find the token
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/lago-webhooks/references/verification.md) — Verification details and gotchas