If you sell hosting in 2026 and you can't accept Stripe payments cleanly, you're leaving real money on the table. Stripe handles 3D Secure, recurring billing, SCA compliance, and dispute management in ways that DIY gateways can't touch. The official WHMCS Stripe module ships out of the box — but there are 6-7 setup decisions that determine whether it works smoothly or generates support tickets every week.
This is the setup I run on every WHMCS install that needs Stripe.
Step 1 — Pick the right Stripe module
WHMCS ships two Stripe modules. They are different and not interchangeable:
- "Stripe" (legacy) — Stripe.js v2 era. Uses an embedded card form on your site. Older 3D Secure flow. Deprecated by Stripe; will eventually stop working.
- "Stripe Payments" (current, sometimes called "Stripe (Payment Intents)") — uses Stripe's Payment Intents API. Handles SCA / 3DS2 properly. Hosted by Stripe via Stripe Elements.
Use Stripe Payments. If you have legacy Stripe configured, plan a migration — Stripe themselves are phasing out the older API and the legacy module's days are numbered.
Step 2 — Configure your Stripe account first
Before touching WHMCS, set up Stripe properly:
- Activate the account. Stripe → Settings → Account details. Provide business info, bank details, tax IDs. Without this, you're in test-mode only.
- Set up your statement descriptor. Settings → Payments → Statement Descriptor. This is what shows up on the customer's bank statement. "STRIPE *YOURCO" is fine; cryptic random strings cause chargebacks.
- Enable the payment methods you want. Settings → Payment methods. At minimum: Card. Strongly recommend also enabling Apple Pay, Google Pay, and (if regionally relevant) Link.
- Set your timezone and currency. Settings → Account → Country & Currencies. Mismatches between Stripe and WHMCS cause subtle reconciliation issues.
Step 3 — Get the right API keys
Stripe → Developers → API keys.
For WHMCS you need:
- Publishable key (starts with
pk_live_...orpk_test_...) — safe to ship in browser code. - Secret key (starts with
sk_live_...orsk_test_...) — server-side only.
Use the restricted key option if your Stripe dashboard offers it: create a key that's limited to the resources WHMCS needs (charges, customers, payment intents, refunds, webhooks). Don't ship a full-access key just because it works.
Start in test mode. You'll get separate test/live keys; do the entire integration test cycle on test keys before flipping to live.
Step 4 — Configure WHMCS
WHMCS Admin → Setup → Payments → Payment Gateways → All Payment Gateways → Stripe Payments → Activate.
Fill in:
- Display Name: "Credit / Debit Card" reads cleaner than "Stripe Payments" on invoices.
- Publishable API Key:
pk_test_... - Secret API Key:
sk_test_... - Webhook Secret: leave empty for now; we'll fill this in step 5.
- Use 3D Secure: Enable. Required for European cards (SCA / PSD2). Skipping this means failed payments for EU customers.
- Store Payment Method: enable if you want recurring billing or saved cards. Required for subscription products.
- Convert To For Processing: leave empty unless you're doing currency conversion at the gateway (rare; usually let Stripe handle).
Save and confirm the gateway appears in the active list.
Step 5 — Set up the webhook (the part everyone skips)
Without a working webhook, Stripe and WHMCS will drift out of sync. Refunds processed in Stripe won't reflect in WHMCS. Subscription cancellations won't propagate. Failed payments won't trigger re-attempts. Always set up the webhook.
In Stripe Dashboard:
- Developers → Webhooks → Add endpoint.
- URL:
https://yourwhmcs.com/modules/gateways/callback/stripe_payments.php - Events to send: Select events → check
charge.refunded,charge.dispute.created,charge.dispute.closed,payment_intent.succeeded,payment_intent.payment_failed,customer.subscription.updated,customer.subscription.deleted. - Save. Stripe shows you a signing secret (
whsec_...). - Copy the signing secret into WHMCS → Stripe Payments → Webhook Secret. Save.
From now on, every relevant event in Stripe will POST to your WHMCS endpoint, which validates the signature and acts on it. This is what keeps both systems in agreement.
Step 6 — Run the full test cycle
Stripe provides test card numbers that simulate every scenario. Run all of these before going live:
| Card | Tests |
|---|---|
4242 4242 4242 4242 | Successful payment |
4000 0025 0000 3155 | 3D Secure required + succeeds |
4000 0000 0000 9995 | Insufficient funds |
4000 0000 0000 0002 | Generic decline |
4100 0000 0000 0019 | Fraud-flagged |
For each, place a test order in WHMCS, complete payment, and verify:
- WHMCS marks the invoice paid (or failed) as expected.
- The Stripe Dashboard shows the corresponding event.
- The webhook log in Stripe shows the call to WHMCS returned 200.
- For a subscription product, place another test order on the same client and verify the saved payment method works.
- Issue a refund from Stripe Dashboard and confirm WHMCS receives the webhook and marks the invoice as Refunded.
Step 7 — Going live
Don't just switch keys. Do this in order:
- In Stripe Dashboard, toggle to Live mode. Copy the live publishable + secret keys.
- Create a second webhook for the live endpoint with the same URL but a different signing secret.
- In WHMCS Stripe Payments config, replace test keys with live keys, replace the test webhook secret with the live webhook secret. Save.
- Process one small real charge (you can refund it after) end-to-end. Watch the invoice, the Stripe Dashboard, and the webhook log.
Don't disable the test webhook in Stripe; it's harmless and helpful if you ever need to debug.
Recurring billing — the rules
WHMCS handles two different recurring scenarios with Stripe:
- WHMCS-managed renewals. WHMCS generates invoices on the next-due-date, then charges the stored card via Stripe. Stripe sees these as single charges. This is the WHMCS default and the right choice for most hosting businesses — WHMCS controls the renewal logic, can apply prorations, coupons, etc.
- Stripe Subscriptions. Stripe controls the billing cycle and creates invoices on its own. WHMCS gets webhook notifications. More complex; only use if you have specific reasons to centralize on Stripe.
For the WHMCS-managed model, the critical setting is Auto Renew per service. Set on the product (Setup → Products/Services → edit → Auto Setup & Auto Renew) and per-client preferences. Use StripePaymentMethod hook points (see WHMCS hook docs) if you need custom logic around saved-card handling.
3D Secure / SCA — what changed and why it matters
European regulation (PSD2) requires Strong Customer Authentication for most card transactions. In practice this means: customers see a popup asking them to verify the payment via their bank app or SMS code. If your integration doesn't support this, EU card payments silently fail.
The Stripe Payments module handles SCA automatically when you enable "Use 3D Secure." When SCA is required:
- Customer enters card on the WHMCS payment page.
- Stripe responds: "authentication required."
- WHMCS redirects to a Stripe-hosted 3DS challenge page.
- Customer authenticates with their bank.
- They're returned to WHMCS, which now completes the charge.
You don't write any of this — it's built in. But you must enable the toggle and you must have the webhook properly configured to receive payment_intent.succeeded after the challenge completes.
How to verify everything is wired correctly
- Setup → Payments → Stripe Payments → Test Settings — confirms the keys work and the Stripe account is reachable.
- Stripe Dashboard → Developers → Webhooks → click your endpoint → confirm last 10 events all returned 200.
- Place a test order with the standard test card; verify the invoice is paid in WHMCS before page reload finishes.
- Issue a Stripe-side refund; within 30 seconds, the invoice in WHMCS should show as Refunded.
- Watch Utilities → Logs → Gateway Log in WHMCS for any errors during real customer charges in the first 48 hours after go-live.
Common pitfalls
"Customers say their card was charged but the invoice shows unpaid." The webhook isn't reaching WHMCS or is failing. Check the webhook log in Stripe — look for non-200 responses. Most common cause: WAF/Cloudflare blocking Stripe's webhook IPs. Whitelist Stripe's webhook IPs (Stripe publishes them) or temporarily disable strict WAF rules for the callback URL.
"Recurring renewals fail for some clients but not others." The saved payment method is from before SCA was enabled. Stripe's policy is that pre-SCA stored cards can be charged off-session for renewals, but new ones need to be set up correctly. The fix: ask affected clients to re-add their card.
"3D Secure required error in the gateway log." Enable 3D Secure in the module config. This is the most common configuration miss I see.
"Refunds processed in Stripe Dashboard don't reflect in WHMCS." The charge.refunded event isn't in your webhook subscription. Add it.
"Disputes / chargebacks aren't creating WHMCS tickets." Stripe doesn't notify WHMCS about disputes natively. Wire up the charge.dispute.created webhook to a hook that creates a support ticket — or just review Stripe's Disputes dashboard regularly.
My take — Stripe vs. alternatives
- Stripe: best card processing in most countries, best developer experience, highest fees in the basket. Worth it unless your margins are razor-thin.
- PayPal: not optional. Some customers refuse to enter card details and only have PayPal. Run both gateways.
- Razorpay / Cashfree (India): if you sell to India, you need a local gateway. Stripe India exists but has limits.
- NowPayments / Cryptomus: only if your customer base actually pays in crypto. Don't add gateways for vibes.
I keep Stripe + PayPal + one regional gateway active on every WHMCS install I work with. Three gateways covers ~98% of customer preferences.
Going further
- Stripe Payment Intents documentation
- Stripe webhooks guide
- WHMCS Stripe module documentation
- Stripe test cards reference
I set up payment gateways for hosting businesses — Stripe, PayPal, Razorpay, NowPayments, regional bank integrations. If your billing isn't smooth, tell me what's broken and I'll send a quote in 24 hours.