تخطَّ إلى المحتوى

Lemon Squeezy Failover Runbook

هذا المحتوى غير متوفر بلغتك بعد.

Switch nSelf billing from Stripe to Lemon Squeezy in under 15 minutes. Existing Stripe subscriptions keep running — only new checkouts route through Lemon Squeezy.

  • Stripe experiences a regional outage or checkout degradation
  • Stripe terminates the nSelf merchant account
  • EU VAT or US sales-tax compliance requires a Merchant of Record

The following must be configured in ping_api environment variables before starting:

VariableWhere to find it
LEMONSQUEEZY_API_KEYLemon Squeezy dashboard → Settings → API Keys
LEMONSQUEEZY_STORE_IDDashboard URL: app.lemonsqueezy.com/stores/{id}
LEMONSQUEEZY_WEBHOOK_SECRETDashboard → Webhooks → your endpoint secret
LEMONSQUEEZY_VARIANT_ID_*Dashboard → Products → each product → Variants

Verify the webhook endpoint is registered at:

https://ping.nself.org/webhooks/lemonsqueezy

with all subscription events enabled (subscription_created, subscription_updated, subscription_cancelled, order_created).

Terminal window
source ~/.claude/vault.env
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $LEMONSQUEEZY_API_KEY" \
https://api.lemonsqueezy.com/v1/stores/$LEMONSQUEEZY_STORE_ID
# Expected: 200

2. Health-check the admin endpoint (1 min)

Section titled “2. Health-check the admin endpoint (1 min)”
Terminal window
curl -s -H "X-Admin-Key: $PING_API_ADMIN_KEY" \
https://ping.nself.org/admin/payment-provider | jq .

Expected output:

{
"active": "stripe",
"persisted": "stripe",
"stripe_configured": true,
"lemonsqueezy_configured": true
}

If lemonsqueezy_configured is false, stop here — set the missing env vars and redeploy ping_api before continuing.

Terminal window
curl -s -X POST \
-H "X-Admin-Key: $PING_API_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"provider":"lemonsqueezy"}' \
https://ping.nself.org/admin/payment-provider | jq .

Expected:

{
"previous": "stripe",
"active": "lemonsqueezy",
"message": "Payment provider switched to lemonsqueezy. New checkouts will use lemonsqueezy. Existing subscriptions continue unaffected."
}
Terminal window
curl -s -H "X-Admin-Key: $PING_API_ADMIN_KEY" \
https://ping.nself.org/admin/payment-provider | jq .active
# Expected: "lemonsqueezy"

Open https://cloud.nself.org/pricing in a private window and start a checkout. Confirm the checkout page is hosted at checkout.lemonsqueezy.com rather than checkout.stripe.com.

If Stripe Elements appear instead of the LS checkout page, the cloud frontend is caching old provider state. Add a query param to bust the cache: ?_bust=$(date +%s).

Post to status.nself.org (or nSentry status page if live):

Billing: switched to backup payment provider. Existing subscriptions unaffected.

While PAYMENT_PROVIDER=lemonsqueezy:

  • New checkouts go through Lemon Squeezy
  • Existing Stripe subscriptions keep renewing — Stripe webhooks (/webhooks/stripe) continue processing renewals, cancellations, and payment failures
  • The /webhooks/lemonsqueezy endpoint handles new LS events in parallel
  • License activation works identically for both providers

There is no need to migrate existing Stripe subscribers to Lemon Squeezy. They stay on Stripe until they cancel; new sign-ups go through LS.

Terminal window
curl -s -X POST \
-H "X-Admin-Key: $PING_API_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"provider":"stripe"}' \
https://ping.nself.org/admin/payment-provider | jq .

The internal switch uses PAYMENT_PROVIDER. The admin panel and cloud frontend also read BILLING_PROVIDER as an alias for display purposes — set either one. The factory in payments/factory.ts reads PAYMENT_PROVIDER as the authoritative source; BILLING_PROVIDER is surfaced in health checks only.

SymptomCheck
lemonsqueezy_configured: falseMissing one of the three required LS env vars
Checkout still goes to StripeVercel may be caching a CDN response — check PAYMENT_PROVIDER in Vercel env
Webhook signature failuresLEMONSQUEEZY_WEBHOOK_SECRET mismatch — regenerate in LS dashboard and redeploy
License not activated after purchaseCheck np_payment_events for the LS event ID; check ping_api logs
503 Lemon Squeezy not fully configuredOne of the three required vars is missing from the running ping_api process