Why is Stripe payment failing for my members?
BYOK key validation, webhook endpoint registration, test vs live mode mismatch, and customer portal config — fix Stripe payment failures in your VeloCMS membership.
A failed payment is the worst thing that can happen to a paid membership — it means a subscriber who's trying to give you money can't. And if it's happening silently (the payment form shows an error but you have no idea as the blog owner), you could be losing revenue without knowing it. Here's how to find and fix the problem.
Step 1 — Verify your BYOK Stripe key
VeloCMS uses Bring Your Own Keys (BYOK) for Stripe — you connect your own Stripe account. Go to Admin → Settings → Membership → Stripe Connection and check the connection status. If it shows 'Connected' with a green indicator, your key is valid. If it shows 'Invalid key' or 'Not connected', the secret key you entered may be wrong, expired, or from the wrong Stripe account.
- In your Stripe dashboard, go to Developers → API keys.
- For production, use the live secret key (starts with sk_live_). For testing, use the test secret key (starts with sk_test_).
- Never use the publishable key (starts with pk_) as the secret key — it won't work for server-side operations.
- If you created a restricted key, make sure it has read+write permissions for: Checkout Sessions, Customer Portal, Customers, Payment Intents, Prices, Products, Subscriptions, and Webhook Endpoints.
- In VeloCMS Admin → Settings → Membership → Stripe Connection, paste the correct key and click Save. The page will immediately verify the key with a test API call.
Step 2 — Check webhook endpoint registration
Stripe uses webhooks to tell VeloCMS when a payment succeeds, fails, or when a subscription status changes. Without a working webhook, VeloCMS can't activate member access after a successful payment — the member pays but their account stays locked.
- In your Stripe dashboard, go to Developers → Webhooks.
- Look for an endpoint with the URL format: https://yourslug.velocms.org/api/member-webhook/yourslug.
- If no such endpoint exists, go to VeloCMS Admin → Settings → Membership → Webhook Setup and click Register Webhook — VeloCMS will create it automatically.
- If the endpoint exists but shows recent failures in Stripe, click on it and look at the failed event details. Common errors: 401 (wrong webhook secret), 500 (server error — check Railway logs), 404 (VeloCMS service is down).
- Copy the Webhook Signing Secret from Stripe and paste it into VeloCMS Admin → Settings → Membership → Webhook Secret. Without this, VeloCMS rejects all incoming webhook events.
Test mode vs live mode mismatch
Stripe has two completely separate environments: test mode and live mode. API keys, customers, products, prices, and webhooks from test mode don't exist in live mode and vice versa. A common mistake is setting up products and prices in test mode, then switching to a live secret key — VeloCMS tries to look up the product in live mode and can't find it.
Your Stripe membership prices must be created in the same mode as your API key. If you're using a live key (sk_live_), your prices must have been created in Stripe live mode. Check the Stripe dashboard with the test mode toggle off to see live mode data.
Customer portal configuration
If payment itself works but members can't manage their subscriptions (cancel, update card, view invoices), the Stripe Customer Portal may not be configured. In your Stripe dashboard, go to Settings → Billing → Customer portal. Enable the portal and at minimum enable: invoice history, subscription cancellation, and payment method updates. Without these settings, the portal link in VeloCMS Admin → Billing returns a generic Stripe error page.
Members access their subscription management via your blog's /member/account page. If the portal shows an error, check the Stripe Customer Portal configuration first before looking at VeloCMS settings.