Checkout Popup
The Checkout Popup is a pre-built, Mazad-hosted payment UI that opens as an overlay on your website. Users confirm payment from their embedded wallet without leaving your page.
Payment flow
Your server creates a checkout session
POST /embedded/checkout/sessions with amount, currency, and user ID. You receive a session_token.
Your frontend opens the popup
Call MazadCheckout.open({ sessionToken }) in the browser. A modal overlay appears.
User reviews and confirms
The popup shows the amount, merchant name, and balance. User taps "Pay Now" or enters their PIN.
Mazad processes the payment
Funds are debited from the user wallet and held in escrow (or settled immediately, depending on your config).
Popup closes, callback fires
The onSuccess / onError callback fires in your frontend. A webhook is sent to your server.
1. Install the JS SDK
Add the Mazad Checkout script to your HTML. This exposes the global MazadCheckout object.
<!-- Add before closing </body> tag -->
<script src="https://cdn.mazad.com/checkout/v1/mazad-checkout.min.js"></script>2. Create a checkout session
Create a session on your server. This returns a short-lived token that your frontend uses to open the popup.
/embedded/checkout/sessionsCreate a new checkout session. The session token expires after 30 minutes if not used.
Request Body
| Name | Type | Required | Description |
|---|---|---|---|
| user_id | string | required | The mazad_user_id or external_id of the payer. |
| amount | integer | required | Payment amount in smallest currency unit (e.g., 25000 = 25 IQD). |
| currency | string | required | ISO 4217 currency code. Must match a currency the user wallet supports. |
| description | string | optional | Shown to the user in the popup. Max 256 characters. |
| reference | string | optional | Your order/invoice ID. Returned in webhooks for reconciliation. |
| capture_mode | string | optional | "automatic" (default) settles immediately. "manual" places a hold requiring a later capture call. |
| redirect_url | string | optional | URL to redirect after payment in mobile browsers where popup is not supported. |
| metadata | object | optional | Arbitrary key-value pairs passed through to webhooks. Max 20 keys. |
| expires_in | integer | optional | Session TTL in seconds. Min 300 (5 min), max 1800 (30 min). Default 1800. |
curl -X POST https://wallet.e-mazad.store/api/v1/embedded/checkout/sessions \
-H "Authorization: Bearer sk_sandbox_abc123" \
-H "Content-Type: application/json" \
-d '{
"user_id": "usr_12345",
"amount": 25000,
"currency": "IQD",
"description": "Order #1234 - Premium Widget",
"reference": "order_1234",
"capture_mode": "automatic",
"metadata": {
"order_id": "1234",
"sku": "widget-premium"
}
}'Session response
{
"success": true,
"data": {
"session_id": "cs_9f8e7d6c5b4a",
"session_token": "cs_live_tok_a1b2c3d4e5f6g7h8i9j0",
"amount": 25000,
"currency": "IQD",
"status": "pending",
"expires_at": "2026-03-20T15:00:00Z",
"payment_id": null,
"created_at": "2026-03-20T14:30:00Z"
}
}3. Open the popup
In your frontend, call MazadCheckout.open() with the session token returned from your server.
// After receiving session_token from your backend
MazadCheckout.open({
sessionToken: 'cs_live_tok_a1b2c3d4e5f6g7h8i9j0',
// Optional: customize appearance
theme: 'light', // 'light' | 'dark' | 'auto'
locale: 'ar', // 'ar' | 'en' | 'ku'
// Callbacks
onSuccess: function(result) {
console.log('Payment succeeded!', result.payment_id);
// result.payment_id - "pay_..."
// result.amount - 25000
// result.currency - "IQD"
// result.reference - "order_1234"
// Redirect to success page or update UI
window.location.href = '/order/1234/success';
},
onError: function(error) {
console.error('Payment failed:', error.code, error.message);
// error.code - "insufficient_funds" | "session_expired" | ...
// error.message - Human-readable error
showErrorToast(error.message);
},
onClose: function() {
// User closed the popup without completing payment
console.log('Popup closed by user');
},
});Popup screens
The checkout popup guides the user through a simple two-step flow. Here is what each screen looks like:
+----------------------------------+ | Mazad Checkout | | | | [Your Brand Logo] | | | | Pay to: Acme Store | | Amount: 25,000 IQD | | Description: Order #1234 | | | | Wallet Balance: 150,000 IQD | | | | +----------------------------+ | | | Pay Now | | | +----------------------------+ | | | | Secured by Mazad Wallet | +----------------------------------+
+----------------------------------+ | Confirm Payment | | | | Amount: 25,000 IQD | | | | Enter your 4-digit PIN: | | | | [ * ] [ * ] [ ] [ ] | | | | +--- --- --- --- --- ---+ | | | 1 || 2 || 3 || 4 || 5 || 6| | | +--- --- --- --- --- ---+ | | | 7 || 8 || 9 || || 0 || <| | | +--- --- --- --- --- ---+ | | | | Forgot PIN? | +----------------------------------+
+----------------------------------+ | | | [Checkmark] | | | | Payment Successful! | | | | 25,000 IQD | | to Acme Store | | | | Ref: pay_x1y2z3 | | | | +----------------------------+ | | | Done | | | +----------------------------+ | | | +----------------------------------+
+----------------------------------+ | | | [X] | | | | Insufficient Funds | | | | Your balance is 10,000 IQD | | but 25,000 IQD is required. | | | | +----------------------------+ | | | Top Up Wallet | | | +----------------------------+ | | +----------------------------+ | | | Cancel | | | +----------------------------+ | | | +----------------------------------+
Branding
Customize the popup appearance from your Mazad merchant dashboard. The following options are available:
| Setting | Description |
|---|---|
| Logo | Your brand logo displayed at the top of the popup. Recommended: 200x60px PNG with transparent background. |
| Brand color | Primary button color. Must meet WCAG AA contrast ratio against white text. |
| Merchant name | Displayed as "Pay to: {name}" in the review screen. |
| Support URL | Link shown in error screens so users can contact your support team. |
Security model
Session tokens are single-use
Each session token can only be used once to open the popup. After the popup closes (success, error, or dismissal), the token is invalidated.
Popup runs on Mazad domain
The popup iframe loads from checkout.mazad.com. Your page never has access to the user PIN or wallet credentials.
Amount is server-defined
The payment amount is locked when you create the session on your server. The frontend cannot modify it. This prevents client-side tampering.
Always verify server-side
Do not trust the onSuccess callback alone. Always verify the payment status via the webhook or by polling GET /embedded/payments/{id} from your server.
Never trust the frontend
onSuccess callback is a UX convenience for showing the user a success message. Always confirm the payment status from your backend via webhook or API polling before fulfilling the order.