Build an E-commerce Checkout
Learn how to integrate NextAPI into your e-commerce platform to create a seamless checkout experience for your customers.
Checkout Flow Overview
Cart Review → Payment Link → Customer Pays → Order Confirmation → Fulfillment
Basic Checkout Implementation
1. Create Payment Link from Cart
async function createPaymentFromCart(cart, customer) {
const totals = calculateTotals(cart);
const paymentLink = await nextapi.paymentLinks.create({
amount: totals.total,
currency: 'PHP',
description: `Order #${cart.id}`,
customer: {
email: customer.email,
name: customer.name
},
metadata: {
order_id: cart.id,
items: cart.items
},
expires_at: new Date(Date.now() + 24 * 60 * 60 * 1000),
success_url: `${process.env.SITE_URL}/checkout/success?order=${cart.id}`,
cancel_url: `${process.env.SITE_URL}/checkout/cancel?order=${cart.id}`
});
return paymentLink;
}
function calculateTotals(cart) {
const subtotal = cart.items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const tax = subtotal * 0.12; // 12% VAT
const shipping = calculateShipping(cart);
return {
subtotal,
tax,
shipping,
total: subtotal + tax + shipping
};
}
2. Handle Payment Webhooks
app.post('/webhooks/nextapi', (req, res) => {
const event = req.body;
switch (event.type) {
case 'payment_link.paid':
handlePaymentSuccess(event.data);
break;
case 'payment_link.failed':
handlePaymentFailure(event.data);
break;
}
res.status(200).send('OK');
});
async function handlePaymentSuccess(paymentData) {
const orderId = paymentData.metadata.order_id;
// Update order status
await updateOrder(orderId, {
status: 'paid',
paid_at: new Date(),
payment_amount: paymentData.amount
});
// Decrease inventory
await decreaseInventory(paymentData.metadata.items);
// Send confirmation email
await sendOrderConfirmation(orderId);
// Start fulfillment
await initiateFulfillment(orderId);
}
3. Order Management
// Create order when checkout is initiated
async function createOrder(cart, customer) {
const order = await db.query(`
INSERT INTO orders (customer_id, status, total_amount, created_at)
VALUES ($1, 'pending_payment', $2, NOW())
RETURNING *
`, [customer.id, calculateTotals(cart).total]);
// Add order items
for (const item of cart.items) {
await db.query(`
INSERT INTO order_items (order_id, product_id, quantity, price)
VALUES ($1, $2, $3, $4)
`, [order.id, item.product_id, item.quantity, item.price]);
}
return order;
}
Advanced Features
Multiple Payment Methods
const paymentLink = await nextapi.paymentLinks.create({
amount: totals.total,
currency: 'PHP',
allowed_payment_methods: ['gcash', 'maya', 'bank_transfer'],
// ... other parameters
});
Order Tracking
app.get('/orders/track/:reference', async (req, res) => {
const order = await getOrderByReference(req.params.reference);
const tracking = await getOrderTracking(order.id);
res.render('order-tracking', {
order,
timeline: generateTimeline(tracking)
});
});
Best Practices
- Secure checkout - Use HTTPS and validate all inputs
- Mobile optimization - Ensure responsive design
- Error handling - Provide clear error messages
- Order confirmation - Send immediate email/SMS confirmation
- Inventory management - Update stock levels in real-time
- Customer support - Provide easy access to help
Related Concepts
- [Create Your First Payment Link](../guides/quickstarts-tutorials/create-your-first-payment-link
- [Understanding Webhooks](../guides/core-concepts/understanding-webhooks
- [The Collections Lifecycle](../guides/core-concepts/the-collections-lifecycle