Overview#
MelakaPay now exposes another generic payment entry points:
- External API Controller (
/generic/*) β a JSON API for external systems to initiate payments, receive responses, requery transactions, view receipts, and download PDFs.
Base URLs#
Staging: https://melakapaystg.melaka.gov.my
Production: https://melakapay.melaka.gov.my
Authentication#
API / external payments:
merchant_code(request body orX-Merchant-Codeheader) andapi_key(Bearer token orapi_keybody parameter). The/generic/*API routes are excluded from CSRF validation so they can be called by external systems.Merchants and their API keys are registered in
config/generic.php:php'cmi-zoo' => [ 'name' => 'Zoo Melaka', 'id' => 26, 'api_keys' => [ env('GENERIC_MERCHANT_CMI_ZOO_KEY', 'a08ec971b56d3c85d4026b58abf9088398346552760525019b988a0a8726959a'), ], ],
Endpoints Summary#
| Endpoint | Method | Description |
|---|---|---|
| `/generic/check` | GET | Validate merchant credentials and API connectivity |
| `/generic/request` | POST | Initiate a payment from an external system |
| `/generic/response` | POST | Payment gateway response handler (internal) |
| `/generic/receipt/{id}` | GET | View payment receipt by transaction ID |
| `/generic/requery/{transaksi_id}` | GET | Requery a transaction status from EPIC |
| `/generic/download/{id}` | GET | Download receipt/statement PDF |
| `/generic/debug` | GET | Debug page to simulate a payment response |
| `/generic/simulate` | GET | Simulate page to test `/generic/request` |
1. Check Connectivity#
Validates the supplied merchant_code and API key.
Endpoint: GET /generic/check
Headers#
| Header | Value | Required |
|---|---|---|
| `Authorization` | `Bearer | Yes |
| `X-Merchant-Code` | ` | Alternative to body |
| `Content-Type` | `application/json` | No |
Request Body#
| Field | Type | Required | Description |
|---|---|---|---|
| `merchant_code` | string | **Yes** | Agency merchant code |
| `api_key` | string | **Yes** | API key (if not using Bearer token) |
Example#
curl -X GET https://melakapaystg.melaka.gov.my/generic/check \
-H "Authorization: Bearer <API_KEY>" \
-H "X-Merchant-Code: cmi-zoo"
Response#
{
"status": true,
"message": "Connection successful",
"data": {
"merchant_code": "cmi-zoo",
"timestamp": "2026-07-24T16:00:00+08:00",
"environment": "local"
}
}
Error Responses#
| HTTP Code | Response |
|---|---|
| 401 | { "status": false, "message": "Missing merchant_code or API key" } |
| 401 | { "status": false, "message": "Merchant code not registered" } |
| 401 | { "status": false, "message": "Unauthorized - invalid API key for merchant" } |
2. Initiate API Payment#
Starts a generic payment session. The response is an HTML payment page that the payer completes in a browser.
Endpoint: POST /generic/request
Headers#
| Header | Value | Required |
|---|---|---|
| `Authorization` | `Bearer | Yes |
| `Content-Type` | `application/json` | Yes |
| `X-Merchant-Code` | ` | Alternative to body |
Request Body#
| Field | Type | Required | Description |
|---|---|---|---|
| `merchant_code` | string | **Yes** | Agency merchant code |
| `trans_id` | string | **Yes** | External transaction reference |
| `amount` | numeric | **Yes** | Total payment amount in RM |
| `service` | string | **Yes** | Service name shown to the payer |
| `description` | string | **Yes** | Payment description |
| `callback_url` | url | **Yes** | URL that receives the payment result |
| `redirect_url` | url | **Yes** | URL to redirect the payer after payment |
| `name` | string | No | Payer name |
| `email` | No | Payer email for receipt delivery | |
| `ic_no` | string | No | Payer IC / username |
| `address_1` | string | No | Address line 1 |
| `address_2` | string | No | Address line 2 |
| `city` | string | No | City |
| `postcode` | string | No | Postcode |
| `state` | string | No | State |
| `phone_no` | string | No | Phone number |
| `extra` | object | No | Additional fields stored in the generic details table |
Details Storage#
The system first tries to store request details in an agency-specific table derived from the merchant code (e.g. cmi_details). If that table does not exist, the data is written to generic_details instead. New integrations therefore do not need a dedicated details table.
Example#
curl -X POST https://melakapaystg.melaka.gov.my/generic/request \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_KEY>" \
-d '{
"merchant_code": "cmi-zoo",
"trans_id": "ZOO-77-20260815120000",
"amount": "150.00",
"service": "Tiket Zoo Melaka",
"description": "Bayaran tiket masuk Zoo Melaka",
"callback_url": "https://your-system.example.com/melakapay/callback",
"redirect_url": "https://your-system.example.com/payment/complete",
"name": "LUKMANUL HAKIM",
"email": "email@user.example",
"ic_no": "920722055401",
"phone_no": "0135871622",
"extra": {
"kod_hasil": "H0272499",
"caj_bayaran": "150.00",
"no_permohonan": "BILL-PROC-0056",
"bill_type": "processing_fee",
"invoice_no": "BILL-PROC-0056",
"company_name": "NAMA COMPANY SDN BHD",
"company_no": "9811223-X"
}
}'
Success Response#
Status Code: 200 OK
Returns the MelakaPay payment page HTML. The payer selects a payment method and is redirected to the FPX/payment gateway.
Error Responses#
| HTTP Code | Response |
|---|---|
| 400 / 401 | `{ "status": false, "message": "Missing merchant_code or API key" }` |
| 400 | `{ "status": false, "message": " |
3. Payment Response (Internal)#
This endpoint is called by the FPX/payment gateway after the payer completes the transaction. It is not called directly by merchants.
Internal Endpoint: POST /generic/response
What Happens#
- MelakaPay receives the payment result from the gateway.
- The transaction and receipt records are updated.
- A callback job is dispatched to the
callback_urlsupplied in the original request. - On success (
STATUS = 1), a receipt email job is dispatched if an email was provided. - The gateway/user is redirected to
/generic/receipt/{transaction_id}.
Gateway Fields#
| Field | Description |
|---|---|
| `STATUS` | `0` = failed, `1` = success, `2` = cancelled, `3` = pending |
| `PAYMENT_MODE` | `fpx`, `fpx1`, `cc`, `dnqr`, `wallet` |
| `MERCHANT_CODE` | Merchant code |
| `TRANS_ID` | MelakaPay transaction ID |
| `RECEIPT_NO` | Receipt number |
| `PAYMENT_TRANS_ID` | Gateway transaction ID |
| `PAYMENT_DATETIME` | Transaction date/time |
| `AMOUNT` | Paid amount |
| `BUYER_BANK` | Payer's bank |
| `BUYER_NAME` | Payer's name |
| `MERCHANT_ORDER_NO` | EPS seller order number |
4. Requery Transaction#
Queries the EPIC database for a transaction status and updates the local record.
Endpoint: GET /generic/requery/{transaksi_id}
Headers#
| Header | Value | Required |
|---|---|---|
| `Authorization` | `Bearer | Yes |
| `X-Merchant-Code` | ` | Alternative to body |
Example#
curl -X GET https://melakapaystg.melaka.gov.my/generic/requery/ZOO-77-20260815120000 \
-H "Authorization: Bearer <API_KEY>" \
-H "X-Merchant-Code: cmi-zoo"
Response#
{
"success": true,
"data": { ... },
"message": "Successfully get the transaction from EPIC. Update status: success"
}
5. View Receipt#
Displays the receipt page for a completed transaction.
Endpoint: GET /generic/receipt/{id}
Example#
curl -X GET https://melakapaystg.melaka.gov.my/generic/receipt/12345
Response#
HTML receipt page with transaction details and a back-to-merchant button.
6. Download Receipt#
Downloads the receipt or statement PDF for a transaction.
Endpoint: GET /generic/download/{id}
Example#
curl -X GET https://melakapaystg.melaka.gov.my/generic/download/12345 \
-o MelakaPay-Receipt-12345.pdf
Response#
PDF stream (Content-Type: application/pdf).
7. Debug / Simulate#
These are browser-based testing pages.
| Endpoint | Description |
|---|---|
| `GET /generic/debug` | Simulate a payment gateway response |
| `GET /generic/simulate` | Build and send a test `/generic/request` payload |
8. Callback Notification#
After the payment result is processed, MelakaPay POSTs a payload to the callback_url supplied in the original request.
Callback Payload#
| Field | Type | Description |
|---|---|---|
| `transaction_id` | string | MelakaPay internal transaction ID |
| `trans_id` | string | Original `account_id` / `trans_id` supplied |
| `status` | string | Numeric status: `0` / `1` / `2` / `3` |
| `payment_status` | string | Human-readable status |
| `receipt_no` | string | Receipt number if successful |
| `payment_datetime` | string | Payment date and time |
| `buyer_name` | string | Name of payer |
| `amount` | string | Total amount paid |
| `payment_mode` | string | Payment method |
| `fpx_charge` | string | FPX transaction fee |
| `buyer_bank` | string | Payer's bank |
| `fpx_transaction_no` | string | FPX reference number |
| `seller_order_no` | string | MelakaPay merchant order number |
| `merchant_code` | string | Merchant code |
| `description` | string | Payment description |
| `service` | string | Service name |
Example Successful Callback#
{
"transaction_id": "12345",
"trans_id": "ZOO-77-20260815120000",
"status": "1",
"payment_status": "Berjaya",
"receipt_no": "RCP-001234",
"payment_datetime": "2026-07-24 15:30:00",
"buyer_name": "LUKMANUL HAKIM",
"amount": "150.50",
"payment_mode": "FPX (Individual)",
"fpx_charge": "0.50",
"buyer_bank": "Maybank2u",
"fpx_transaction_no": "FPX-TXN-99887766",
"seller_order_no": "EPX-20260724153000",
"merchant_code": "cmi-zoo",
"description": "Bayaran tiket masuk Zoo Melaka",
"service": "Tiket Zoo Melaka"
}
Payment Flow Summary#
ββββββββββββββββββββ POST /generic/request ββββββββββββββββ
β β ββββββββββββββββββββββββββββββββββΊβ β
β External System β (merchant_code + api_key + β MelakaPay β
β β trans_id, amount, callback_url) β β
β β βββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββ HTML payment page ββββββββ¬ββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Payer selects bank / payment method β
β & submits to FPX gateway β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββ
β FPX Gateway β
ββββββββ¬ββββββββ
β
βΌ
ββββββββββββββββ
β POST /genericβ
β /response β
ββββββββ¬ββββββββ
β
POST callback_url β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬ββββββββ΄ββββββββ
(payment result payload) βΌ βΌ
βββββββββββββ ββββββββββββββββ
β Receipt β β Email with β
β Page β β PDF Receipt β
βββββββββββββ ββββββββββββββββ
Files Created/Modified#
| File | Description |
|---|---|
| `app/Http/Controllers/Payment/GenericPaymentController.php` | Portal generic payment processing controller |
| `app/Http/Controllers/API/GenericAPIController.php` | External generic API controller |
| `config/generic.php` | Merchant credentials and agency metadata for API access |
| `database/migrations/2026_08_15_000001_create_generic_details_table.php` | Fallback generic payment details table |
| `app/Http/Requests/Payment/GenericPaymentRequest.php` | Validation rules for portal generic payments |
| `app/Jobs/PostGenericCallback.php` | Job for dispatching external merchant callbacks |
| `resources/views/user/generic/*.blade.php` | Generic payment, receipt, debug, and simulate views |
| `routes/web.php` | Route registration for `/generic/*` and `/payment/process/generic` |
| `docs/generic-payment-api.md` | This documentation |
| `docs/generic-payment-api.postman_collection.json` | Importable Postman collection |
Changelog#
Version 1.2.1 (2026-08-17)#
- Removed unused enpoint
Version 1.2.0 (2026-08-15)#
- Moved API merchant credential validation from
agencies/agency_servicestoconfig/generic.php. - Added
generic_detailsfallback table for merchants without an agency-specific details table. - Updated
GenericPaymentControllerandGenericAPIControllerto usegeneric_detailsas fallback.
Version 1.1.0 (2026-07-24)#
- Added external generic API controller (
GenericAPIController) with/generic/*endpoints. - Added credential validation against
agenciesandagency_services. - Added
receipt,requery,download,debug, andsimulateAPI endpoints. - Added
PostGenericCallbackjob for asynchronous merchant notifications.
Version 1.0.0 (2026-07-24)#
- Initial generic agency payment controller based on
BksaController. - Supports
agency_idormerchant_codeagency resolution. - Supports portal (
source=portal) and API (source=api) payment flows. - Auto-derives agency-specific details table from merchant code.
- Accepts arbitrary
detailsandfpx_datapayloads for agency extensibility.