Quick Overview
The MoPay flow is intentionally short: create a session, redirect the customer, then verify the payment result when they return.
Your backend owns the session creation, MoPay owns the payment experience, and your app regains control once the customer is redirected back.
Your App → Create Payment Session → Redirect to MoPay → User Pays → Redirect Back
API Service
https://pay.mopay.co.lsCreate and manage payment sessions from your backend.
Payment UI
https://mopay.co.lsHosted customer-facing checkout for mobile money and card payments.
Getting Started
Start by creating a MoPay account and generating the API key your server will use for payment session creation.
Get Your API Key
- Go to https://mopay.co.ls
- Create an account and log in
- Create a new Project
- Copy your API Key from the project settings
Security: Keep your API key secure. Store it in environment variables, never in client-side code.
Integration Steps
Build the integration in three predictable moves: create the session, redirect the customer to MoPay, then verify what happened on return.
Step 1: Create a Payment Session
Make a POST request to create a payment session:
POST https://pay.mopay.co.ls/api/external/payment
Headers:
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Body:
{
"amount": "100.00",
"reference": "ORDER12345",
"redirectUrl": "https://yourwebsite.com/payment-complete",
"description": "Order #12345",
"customerEmail": "customer@example.com",
"customerName": "John Doe"
}Reference Format: Must contain only alphanumeric characters. No spaces, hyphens, underscores, or special characters.
Note on paymentFrequency:
ONCE- One-time payment onlyMONTHLY- (Coming Soon) Monthly debit orders/subscriptionsANNUALLY- (Coming Soon) Annual debit orders/subscriptions
⚠️ Debit order functionality for MONTHLY and ANNUALLY is not yet available. All payments currently process as one-time payments.
Success Response (200):
{
"success": true,
"sessionId": "MOP_abc123_ORDER12345",
"paymentUrl": "https://mopay.co.ls/pay/MOP_abc123_ORDER12345",
"reference": "ORDER12345",
"amount": "100.00"
}Step 2: Redirect User to Mopay
After receiving the response, redirect the user to the payment URL:
// JavaScript example
window.location.href = response.paymentUrl;
// Or use a link
<a href="https://mopay.co.ls/pay/MOP_abc123_ORDER12345">Complete Payment</a>The user will be taken to Mopay's payment page where they can select a payment method (M-Pesa, EcoCash, or Card) and complete the transaction.
Step 3: Handle the Redirect Back
After payment completion, users are redirected to your URL with query parameters:
✅ Successful Payment:
https://yourwebsite.com/payment-complete?status=success&reference=ORDER12345&transactionId=TXN123&sessionId=MOP_abc123_ORDER12345&amount=100.00&paymentMethod=mpesa❌ Failed Payment:
https://yourwebsite.com/payment-complete?status=failed&reference=ORDER12345&sessionId=MOP_abc123_ORDER12345&error=Payment+declined&paymentMethod=card⚠️ Cancelled Payment:
https://yourwebsite.com/payment-complete?status=cancelled&reference=ORDER12345&amount=100.00&paymentMethod=none&sessionId=MOP_abc123_ORDER12345When a user clicks "Cancel Payment" on the Mopay payment page, they are redirected with status=cancelled. The paymentMethod will be none if cancelled before selecting a payment method.
Complete Code Examples
Switch between working examples to see the same flow translated into the stack you already use.
// Create payment session
async function createPaymentSession(orderData) {
const response = await fetch("https://pay.mopay.co.ls/api/external/payment", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MOPAY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: orderData.total.toFixed(2),
reference: orderData.orderId,
redirectUrl: "https://yoursite.com/payment-complete",
description: `Order #${orderData.orderId}`,
customerEmail: orderData.customerEmail,
customerName: orderData.customerName,
}),
});
const data = await response.json();
if (!data.success) {
throw new Error(data.error);
}
return data;
}
// Usage
const payment = await createPaymentSession({
orderId: "ORD001",
total: 150.0,
customerEmail: "john@example.com",
customerName: "John Doe",
});
// Redirect user to payment page
window.location.href = payment.paymentUrl;One integration, the payment methods your customers already trust.
MoPay keeps the checkout surface consistent while each payment option stays visually grounded in its real brand.
Mobile money stays native for Lesotho customers, while card payments use the same hosted flow and session model documented across the rest of the API.
M-Pesa
Vodacom Lesotho mobile money checkout with a familiar USSD approval flow and locally optimized payment completion.
EcoCash
Econet EcoCash collections through the same MoPay session architecture, with a simple redirect and return flow.
Cards
Visa and Mastercard payments are processed through iVeri inside the hosted MoPay experience for a secure checkout.
Retrieving Session Details
Once you receive the customer back, use the session ID to confirm the final payment state from the API.
Recommended: Always verify the transaction status by retrieving the session details from the API. Do not rely solely on the redirect parameters as they can be tampered with.
GET https://pay.mopay.co.ls/api/external/session/v1/{sessionId}
curl -X GET "https://pay.mopay.co.ls/api/external/session/v1/MOP_abc123_ORDER12345" \
-H "Accept: application/json"Response:
{
"success": true,
"session": {
"id": "...",
"sessionId": "MOP_abc123_ORDER12345",
"amount": "100.00",
"reference": "ORDER12345",
"transactionStatus": "success",
"redirectUrl": "https://yoursite.com/payment-complete",
"status": "COMPLETED",
"selectedPaymentMethod": "mpesa",
"transactionId": "TXN123",
"createdAt": "2025-12-04T14:00:00Z",
"completedAt": "2025-12-04T14:05:00Z"
}
}Error Handling
Treat every response as data to validate. A simple success check upfront keeps your checkout flow predictable.
const response = await fetch("https://pay.mopay.co.ls/api/external/payment", {
// ...
});
const data = await response.json();
if (!data.success) {
// Handle error
console.error("Error:", data.error);
throw new Error(data.error);
}
// Proceed with data.paymentUrlSecurity Best Practices
Keep the integration server-led, validate outcomes from the API, and treat your API key like production infrastructure.
Never expose your API key
- • Store in environment variables
- • Only make API calls from server-side code
Validate payments server-side
- • Don't trust client-side redirect parameters alone
- • Use the session retrieval API to verify payment status
Use unique references
- • Generate unique order IDs
- • Prevents duplicate payments
Use HTTPS
- • Always use https:// for your redirectUrl
- • Protects customer data
Testing
Use low-value transactions and the real session lifecycle to confirm redirects, callbacks, and state handling before go-live.
- 1Get API key from https://mopay.co.ls
- 2Create session via POST https://pay.mopay.co.ls/api/external/payment
- 3Redirect user to the returned paymentUrl
- 4Handle redirect back to your redirectUrl with payment status