Skip to content

Markdown version · llms.txt

On this page

Xylo CMS bills through the business owner’s own Stripe account. There is no Stripe Connect and no Xylo platform fee. Money does not pass through Xylo.

Caution. This is for the owner and their agent together. Live keys take real money. Use test keys until the Stripe account is verified and a bank is connected. Do not put secret keys in site config or in the Git repo. Back up nothing here except the knowledge that a wrong webhook URL silently drops payment events.

Until this is done, payments, memberships and session packs run in simulated mode locally and on preview deploys. Production pay links say online payment is not set up. Staff can still record cash and checks.

Activate the account

Create or sign in at the Stripe dashboard and finish activating it: business details, bank account for payouts, identity. Stripe asks for these. Nobody else should fill them in.

Keys

In Vercel (Production only; leave Stripe unset on Preview):

  • STRIPE_SECRET_KEY — sk_test_… / sk_live_…, or a restricted key rk_…
  • STRIPE_WEBHOOK_SECRET — whsec_… from the webhook endpoint
  • NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY — pk_… (optional for Checkout today; needed later for cards on file)

A restricted key needs Write on Checkout Sessions, Refunds, Customers, Products, Prices, Subscriptions, and Billing Portal Sessions/Configurations, and Read on PaymentIntents, PaymentMethods and Invoices. If a test payment fails with a Stripe permission error, add the permission the log names.

Webhook

Developers → Webhooks → Add destination. Endpoint:

https://YOUR-DOMAIN/api/stripe/webhook

Subscribe to exactly these events (the CMS ignores anything else):

  • checkout.session.completed
  • checkout.session.async_payment_succeeded
  • checkout.session.async_payment_failed
  • charge.refunded
  • customer.subscription.created
  • customer.subscription.updated
  • customer.subscription.deleted
  • invoice.paid
  • invoice.payment_failed

Subscription events are used when memberships is on. They are harmless if it is off. Events are stored and applied once. Replays from the Stripe dashboard should not double-pay or double-activate.

Billing portal

In Stripe, enable the Customer billing portal. The CMS opens a portal session for the signed-in customer’s own Stripe customer:

  • Payment method updates and invoice history stay on
  • Cancellation follows Let members cancel online on admin → Memberships (on by default). When that is off, the portal configuration has cancellation disabled.

Use test keys while you try this. The no-cancel configuration is created in Stripe the first time it is needed, then cached.

Payment methods

Cards and wallets are on by default. Turn on ACH Direct Debit in Stripe if you want US bank payments (cheaper for large invoices; they take a few business days). Checkout offers whatever you enabled.

Test then live

  1. Test-mode keys and a test-mode webhook (its own whsec_…).
  2. Buy a membership plan, a session pack if that switch is on, and pay a test invoice (card 4242 4242 4242 4242).
  3. Confirm status in admin after the webhook, not only in the Stripe dashboard.
  4. Switch to live keys and a live webhook before launch.
  5. Make a small real payment, confirm it in admin → Payments, then refund it there.

Payouts (daily by default, instant payouts to a debit card) are in the Stripe dashboard, not in the CMS.

Canonical: https://www.xylosoftware.com/cms/docs/stripe