Prerequisites
- Payment provider connected to Flexprice: see Razorpay Setup
- Required webhook events enabled on your provider dashboard
- Flexprice webhook endpoint registered to receive
checkout.session.*events - Customer record exists in Flexprice before the checkout starts
- Plan has at least one non-zero charge
Architecture
Step 1: Create a customer
A customer must exist in Flexprice before a session can be created. Create one at sign-up:external_id as your reference in subsequent calls.
Step 2: Create a Checkout Session
Call this from your backend only: never expose your API key to the frontend.{CHECKOUT_SESSION_ID}insuccess_urlis a placeholder that Razorpay replaces on redirect. Use it to identify which session the customer just completed.idempotency_keytied to your internal order ID means a retry on timeout gives you back the same session, not a duplicate.
id (chk_...) in your database alongside the order.
Step 3: Redirect the customer
Return thepayment_action.url from your backend to your frontend and redirect immediately:
Step 4: Handle the webhook
Do not rely on the redirect URL to confirm payment: it can be bypassed. Thecheckout.session.completed webhook is the authoritative signal.
Register your endpoint in Settings → Webhooks, then handle the events:
Step 5: Handle success and failure pages
Use the redirect URLs for UX only, not for fulfillment logic. Success page: poll the session to confirm before showing a result:checkout_status is completed, show the success state. If it’s still pending, the webhook hasn’t arrived yet: show a “processing” state and poll again in a few seconds.
Failure or cancel page: The customer can start over. Create a new session. The previous session and everything it created are cleaned up automatically.
Step 6: Test the integration
Use your provider’s test credentials before switching to live keys. For Razorpay test cards and UPI IDs, see Razorpay Checkout Setup. After a test payment, verify:- Session
checkout_statusiscompleted - Subscription is
active - Invoice is
finalized - Your backend received
checkout.session.completed - Fulfillment ran (access granted, emails sent, DB updated)
Error reference
| Scenario | Response | Fix |
|---|---|---|
| Customer doesn’t exist | 404 | Create the customer before starting checkout |
| Plan produces zero-amount invoice | 400 | Use a plan with at least one non-zero charge |
Duplicate idempotency_key for active session | 409 | Fetch the existing session; use a new key for a new attempt |
| Customer doesn’t pay in time | Session expires; drafts cleaned up | Let the user start a new checkout |
payment_link.paid not enabled | Subscription stays inactive | Enable the event in your payment provider dashboard |
Go-live checklist
- Switch provider connection from test keys to live keys
- Confirm all required webhook events are enabled on the production URL (not test)
-
success_url,failure_url,cancel_urlpoint to production domains - Webhook endpoint responds within 5 seconds and uses HTTPS
- Fulfillment handler is idempotent
Razorpay Setup
Test credentials and webhook event configuration.
Checkout Sessions API
Full field reference for the create session call.

