Source: https://www.hype-stack.dev/docs/packs-templates/packs/pack-billing-lemonsqueezy

# Billing (Lemon Squeezy)

Lemon Squeezy integration, subscriptions, and billing flows. This is the `pack-billing-lemonsqueezy` pack, one of the
three variants in the billing family. Pick it when you want a merchant of record: Lemon Squeezy is the seller, so it
collects and remits sales tax and VAT for you.

The product shape is the same as [Billing (Stripe)](/docs/packs-templates/packs/pack-billing-stripe): a billing page
with plan cards, a hosted checkout, a customer portal, signature-verified webhooks, and the admin revenue widgets. Only
the provider behind it changes, which is what makes the three packs swappable.

## What you need

- A **Lemon Squeezy** account and a store. Sign up at [app.lemonsqueezy.com](https://app.lemonsqueezy.com).
- Two subscription products (Pro and Premier in the pack's schema), each with a variant.
- Postgres and Valkey (subscription status is cached in Valkey, keyed by organization).
- Optionally **Resend** for receipt emails.

## Credentials

From the Lemon Squeezy dashboard, grab:

- An **API key** (`LEMONSQUEEZY_API_KEY`) from Settings > API.
- Your **store id** (`LEMONSQUEEZY_STORE_ID`) from Settings > Stores.
- The **variant ids** of the two plans (`LEMONSQUEEZY_VARIANT_PRO`, `LEMONSQUEEZY_VARIANT_PREMIER`).
- A **webhook signing secret** (`LEMONSQUEEZY_WEBHOOK_SECRET`), which you choose when you create the webhook below.

Lemon Squeezy has a test mode toggle in the dashboard. Keys and variant ids differ between test and live, so keep both
sets and switch them together.

## Webhook endpoint

The pack exposes the receiver at:

```
POST /checkout/webhook
```

In Settings > Webhooks, add an endpoint pointing at `https://your-api-origin/checkout/webhook`, set a signing secret,
and subscribe to the subscription events. The pack handles the whole `subscription_*` family: created, updated, plan
changed, paused and resumed, payment success, failed, and recovered, cancelled, and expired. Copy the secret into
`LEMONSQUEEZY_WEBHOOK_SECRET`.

There is no local forwarding CLI. For development, expose your backend through a tunnel and register that URL in test
mode.

## Environment variables

| Variable                       | Purpose                                 |
| ------------------------------ | --------------------------------------- |
| `LEMONSQUEEZY_API_KEY`         | API key                                 |
| `LEMONSQUEEZY_STORE_ID`        | The store products belong to            |
| `LEMONSQUEEZY_WEBHOOK_SECRET`  | Signing secret for the webhook endpoint |
| `LEMONSQUEEZY_VARIANT_PRO`     | Variant id for Pro                      |
| `LEMONSQUEEZY_VARIANT_PREMIER` | Variant id for Premier                  |
| `RESEND_API_KEY`               | Optional. Enables receipt emails        |

## In the admin

On top of a starter, this pack adds a revenue row to the [admin app](/docs/packs-templates/packs/admin) dashboard, a
billing card and revenue card on the organization details page, and `/admin/billing` API routes.

## Switching providers

Billing is a family slot. To move to Stripe or Polar later:

```bash
npx @hype-stack/cli compose --packs pack-billing-polar
```

The CLI replaces the files the two packs share, removes the Lemon Squeezy-only ones, and leaves your own code alone.
Subscription state is cached per organization, so existing customers need to be re-subscribed on the new provider.

## Related

- [Billing (Stripe)](/docs/packs-templates/packs/pack-billing-stripe) for the shared checkout and portal flow
- [Organizations](/docs/backend/organizations) for the tenant boundary billing attaches to
- [Going to production](/docs/getting-started/going-to-production) for the webhook checklist
