E-Mandate Applet
Overview
An e-mandate is a customer’s standing authorisation, given through their own bank, for you to debit their account directly. In Malaysia that authorisation is granted over FPX (Financial Process Exchange), the national payment gateway, and BigLedger stores the resulting mandate against the customer entity it belongs to.
bl_applet_hdr holds no row — of any status — whose
code, name or routerLink mentions a mandate or FPX (queried 2026-09-15). The e-mandate capability
described on this page is backend-only: it is reachable through the …/paygw/my/fpx/…
endpoints listed below and through whatever front end a tenant points at them. A front end exists
in the repository (blg-applet-core-akaun-platform-e-mandate-applet); it is not registered, so it
cannot be installed from the Applet Store, and the section
“The e-mandate front end” below records what it does and does not do.Where it fits
| Upstream | This | Downstream |
|---|---|---|
A settlement method of type FPX_EMANDATE, carrying the FPX seller credentials and signing certificate — settlement methods are documented on the Cashbook applet page | The mandate record on the customer entity | Collections taken against the mandate, settled through the Cashbook applet |
| A customer entity in Customer Maintenance — the mandate hangs off its entity line |
Customer Maintenance already lists FPX e-mandate among the settlement methods a customer can be given; this page is the reference for what that record actually is.
Screens and menus
There is no installed screen surface for a mandate. Every capability on this page is reached through
the …/paygw/my/fpx/… endpoints, and the one place a mandate becomes visible to a normal user is the
customer’s own record in Customer Maintenance,
where FPX e-mandate appears among the customer’s settlement methods. The screens described below
exist only in an unregistered repository build and cannot be installed.
The e-mandate front end
A repository named blg-applet-core-akaun-platform-e-mandate-applet builds an Angular applet under
the route eMandate, with a sidebar of E-Mandate Create · E-Mandate Update · E-Mandate
Terminate plus Settings and Personalization. It has no registry row, so it cannot be installed.
It is documented here because the screenshots and menu names circulating internally come from it,
and because what it does is not what its labels say.
Read from the repository at commit 3bf0ec05b921:
- Create is a real form — Online Direct Debit Enrolment, one Details tab, the fields Reference Number, Name, Email, Phone Number, ID Type, ID Number, Bank, Single / Multiple Signatory, Expiry Date, Extended Expiry Date, Max Amount per DD Transaction, Frequency, Initial Collection Option, Initial Collection Amount, Collection Date Start / End, Maximum Frequency, Purpose of Payment, Collection Amount.
- Only the CREATE button is wired. Save & Email, Save As Draft and Cancel carry no click handler at all. Nothing in the applet sends an e-mail to anybody.
- Update and Terminate are the same component,
GenericContainerComponent, and it lists internal sales orders —InternalSalesOrderService, columns Doc No · Location · Customer Name · Created Date · Created By · Status, with the Status column bound to a stock-balance field that a sales order does not have. There is no mandate listing, no amend screen and no terminate screen. - The applet’s create action does not call the FPX endpoints described above. It posts the raw form to a payment-gateway init-form service, and the object it assembles for FPX — the one carrying the transaction GUID, the bank id and the frequency — is built and then discarded.
Treat the three menu items as unfinished work, not as a workflow. The capability that is real is the API.
Configuration
Everything that has to be right before a mandate can be created lives in another applet. The
e-mandate front end in the repository has the two settings screens every Wavelet applet carries —
Settings → Field Settings and Default Selection, plus Personalization — and neither of them is
wired to anything: the toggles on the field-settings screen carry no form binding and its SAVE button
has no click handler, and the routed default-selection component is never given the applet container
it writes into, so its SAVE emits nothing. Nothing in the applet reads a setting key of any kind
(checked across blg-applet-core-akaun-platform-e-mandate-applet @ 3bf0ec05b921). Since the applet
has no registry row and cannot be installed, there is nowhere for a setting to be stored in the
first place.
So there is one configuration surface that matters, and it is the settlement method.
Before you can
- A settlement method whose
referenceisFPX_EMANDATE, carrying two extension rows —FPX_SELLER_IDandFPX_EXCHANGE_ID. A missing method fails withNO_FPX_STL_MTHD_FOUND; a missing extension withNO_FPX_STL_MTHD_DETAILS_FOUND. - A signing certificate on that settlement method. Upload it through
POST /core2/tnt/dm/erp/settlement-methods/current-fpx-public-cert-upload/{hdrGuid}; the next certificate in a rollover goes to…/next-fpx-public-cert-upload/{hdrGuid}. - The buyer’s bank must exist in
bl_fi_bank_hdrwithcountry_code = MYSand a bank code that matchesfpx_buyerBankId, or the request fails with Invalid buyer bank id. Fetch the live list fromGET /core2/tnt/dm/paygw/my/fpx/banks. - A payment reference number —
GET /core2/tnt/dm/paygw/my/fpx/pmt-ref-noincrements the tenant’sSETTLEMENT-METHOD-FPX-EMANDATEsequence and returns the next value.
Permissions
Every authenticated FPX endpoint — the AD request and all three read endpoints — accepts the
same set: the caller is a tenant OWNER or ADMIN, or holds one of
API_TNT_DM_PGW_FPX_OWNER, API_TNT_DM_PGW_FPX_ADMIN or API_TNT_DM_PGW_FPX_CREATE.
API_TNT_DM_PGW_FPX_MEMBER is defined in TntPgwPermissions but is not accepted by any endpoint on
this controller, so there is no read-only role for mandates: anyone who may look at a mandate may
also raise one.
The two AC callbacks take no token at all.
Fields
There is no working create form, so “the fields” here means two different things: the rows a mandate is made of once it exists, and the fields the AD request must carry to create one. Both are below. The form in the unregistered front end asks for a third, longer set — reference number, signatory, initial collection option, collection dates — and discards most of it; see The e-mandate front end.
How a mandate is stored
A mandate is not a document. It has no header, no lines, no signum, and it posts nothing to the
ledger. It is a set of rows on the customer’s master-entity record (EMandateContainer):
| Row | What it holds |
|---|---|
bl_fi_mst_entity_line | The mandate itself — one row per mandate, hanging off the customer entity |
bl_fi_mst_entity_ext with param_code = PMT_MTHD_E_MANDATE | The FPX request message as JSON (buyer name, e-mail, bank, ID, IBAN-encoded terms, amount, product description), and the mandate’s status |
bl_fi_mst_entity_ext with param_code = BL_FI_MST_ITEM_HDR_GUID | The link to the FPX settlement method that supplies the seller credentials and the signing key |
bl_fi_mst_entity_event | One row per exchange with FPX — NEW_APPLICATION_AD_REQ, NEW_APPLICATION_DIRECT_AC, NEW_APPLICATION_INDIRECT_AC — each carrying the message sent or received |
Because the terms live in the ext row’s JSON rather than in columns, there is no BigLedger-side validation of them beyond the checks listed under Creating a mandate.
What the request must carry
Every one of these is checked before anything is saved, and each throws its own message naming the field:
| Field | Meaning |
|---|---|
fpx_msgToken | 01 consumer, 02 or 03 business |
fpx_sellerOrderNo | Your reference for this mandate |
fpx_txnAmount | The ceiling per collection. Must be greater than zero |
fpx_buyerEmail, fpx_buyerName, fpx_buyerId | The payer and their identity document number |
fpx_buyerBankId | The bank code from the FPX bank list |
fpx_productDesc | What the collection is for |
fpx_buyerIban | The packed terms string — see below |
fpx_buyerIban is unpacked into six values, four of which are validated: application type must
be 01, 02 or 03; phone number must be present; maximum frequency must be present and
greater than zero; frequency mode must be present (DL daily, WK weekly, MT monthly, YR
yearly); effective date must be present. The expiry date is carried but not checked.
Three values are fixed by BigLedger and cannot be set per request: seller bank code 01, currency
MYR, and FPX message version 7.0. A mandate in any other currency is not supported.
Lifecycle and effects
A mandate is not a document. It has no server document type, no quantity or amount signum, and no
row in bl_fi_generic_doc_hdr, so none of the usual document machinery touches it: no journal
line, no stock movement, no e-Invoice, no knock-off, no VOID. Its whole life is the two-step
exchange below, and every step of that exchange happens inside the HTTP request that triggers it.
Nothing sweeps a pending mandate. There is no job processor for FPX or for mandates of any kind —
JobProcessorClassName names none at backend commit 2ca2a4492afa — no queue, no retry and no
scheduled reconciliation with FPX. A mandate whose confirmation never arrives stays at
NEW_APPLICATION_PENDING_AUTHORIZATION for as long as nobody looks at it, and it will not appear on
any report, because no report lists mandates.
The one thing that moves it is a read: GET …/fpx/e-mandate-event/{eventGuid} asks FPX for the
current status and writes the answer back when the stored event is still ACTIVE or
PENDING_AUTHORIZATION. Reconciling mandates is therefore something a person or an integration has
to do on a schedule of its own — the platform will not do it for you.
The AD / AC exchange
Every change to a mandate — creating it, amending it, ending it — is the same two-step exchange with FPX. BigLedger builds and signs an AD (authorisation request) message; FPX replies with an AC (authorisation confirmation) message, either straight back to the server or through the customer’s browser.
You post the mandate to
POST /core2/tnt/dm/paygw/my/fpx/ad-request-messagewith anEMandateContainerbody. BigLedger validates it, saves it if this is a new application, records anAD_REQevent, and returns the signed request message.The signed message is submitted to FPX, which takes the customer to their own bank to approve it.
FPX confirms, by one of two routes:
POST /core2/tnt/dm/paygw/my/fpx/direct-ac/{tenantCode}— server to server. Returns JSON.POST /core2/tnt/dm/paygw/my/fpx/indirect-ac/{tenantCode}— the customer’s browser is redirected here. Returns HTTP 302 to a status page.
Both are anonymous endpoints — no login token. They are authenticated by the
fpx_checkSumsignature on the message, and a mismatch fails withCLIENT_FPX_CHECKSUM_VERIFICATION_FAILED.BigLedger updates the mandate from the confirmation: it stamps the AD event with the outcome, records the AC as a second event, and rewrites the mandate’s status or terms.
What the three application types do
The type is not a separate field — it is the first two characters of fpx_buyerIban, which is a
packed string rather than a bank account number.
| Code | Type | Effect on a successful confirmation |
|---|---|---|
01 | New application | The mandate row is created before the AD request is sent, then its status is set to NEW_APPLICATION_<outcome> |
02 | Maintenance | The stored e-mail, amount and terms are overwritten from the request. The status is not changed — a maintained mandate keeps whatever status its new application left it with |
03 | Termination | The status is set to TERMINATION_<outcome>, but only if the outcome was not UNSUCCESSFUL |
Maintenance and termination both require the mandate to already exist; if it does not, the request
fails with EMANDATE_GUID_DOES_NOT_EXIST.
The outcome comes from one FPX field
fpx_debitAuthCode on the confirmation decides everything:
fpx_debitAuthCode | Outcome |
|---|---|
00 | SUCCESSFUL |
99 | PENDING_AUTHORIZATION |
| anything else | UNSUCCESSFUL |
Creating a mandate
Creating, amending and terminating a mandate are the same exchange with a different application type
in fpx_buyerIban, and all three are API calls — there is no working screen for any of them. Before
the first one will succeed you need the settlement method and certificate under
Before you can; the body has to carry the fields under
What the request must carry.
For a new application (01) the mandate rows are written to the customer entity before the AD
request is signed, so a customer whose bank later declines still has a mandate row — at
NEW_APPLICATION_UNSUCCESSFUL. Nothing removes it. For maintenance (02) and termination
(03) the mandate must already exist or the call fails with EMANDATE_GUID_DOES_NOT_EXIST.
Statuses
Two different status values are in play, and they are easy to confuse.
On the mandate (bl_fi_mst_entity_ext.status) — the application type and the outcome, joined
with an underscore:
| Status | What it means |
|---|---|
ACTIVE | The row exists but no FPX exchange has completed against it |
NEW_APPLICATION_PENDING_AUTHORIZATION | Sent to the bank; the customer has not finished approving |
NEW_APPLICATION_SUCCESSFUL | Authorised. This is the state a mandate you can collect against is in |
NEW_APPLICATION_UNSUCCESSFUL | The bank or the customer declined |
TERMINATION_PENDING_AUTHORIZATION | Termination sent, not yet confirmed |
TERMINATION_SUCCESSFUL | Ended |
On each event (bl_fi_mst_entity_event.status) — ACTIVE, SUCCESSFUL,
PENDING_AUTHORIZATION, NO_TRANSACTIONS_FOUND or UNSUCCESSFUL.
There is no expiry status and no rejection status. An expiry date is carried inside the packed
fpx_buyerIban string and is enforced by the bank, not by a BigLedger status transition; a decline
is …_UNSUCCESSFUL.
GET …/fpx/e-mandate-event/{eventGuid} does not simply return what
is stored: if the underlying AD event is still ACTIVE or PENDING_AUTHORIZATION, BigLedger asks
FPX for the current status (an AE enquiry) and writes the answer back before replying. A read
of a pending mandate is therefore also a refresh of it.Related applets
A mandate is not a document, so there is no document before it and none after it. Two applets own the halves of it, and both are places you will have to visit before an AD request will succeed.
| Applet | Why you end up there |
|---|---|
| Customer Maintenance | The mandate is rows on a customer’s entity record, so every mandate starts as a customer created here. This is also the only screen in the product where the existence of a mandate shows: FPX e-mandate sits among the customer’s settlement methods, with nothing behind it explaining what was stored. |
| Cashbook | Settlement methods are documented on the Cashbook page, and the FPX_EMANDATE method is what carries the seller id, the exchange id and the signing certificate. Without it the AD request fails at the first check with NO_FPX_STL_MTHD_FOUND. Collections taken against a mandate also settle through the cashbook. |
Nothing else reads a mandate. It posts no journal, touches no document, and no report in the product lists mandates — which is why the only way to see one today is to read the customer’s entity rows.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| bl_fi_mst_entity_ext for PMT_MTHD_E_MANDATE not found | The container was posted without the ext row that holds the FPX message | Build the container with both ext rows — the mandate JSON and the settlement-method link |
| bl_fi_mst_entity_ext for BL_FI_MST_ITEM_HDR_GUID not found | The mandate is not linked to a settlement method | Add the link ext row before requesting the AD message |
NO_FPX_STL_MTHD_FOUND / NO_FPX_STL_MTHD_DETAILS_FOUND | The linked settlement method is missing, or has no FPX_SELLER_ID / FPX_EXCHANGE_ID | Create the FPX_EMANDATE settlement method and fill both extension values |
| Invalid buyer bank id | fpx_buyerBankId does not match a Malaysian bank row | Take the code from GET …/fpx/banks, not from the customer |
CLIENT_FPX_CHECKSUM_VERIFICATION_FAILED on a callback | The certificate used to sign does not match the one FPX verified against | Check which certificate the settlement method is serving — current or next |
EMANDATE_GUID_DOES_NOT_EXIST on an amend or terminate | Application type 02 or 03 sent for a mandate that was never created | Create the mandate with type 01 first |
A mandate sits at NEW_APPLICATION_PENDING_AUTHORIZATION | The customer has not finished approving at their bank, or FPX has not confirmed | Read the event — the read triggers an enquiry to FPX and writes back the current answer |
Related documentation
- Customer Maintenance applet — where the customer entity the mandate hangs off is created
- Cashbook applet — where collections land
- Applet Store — how an applet that does have a registry row is installed
- Complete Applet Catalog — every applet that can be installed today