Learn how to redirect users after successful payment with Stripe Checkout, including setup, session creation, success handling, webhooks, and security best practices.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
How to Redirect After Successful Payment with Stripe Checkout
Step 1: Set Up Stripe Checkout
First, you need to set up Stripe Checkout in your application. Make sure you have the Stripe library installed in your project.
For Node.js applications:
npm install stripe
For PHP applications:
composer require stripe/stripe-php
Step 2: Create a Checkout Session
When creating a Checkout Session, you need to specify the success and cancel URLs. These are the URLs where customers will be redirected after they complete or cancel the payment.
For Node.js with Express:
const stripe = require('stripe')('your_stripe_secret\_key');
const express = require('express');
const app = express();
app.post('/create-checkout-session', async (req, res) => {
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line\_items: [
{
price\_data: {
currency: 'usd',
product\_data: {
name: 'Your Product',
},
unit\_amount: 2000, // $20.00 in cents
},
quantity: 1,
},
],
mode: 'payment',
success_url: 'https://yourwebsite.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel\_url: 'https://yourwebsite.com/cancel',
});
res.json({ id: session.id });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
For PHP:
['card'],
'line\_items' => [[
'price\_data' => [
'currency' => 'usd',
'product\_data' => [
'name' => 'Your Product',
],
'unit\_amount' => 2000,
],
'quantity' => 1,
]],
'mode' => 'payment',
'success_url' => 'https://yourwebsite.com/success?session_id={CHECKOUT_SESSION_ID}',
'cancel\_url' => 'https://yourwebsite.com/cancel',
]);
echo json_encode(['id' => $checkout_session->id]);
?>
Step 3: Redirect the Customer to the Checkout Page
After creating the session, redirect the customer to the Stripe Checkout page using the session ID.
For client-side JavaScript with Stripe.js:
// Add Stripe.js to your HTML
Step 4: Handle the Success Redirect
Create a success page that will handle the redirect after a successful payment. This page will receive the session ID in the URL query parameters.
For Node.js with Express:
app.get('/success', async (req, res) => {
const { session\_id } = req.query;
try {
// Retrieve the session to get payment details
const session = await stripe.checkout.sessions.retrieve(session\_id);
// Verify payment was successful
if (session.payment\_status === 'paid') {
// Payment was successful, update your database or perform other actions
// Render success page or redirect
res.render('success', {
paymentId: session.payment\_intent,
customerEmail: session.customer\_details.email
});
} else {
// Payment was not successful
res.redirect('/payment-failed');
}
} catch (error) {
console.error('Error retrieving session:', error);
res.redirect('/error');
}
});
For PHP:
payment\_status === 'paid') {
// Payment was successful, update your database or perform other actions
// Display success page
echo "Thank you for your payment!";
echo "Payment ID: " . $session->payment\_intent;
echo "Customer Email: " . $session->customer\_details->email;
} else {
// Payment was not successful
header('Location: /payment-failed.php');
exit;
}
} catch (\Exception $e) {
echo "Error: " . $e->getMessage();
header('Location: /error.php');
exit;
}
} else {
header('Location: /');
exit;
}
?>
Step 5: Implement Webhook for Payment Verification (Recommended)
It's important to implement a webhook to verify payments server-side. This ensures that you capture all payment events, even if the user closes the browser before being redirected.
For Node.js with Express:
const bodyParser = require('body-parser');
// Use the raw text body parser for webhook signatures
app.post('/webhook', bodyParser.raw({type: 'application/json'}), async (req, res) => {
const sig = req.headers['stripe-signature'];
const endpointSecret = 'your_webhook_signing\_secret';
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
console.log(`Webhook Error: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the checkout.session.completed event
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Fulfill the order
if (session.payment\_status === 'paid') {
fulfillOrder(session);
}
}
res.status(200).send();
});
function fulfillOrder(session) {
// Update your database
// Send an email to the customer
console.log(`Order fulfilled: ${session.id}`);
}
For PHP:
type == 'checkout.session.completed') {
$session = $event->data->object;
// Fulfill the order
if ($session->payment\_status === 'paid') {
fulfillOrder($session);
}
}
http_response_code(200);
function fulfillOrder($session) {
// Update your database
// Send an email to the customer
error\_log("Order fulfilled: " . $session->id);
}
?>
Step 6: Add Security Measures
To enhance security, add measures to verify that the payment is legitimate before providing access to purchased content or services.
// In your success route handler, add additional verification
app.get('/success', async (req, res) => {
const { session\_id } = req.query;
// Verify that the session\_id exists
if (!session\_id) {
return res.redirect('/error');
}
try {
const session = await stripe.checkout.sessions.retrieve(session\_id);
// Verify that the session belongs to the current user (if applicable)
// This could involve checking against a user ID stored in the session metadata
if (session.metadata.userId !== req.user.id) {
return res.redirect('/unauthorized');
}
// Verify payment was successful
if (session.payment\_status === 'paid') {
// Additional verification: Check if this order has already been processed
const orderExists = await checkOrderExists(session.id);
if (orderExists) {
// Order already processed, just show success page
return res.render('success', { paymentId: session.payment\_intent });
}
// Process the order and save to database
await processOrder(session);
// Render success page
res.render('success', {
paymentId: session.payment\_intent,
customerEmail: session.customer\_details.email
});
} else {
res.redirect('/payment-failed');
}
} catch (error) {
console.error('Error verifying payment:', error);
res.redirect('/error');
}
});
Step 7: Testing the Integration
Before going live, test your integration using Stripe's test mode.
// Install Stripe CLI and run the following command to forward webhook events
stripe listen --forward-to http://localhost:3000/webhook
Step 8: Advanced: Custom Success Page with Dynamic Content
Create a more personalized success page by dynamically loading content based on the payment details.
app.get('/success', async (req, res) => {
const { session\_id } = req.query;
try {
// Retrieve the session
const session = await stripe.checkout.sessions.retrieve(session\_id, {
expand: ['line_items', 'customer', 'payment_intent']
});
if (session.payment\_status === 'paid') {
// Get purchased items details
const purchasedItems = session.line\_items.data;
// Get customer information
const customer = session.customer;
// Get payment details
const paymentIntent = session.payment\_intent;
// Generate download links, access codes, or other resources
const resources = await generateResources(purchasedItems);
// Send confirmation email
await sendConfirmationEmail(customer.email, purchasedItems, paymentIntent.id);
// Render success page with all details
res.render('detailed-success', {
customer: customer,
paymentId: paymentIntent.id,
amount: paymentIntent.amount / 100, // Convert cents to dollars
items: purchasedItems,
resources: resources,
date: new Date(paymentIntent.created \* 1000).toLocaleDateString()
});
} else {
res.redirect('/payment-pending');
}
} catch (error) {
console.error('Error processing success page:', error);
res.redirect('/error');
}
});
// Helper functions
async function generateResources(items) {
// Generate download links, access codes, etc.
// Based on purchased items
return items.map(item => ({
id: item.id,
name: item.description,
downloadLink: `https://yoursite.com/downloads/${item.id}`,
accessCode: generateUniqueCode()
}));
}
function generateUniqueCode() {
return Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
}
async function sendConfirmationEmail(email, items, paymentId) {
// Implement email sending logic
console.log(`Sending confirmation email to ${email} for payment ${paymentId}`);
}
Step 9: Handling Failed Payments
Create a page to handle failed payments, providing clear instructions for customers.
app.get('/payment-failed', (req, res) => {
res.render('payment-failed', {
supportEmail: '[email protected]',
supportPhone: '+1-800-123-4567',
tryAgainUrl: '/checkout'
});
});
Step 10: Session Recovery for Abandoned Checkouts
Implement session recovery for customers who abandon the checkout process.
// Store session ID in your database when creating the checkout session
app.post('/create-checkout-session', async (req, res) => {
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line\_items: [
{
price\_data: {
currency: 'usd',
product\_data: {
name: 'Your Product',
},
unit\_amount: 2000,
},
quantity: 1,
},
],
mode: 'payment',
success_url: 'https://yourwebsite.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel\_url: 'https://yourwebsite.com/cancel',
// Add metadata for tracking
metadata: {
userId: req.user.id,
cartId: req.body.cartId
}
});
// Store session in database
await saveCheckoutSession(session.id, req.user.id, req.body.cartId);
res.json({ id: session.id });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Function to save checkout session
async function saveCheckoutSession(sessionId, userId, cartId) {
// Implementation depends on your database
console.log(`Saving session ${sessionId} for user ${userId} with cart ${cartId}`);
}
// Endpoint to recover abandoned sessions
app.get('/recover-checkout', async (req, res) => {
try {
// Get user's latest abandoned session
const abandonedSession = await getAbandonedSession(req.user.id);
if (abandonedSession) {
// Check if session is still valid
const session = await stripe.checkout.sessions.retrieve(abandonedSession.sessionId);
if (session.status === 'open' && !session.expired) {
// Redirect to existing checkout
return res.redirect(session.url);
}
}
// If no valid session exists, create a new one
res.redirect('/checkout');
} catch (error) {
console.error('Error recovering session:', error);
res.redirect('/checkout');
}
});
async function getAbandonedSession(userId) {
// Implementation depends on your database
console.log(`Getting abandoned session for user ${userId}`);
// Return null if no abandoned session exists
return null;
}
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.