Skip to content

Webhooks

Receive real-time notifications when subscription events occur.

Setup

  1. Go to Settings (gear icon)
  2. Enable Webhook notifications
  3. Enter your webhook URL
  4. Save

Your endpoint will receive POST requests for subscription events.

Payload Format

json
{
  "event": "subscription.created",
  "timestamp": 1704067200,
  "data": {
    "subscription_id": "sub_abc123",
    "plan_id": "plan_xyz",
    "plan_name": "Pro Plan",
    "subscriber_email": "user@example.com",
    "subscriber_name": "John Doe",
    "status": "pending",
    "amount_sats": 10000
  }
}

Events

EventTriggered When
subscription.createdNew subscription created
subscription.activatedFirst payment received
subscription.renewedRenewal payment received
subscription.payment_failedPayment attempt failed
subscription.cancelledSubscription cancelled
subscription.expiredSubscription period ended

Event Details

subscription.created

Fired when someone starts the checkout process.

json
{
  "event": "subscription.created",
  "data": {
    "subscription_id": "sub_abc123",
    "plan_id": "plan_xyz",
    "subscriber_email": "user@example.com",
    "status": "pending"
  }
}

subscription.activated

Fired when the first payment is received.

json
{
  "event": "subscription.activated",
  "data": {
    "subscription_id": "sub_abc123",
    "plan_id": "plan_xyz",
    "subscriber_email": "user@example.com",
    "status": "active",
    "current_period_end": 1706745600
  }
}

subscription.cancelled

Fired when a subscription is cancelled.

json
{
  "event": "subscription.cancelled",
  "data": {
    "subscription_id": "sub_abc123",
    "subscriber_email": "user@example.com",
    "cancelled_by": "subscriber",
    "reason": "User requested cancellation"
  }
}

Handling Webhooks

python
from flask import Flask, request

app = Flask(__name__)

@app.post("/webhook/subscriptions")
def handle_webhook():
    event = request.json

    if event["event"] == "subscription.activated":
        # Grant access
        user_email = event["data"]["subscriber_email"]
        grant_premium_access(user_email)

    elif event["event"] == "subscription.cancelled":
        # Revoke access
        user_email = event["data"]["subscriber_email"]
        revoke_premium_access(user_email)

    return {"ok": True}
💡

Always respond with a 200 status code quickly. Do heavy processing asynchronously.

Security

Webhooks don't include a signature by default. To verify requests:

  1. Use a secret URL path (e.g., /webhook/abc123secret)
  2. Check the IP address matches your LNbits server
  3. Verify the subscription exists via API call

Retry Policy

Failed webhook deliveries (non-2xx response) are not automatically retried. Use the API to poll for missed events if needed.