Checkout Flow
Learn how to build a complete checkout experience with Salam Gateway.
Overview
The checkout flow has three main stages:
- Payment Creation - Create payment on your server
- Customer Checkout - Redirect customer to complete payment
- Payment Confirmation - Receive webhook and show confirmation
Payment Creation
Create a payment when the customer is ready to checkout:
typescript
// On your server
app.post('/api/checkout', async (req, res) => {
try {
const payment = await salam.payments.create({
amount: req.body.amount,
description: req.body.description,
success_url: `${process.env.APP_URL}/checkout/success`,
cancel_url: `${process.env.APP_URL}/checkout/cancel`,
metadata: {
order_id: req.body.order_id,
customer_email: req.body.email,
},
});
res.json({ redirect_url: payment.redirect_url });
} catch (error) {
res.status(500).json({ error: error.message });
}
});Customer Checkout
Redirect the customer to the checkout page:
javascript
// On your frontend
async function checkout() {
const response = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: 10000,
description: 'Order #1234',
order_id: '1234',
email: 'customer@example.com',
}),
});
const { redirect_url } = await response.json();
// Redirect to checkout
window.location.href = redirect_url;
}\n```
## Success Page
Handle the redirect after successful payment:
```typescript
// pages/checkout/success.tsx
export default function CheckoutSuccess() {
const searchParams = useSearchParams();
const paymentId = searchParams.get('payment_id');
useEffect(() => {
// Verify payment status
fetch(`/api/payments/${paymentId}/verify`)
.then(res => res.json())
.then(data => {
if (data.status === 'captured') {
// Payment confirmed
showSuccessMessage();
}
});
}, [paymentId]);
return (
<div>
<h1>Payment Successful!</h1>
<p>Your order has been confirmed.</p>
</div>
);
}Cancel Page
Handle cancelled payments:
typescript
// pages/checkout/cancel.tsx
export default function CheckoutCancel() {
return (
<div>
<h1>Payment Cancelled</h1>
<p>Your payment was cancelled. No charges were made.</p>
<button onClick={() => router.push('/cart')}>
Return to Cart
</button>
</div>
);
}Webhook Handler
Process the payment confirmation:
typescript
app.post('/webhooks/salam',
express.raw({ type: 'application/json' }),
async (req, res) => {
const signature = req.headers['salam-signature'];
try {
const event = salam.webhooks.constructEvent(req.body, signature);
if (event.type === 'payment.captured') {
const payment = event.data;
// Update order status
await db.orders.update(
{ id: payment.metadata.order_id },
{ status: 'paid', payment_id: payment.id }
);
// Send confirmation email
await sendOrderConfirmation(payment.metadata.customer_email);
// Trigger fulfillment
await fulfillOrder(payment.metadata.order_id);
}
res.json({ received: true });
} catch (error) {
res.status(400).send('Webhook Error');
}
}
);Complete Flow Diagram
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Cart │────▶│ Create │────▶│ Checkout │────▶│ Success │
│ Page │ │ Payment │ │ Page │ │ Page │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ ▲
│ │
▼ │
┌──────────┐ ┌──────────┐
│ Webhook │─────────────────────▶│ Update │
│ Received │ │ Order │
└──────────┘ └──────────┘Best Practices
1. Store Payment ID
Always store the payment ID with your order:
typescript
await db.orders.create({
id: order_id,
payment_id: payment.id,
status: 'pending',
amount: payment.amount,
});2. Use Metadata
Pass relevant data in metadata:
typescript
const payment = await salam.payments.create({
amount: 10000,
metadata: {
order_id: '1234',
customer_id: 'cus_abc',
items: JSON.stringify([...]),
},
});3. Handle Timeouts
Payments expire after 30 minutes:
typescript
if (payment.status === 'expired') {
// Show message: \"Payment expired. Please try again.\"
}4. Verify Payment Status
Always verify payment status on success page:
typescript
const payment = await salam.payments.retrieve(paymentId);
if (payment.status !== 'captured') {
// Don't show success message
}Next Steps
- Webhooks Guide - Set up webhooks
- Error Handling - Handle failures
- Going Live - Production checklist