Stripe billing
Twinlix uses Stripe for subscription billing. Each tenant gets a stripe_customer_id on first checkout; ongoing webhook events keep our internal Subscription row in sync with the Stripe-side state.
Live keys
As of 2026-05-22 (TWIN-135) the platform runs against the live Stripe account acct_1TKhZKI7Gof92OLY (Twinlix.com, Poland).
- Webhook endpoint —
POST https://api.twinlix.com/v1/webhooks/stripe, signing secret stored in backend.envasSTRIPE_WEBHOOK_SECRET. - Products + prices — three tiers (
Small/Middle/Large), monthly + annual price per tier, EUR. Stored onpricing_tierstable withstripe_price_idcolumn.
Test cards
For sanity checks before going live, switch the keys back to sk_test_… and use:
4242 4242 4242 4242— succeeds.4000 0000 0000 9995— declined (insufficient funds).
Subscription lifecycle
signup (Free tier, no Stripe interaction)
│
v
user clicks "Upgrade" on the change-plan page
│
v
POST /v1/crm/stripe/checkout → Stripe Checkout Session URL
│
v
user pays in Stripe-hosted form
│
v
checkout.session.completed webhook
│
v
backend writes Subscription { tier='small', stripe_subscription_id }Cancellation flow lands customer.subscription.deleted on the webhook; backend keeps the row for audit but flips status='cancelled'.
Retention discount (planned)
RETENTION_50_OFF_1MONTH coupon (50% off next month) is on the roadmap for the cancel flow but not yet wired (see TWIN-45).