Node.js / Express Example
A complete implementation using Node.js, Express, and Stripe.
Setup
npm install express stripe uuid
npm install -D typescript @types/express @types/nodeMain Server
import express from 'express';
import Stripe from 'stripe';
import crypto from 'crypto';
import { v4 as uuidv4 } from 'uuid';
const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
app.use(express.json());
// In-memory store (use database in production)
const sessions = new Map();
// Signature verification middleware
function verifySignature(req, res, next) {
const signature = req.headers['signature'];
const timestamp = req.headers['timestamp'];
const expected = crypto
.createHmac('sha256', process.env.SIGNING_SECRET!)
.update(`${timestamp}.${JSON.stringify(req.body)}`)
.digest('base64');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).json({ error: { code: 'invalid_signature' } });
}
next();
}
// Create session
app.post('/checkout_sessions', verifySignature, async (req, res) => {
const { cart_items, buyer_context, currency } = req.body;
const sessionId = `cs_${uuidv4().replace(/-/g, '')}`;
const session = {
checkout_session_id: sessionId,
state: buyer_context?.shipping_address ? 'ready_for_payment' : 'not_ready_for_payment',
cart: { items: cart_items.map(item => ({
...item,
title: 'Product',
unit_price: 2999,
total: 2999 * item.quantity,
}))},
totals: {
items_base_amount: 2999,
subtotal: 2999,
tax: 262,
total: 3261,
},
expires_at: new Date(Date.now() + 30 * 60000).toISOString(),
};
sessions.set(sessionId, session);
res.status(201).json(session);
});
// Complete checkout
app.post('/checkout_sessions/:id/complete', verifySignature, async (req, res) => {
const session = sessions.get(req.params.id);
if (!session) {
return res.status(404).json({ error: { code: 'session_not_found' } });
}
const { payment_data } = req.body;
try {
await stripe.paymentIntents.create({
amount: session.totals.total,
currency: 'usd',
payment_method: payment_data.token,
confirm: true,
payment_method_options: {
card: { request_delegated_payment: true },
},
});
session.state = 'completed';
session.order = {
order_id: `ord_${uuidv4().slice(0, 16)}`,
order_number: `ORD-${Date.now()}`,
status: 'confirmed',
};
res.json(session);
} catch (error) {
res.status(400).json({ error: { code: 'payment_declined' } });
}
});
app.listen(3000, () => console.log('Server running on port 3000'));Running
# Development
npx tsx watch server.ts
# HTTPS tunnel for testing
ngrok http 3000