Docs
Documentation
Documentation Payment Operations/hosted Payment Page

Payment Operations - Hosted Payment Page

Simple payment integration with our pre-built hosted payment solution

Overview

The Hosted Payment Page API enables a streamlined payment experience where customers can select their preferred bank after the payment session is initialized. This approach provides better user experience compared to pre-selecting banks, allowing customers to choose from available banking options during checkout.

Integration Flow

The hosted payment page integration follows a simple redirect-based flow that minimizes the integration complexity on your end while providing a secure and user-friendly payment experience.

Flow Diagram

sequenceDiagram
    participant M as Merchant
    participant Z as ZenPay API
    participant C as Customer
    participant B as Bank (FPX)

    M->>Z: POST /v1/checkout-sessions (Create Session)
    Z-->>M: Session ID & Checkout URL
    M-->>C: Redirect to Checkout URL

    C->>Z: GET /v1/checkout-sessions/{id}/checkout
    Z-->>C: Checkout Page (Bank Selection)

    C->>Z: Select Bank & Confirm Payment
    Z->>B: Initiate FPX Payment Flow
    B-->>C: Bank Authentication & Payment

    B-->>Z: Payment Result (Success/Failed)
    Z->>M: Webhook Notification (callback_url)
    Z-->>C: Redirect to return_url/decline_url
                

Step-by-Step Integration

  1. Create Checkout Session - Initialize payment session with order details
  2. Redirect Customer - Send customer to the provided checkout URL
  3. Bank Selection - Customer selects preferred bank on checkout page
  4. Payment Processing - Customer completes payment through FPX
  5. Notification - Receive payment status via webhook
  6. Customer Return - Customer redirected to success/failure page

This endpoint requires Signature Authentication, IP Whitelisting, and is subject to Rate Limiting.

Request

Http Method & URL

POST /v1/checkout-sessions

Headers

Header Type Required Description
Content-Type
string Yes application/json
X-Signature
string Yes HMAC-SHA256 signature for request authentication

Signature Generation: Refer to the Signature Generation section for detailed steps on generating the X-Signature header value.

Timestamp Validation: Requests with timestamps older than 5 minutes will be rejected. Ensure your system clock is synchronized with UTC.

Parameters

Parameter Type Required Description
biller_code
string Yes Your merchant biller code
order_id
string Yes Unique order identifier (max 50 chars)
email
string Yes Customer email address (valid email format)
amount
string Yes Payment amount (decimal, 2 decimal places, e.g., "150.50")
callback_url
string Yes URL for payment status notifications (webhooks)
return_url
string No URL to redirect after successful payment
decline_url
string No URL to redirect after failed/declined payment
currency
string Yes Currency code ("MYR" only)
timestamp
string Yes ISO 8601 timestamp (within 5 min past, 1 min future)

Request Body Example

{
  "biller_code": "202500039",
  "order_id": "ORDER123456",
  "email": "customer@example.com",
  "amount": "150.50",
  "callback_url": "https://merchant.com/payment/callback",
  "return_url": "https://merchant.com/payment/success",
  "decline_url": "https://merchant.com/payment/failed",
  "currency": "MYR",
  "timestamp": "2025-01-15T10:30:00Z",
}

Response

Success Response (200)

{
    "success": true,
    "message": "Checkout session created successfully",
    "data": {
        "id": "cs_abc123def456ghi789",
        "status": "open",
        "amount": "150.50",
        "currency": "MYR",
        "order_id": "ORDER123456",
        "email": "customer@example.com",
        "url": "https://api.zenpay.com/v1/checkout-sessions/cs_abc123def456ghi789/checkout",
        "expires_at": "2025-01-15T11:30:00Z",
        "created_at": "2025-01-15T10:30:00Z",
        "updated_at": "2025-01-15T10:30:00Z"
    }
}

Error Response (400/401/500)

{
    "success": false,
    "message": "Validation failed",
    "errors": [
        {
            "field": "email",
            "message": "Invalid email format"
        }
    ]
}

Checkout Page Response

The checkout page endpoint returns an HTML page with:

  • Payment amount and order details
  • Bank selection interface (retail/corporate)
  • Real-time bank list fetching
  • Responsive design for mobile/desktop
  • Session expiration countdown

API Endpoints

Create Checkout Session

Create a new checkout session with payment details. The customer can then select their preferred bank on the checkout page.

Endpoint: POST /v1/checkout-sessions

Authentication: HMAC-SHA256 signature

Get Checkout Session

Retrieve details of an existing checkout session.

Endpoint: GET /v1/checkout-sessions/{session_id}

Authentication: Not required

Serve Checkout Page

Serves the interactive checkout page where customers can select their bank and complete payment.This url will be returned in the response of the Create Checkout Session endpoint from url field.

Endpoint: GET /v1/checkout-sessions/{session_id}/checkout

Authentication: Not required

Frontend Integration

Redirecting to Checkout

After creating a checkout session, redirect the customer to the provided checkout URL:

// After creating checkout session
const response = await fetch("/v1/checkout-sessions", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-Signature": signature,
    },
    body: JSON.stringify(requestData),
});

const session = await response.json();
if (session.success) {
    // Redirect customer to checkout page
    window.location.href = session.data.url;
}

Checkout Page Features

The checkout page provides:

  • Session Validation - Checks if session exists and is valid
  • Payment Details Display - Shows amount, order ID, and expiration
  • Bank Selection - Dynamic list of available banks
  • Bank Type Toggle - Retail vs Corporate banking options
  • Payment Processing - Handles FPX form submission
  • Responsive Design - Works on mobile and desktop

Handling Returns

After payment completion, customers are redirected to:

  • return_url - For successful payments
  • decline_url - For failed/declined payments

Handle these redirects in your application:

// Check URL parameters for payment result
const urlParams = new URLSearchParams(window.location.search);
const status = urlParams.get("status");
const payrefId = urlParams.get("payref_id");

if (status === "success") {
    // Payment successful - show success page
    showPaymentSuccess(payrefId);
} else if (status === "failed") {
    // Payment failed - show error page
    showPaymentFailed(payrefId);
}

Error Handling

Session Errors

{
    "success": false,
    "message": "Invalid or expired session",
    "errors": [
        {
            "field": "session_id",
            "message": "Session has expired"
        }
    ]
}

Validation Errors

{
    "success": false,
    "message": "Validation failed",
    "errors": [
        {
            "field": "amount",
            "message": "Amount must be greater than 0"
        },
        {
            "field": "email",
            "message": "Invalid email format"
        }
    ]
}
Was this helpful?
Docs

API

Copyright © Zenpay. All rights reserved.