Skip to main content

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

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

  1. Secure checkout - Use HTTPS and validate all inputs
  2. Mobile optimization - Ensure responsive design
  3. Error handling - Provide clear error messages
  4. Order confirmation - Send immediate email/SMS confirmation
  5. Inventory management - Update stock levels in real-time
  6. Customer support - Provide easy access to help
  • [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