Skip to content

Storefront E-Invoice Request

Let a shopper who paid at a branch or on your web store claim their own e-invoice from the storefront, with no account needed. The sale leaves your monthly consolidated e-invoice and goes to LHDN in the shopper’s name, with no approval step and no notice to you: the Portal Request list in My E-Invoice Admin is where you see it, and a failed row there needs somebody.

Overview

A shopper who paid at a branch or on the web store can ask for their own Malaysian LHDN e-invoice from the storefront itself — no account required. They type the cash-bill number with either the PIN printed on the receipt or the amount and date, confirm it is their transaction, fill in their identification number and tax identification number (TIN), and the sale is taken out of the merchant’s monthly consolidated e-invoice and submitted to LHDN as an individual one in their name.

That path is a widget in the Cross Platform Commerce storefront app (the web and mobile Customer Portal), not a screen in an applet. It is placed on a Customer Portal page from CP Commerce Admin, and everything it does runs through a handful of server calls and one queued request run.

This page documents the storefront path only. The merchant’s side of the same pipeline — the pools, the submission and validation queues, the cancellation requests — is the My E-Invoice Admin applet. The equivalent request flow for a tenant-side buyer account, in a different applet and a different repository, is the MY E-Invoice Portal applet.

Where it fits

PositionApplet / systemWhy
ModuleE-Commerce, E-InvoiceA storefront feature that writes into the e-invoice pipeline.
Placed fromCP Commerce AdminWebsite → Layout Instance → Nodes → Widget ID → EINVOICE WIDGET.
Runs inThe Customer Portal web site and mobile appThe widget itself.
UpstreamPOS General, Shopping CartThe cash bill or sales invoice the shopper is asking about, and the pool row it produced.
DownstreamMy E-Invoice AdminThe request lands as a pool update and a submission-queue row that the operator sees there.
Buyer recordsCustomerA signed-in shopper’s identification, TIN and e-invoice address are written back to their customer entity; a guest’s are not.
SiblingMY E-Invoice PortalThe same request, made from a tenant-side buyer account instead of a storefront.

Screens and menus

There is no menu. The widget renders wherever the layout puts it, usually on a page whose code is E-Invoice — the tracking e-mail BigLedger sends links to https://<website code>/page/E-Invoice.

The widget draws a four-item left rail on desktop and a four-item tab strip on mobile. Three of the four are hidden unless the shopper is signed in. Below 550 px, and between 768 px and 1120 px, the rail labels shorten — Request E-Invoice becomes Request, E-Invoice Cancellation becomes Cancellation, and so on.

Request E-Invoice (the search and the request) is open to everyone. Requested E-Invoices is shown to signed-in shoppers, and to a guest only when the page address carries the key and email of the tracking link BigLedger e-mailed them — a guest who closes that e-mail has no other way back to their requests. E-Invoice Cancellation and E-Invoice History are for signed-in shoppers only, so a guest cannot ask to cancel an e-invoice from the storefront at all.

A Help Centre row sits at the bottom of the rail. It is a label with no click handler and no destination.

Request E-Invoice

Two search modes, as sub-tabs:

  • By Date Amount (the default) — Cash Bill/Invoice No., Amount, Transaction Date.
  • By Pin — Cash Bill/Invoice No., Pin. Hidden when the widget’s hideByPin parameter is true.

The transaction-date picker does not accept arbitrary dates; see The request window below.

The result is one card (grid view) or one row (list view), showing invoice number, transaction date, currency and amount. Which number is shown as “invoice number” is controlled by the widget’s einvoiceNoDisplayConfig parameter.

Three outcomes:

What came backWhat the shopper sees
A pool row that has not been submittedThe result card with a Request button.
A record that is already submitted, or has no pool row leftAn amber banner — “This invoice has already been submitted. No further requests can be made.” — above a read-only summary of Request Status, Submission Status, Validation Status, Submission Date and Validation Date. No Request button.
Nothing matchingA red box with the API’s message, or “Search failed. Please try again.”

When the widget’s exportPdfPublicAccess parameter is true and the record’s validation status is Valid, an Export button appears on this screen — for anyone who ran the search, signed in or not.

The request pop-up — Update E-Invoice Profile

Pressing Request opens a modal titled Update E-Invoice Profile. It opens for every guest, and for a signed-in shopper whose customer record is missing any of: TIN, identification number, identification type, e-invoice identification type, e-invoice identification value, e-mail, phone, or a billing/shipping address flagged as the default e-invoice address with address line 1, city, state, country and postal code all filled. A signed-in shopper with all of those already on file skips the modal and the request is sent straight away.

After the request

PathWhat the shopper sees
Signed inA modal — a tick, “Submission Successful”, “Thank you requesting for e-invoice. Your request will be processed.”, with Request More and Check Status buttons.
GuestA page message — “Your request will be processed.”
Either, on failure“Request already made by a user.”

That last message is shown for every failure of the request call, not only for a duplicate — an authorisation failure or a network error produces the same words.

Requested E-Invoices, Cancellation and History

All three are the same list component with different filters, each with a grid/list toggle, a search box (Search Invoice No/Cash Bill No), an After/Before date range and a status drop-down.

  • Requested E-Invoices — counters for All Invoices, In Queue, Validated, Validation Error.
  • E-Invoice Cancellation — All Invoices, Requested for Rejection, Cancelled.
  • E-Invoice History — All Invoices, In Queue, Validated, Validation Error, Requested for Rejection, Cancelled.

Each counter is a separate query, and what each one reads decides what the shopper should do about it:

CounterWhat it countsWhat it means
In QueueE-invoices whose document status is In Queue or Submitted, plus failed requests on a receipt in the batch or single-general poolEither LHDN has not seen it yet, or it has it and has not answered — or BigLedger tried and could not build it. All three sit under one number. A failed request on a receipt in the individual pool is not counted anywhere on this screen.
ValidatedDocument status ValidLHDN accepted it.
Validation ErrorDocument status Invalid — nothing elseLHDN examined the e-invoice and refused it on content. A request that BigLedger never sent is not counted here.
Cancelled / Requested for RejectionDocument status Cancelled; the rejection request’s own statusAs named.

So Validation Error always means the document reached LHDN and came back refused — which is the case the shopper cannot re-request, because the request behind it already went through (see Troubleshooting). A request that failed on BigLedger’s own side is folded into In Queue.

The guest version of Requested E-Invoices is a separate, simpler component: no counters, no filters, driven entirely by the key and email in the URL.

The details pop-up

The magnifier icon — always present on a grid card, and on a list row only in the requested, cancellation and history lists — opens a pop-up with invoice number, transaction date, amount and status. When the status is Valid it also renders the LHDN validation QR code, as a base64 PNG held on the record, and an Export button that downloads the rendered e-invoice as E-invoice-<company>-<document type>-<date>-<invoice no>.pdf. On an iOS or Android user-agent the file opens in a new tab instead of downloading, because mobile browsers do not honour the download attribute on blob URLs.

Cancellation

On a validated e-invoice, and only while a countdown of 72 hours from the validation date-time has not run out, a Request for Rejection button appears with the remaining time beside it. It opens a radio list of reasons — Wrong buyer details, Wrong invoice details, Others by default, overridable per widget — with a free-text box when Others is chosen. Once raised, the button is replaced by Requested for Rejection in red.

The countdown is drawn by the widget. Whether the backend independently refuses a late cancellation from this path is not established here.

Configuration

Before you can use it

PrerequisiteWhereWhy
The hostname carries a CP Commerce public keyHost Name record for the storefront’s domain, extension parameter SYS_AKN_WEB_CP_COMMERCE_PUBLIC_KEYWithout it the storefront cannot authenticate any call and every step of this flow fails with an authorisation error — see below.
The hostname carries a default tenant and a website GUIDSame record, SYS_DEFAULT_TENANT and SYS_AKN_WEB_CP_COMMERCE_CMS_WEBSITE_HDR_GUIDThe tenant code goes on every call; the website GUID identifies the site on the guest request and guest tracking calls, and an unknown one is rejected.
The company is configured for e-invoicing and its sales documents reach the poolsMy E-Invoice AdminThe search looks the shopper’s receipt up in the batch, single-general and individual pools, then in the to-IRB headers. A document that never reached a pool cannot be found.
Receipts carry a PIN, if you want the By Pin searchPrintable format on the selling documentThe PIN searched here is the one recorded on the document’s e-invoice pool entry.
An outgoing e-mail sender is configuredMessaging channel for the tenantThe guest tracking link is an e-mail. With no custom sender the platform default is used.

Placing the widget

CP Commerce Admin → Website → (select website) → Layout Instance → (select layout) → Nodes → (select or add a node) → Main → Widget ID.

The Widget ID drop-down is built by enumerating the shared widget catalogue, so the entry reads EINVOICE WIDGET and its stored value is e-invoice. The storefront resolves that value to the widget.

Widget parameters

The widget reads six parameters from its node’s widgetPlaceHolderConfig.param. Four of them work and two are inert. None of the six has a field in CP Commerce Admin: the widget is registered in the catalogue without a parameter form and the node editor has none for it, so the only way to set them is to edit the layout’s raw JSON on the node’s Json Params tab — which edits the whole layout instance, not the single node. This is recorded as a product finding.

ParameterWhat it controlsDefaultEffect when changed
hideByPinWhether the By Pin search sub-tab is offeredfalse — the tab is shownSet true on a storefront whose receipts carry no PIN, so shoppers are not sent down a search that can never match.
rejectionReasonsThe radio list in the cancellation-reason pop-upWrong buyer details, Wrong invoice details, OthersReplaces the list entirely. Only the literal value Others opens the free-text box, so keep it in the list.
einvoiceNoDisplayConfigWhich document number is displayed as the invoice numberserver_doc_1Accepts server_doc_1, client_doc_1…client_doc_5, running_no, doc_reference. If the chosen field is empty on a record, the widget falls back to the invoice number.
exportPdfPublicAccessWhether the Export button appears on the search result for an unauthenticated visitorfalseSet true to let anyone who can produce the invoice number plus PIN (or amount and date) download the rendered e-invoice PDF.
styleDeclared as colour, font and background—Inert. The values are read but never applied; the widget’s colours are hard-coded.

The public key is the whole guest path

The storefront has no anonymous session of its own. On start-up it looks its own hostname up and uses the hostname’s SYS_AKN_WEB_CP_COMMERCE_PUBLIC_KEY to authenticate every call it makes until someone signs in, at which point the user’s own sign-in takes over.

None of the calls in this flow needs the shopper’s own permissions — they need the storefront’s key. So a storefront whose hostname record is missing the public key shows the search form and fails every search with an authorisation error. That is the single most likely cause of “the e-invoice page does not work”.

The request window

The transaction-date picker in the By Date Amount search only accepts dates inside a window derived from the company’s e-invoice request extension period setting:

  • No value set — only dates in the current calendar month are selectable.
  • A day-of-month value, and today is on or before that day — dates from the start of last month onwards are selectable.
  • A day-of-month value, and today is past it — only dates from the start of this month onwards.

This is a restriction on the date picker only. The search itself applies no date window.

Feature visibility / permissions

The widget gates its own features on one thing: whether the session holds an auth token. There are no client-side permission definitions for it, and no permission code is checked on the shopper’s behalf anywhere in this flow.

CapabilityGuestSigned-in shopper
Search for a receiptYesYes
Request an e-invoiceYesYes
Have the identity saved to a customer recordNoYes
See Requested E-InvoicesOnly through the e-mailed tracking linkYes
See E-Invoice Cancellation and E-Invoice HistoryNoYes
Request a cancellationNo — the effect chain is gated on an authorised sessionYes
Export the PDF from the search resultOnly when exportPdfPublicAccess is trueOnly when exportPdfPublicAccess is true
Export the PDF from the details pop-upThrough the tracking linkYes

Fields

Search — By Date Amount

FieldMeaningRequiredNotes
Cash Bill/Invoice No.The document number printed on the receiptYesMatched against any of the numbers the receipt carries — its tenant, company or branch running number, or any of its client document numbers — so whichever one your printed receipt shows will do. The receipt is looked for in the three e-invoice pools first and then among e-invoices already built; the first match is taken.
AmountThe transaction totalYesCompared for exact equality with the document total — 12.5 and 12.50 both match, 12.49 does not. The form itself checks nothing, so a mistyped figure shows only as No matching eInvoice record found.
Transaction DateThe date on the receiptYesRestricted by the request window above. Interpreted in Malaysian time.

Search — By Pin

FieldMeaningRequiredNotes
PinThe PIN printed on the receiptYesMatched against the PIN recorded on the document’s e-invoice pool entry, together with the invoice number as above.

The search rejects anything that is neither (invoice number + PIN) nor (invoice number + date + amount) with “Invalid request. Provide either (invoice_no + pin_no) OR (txn_date + txn_amount + invoice_no).”, and returns “No matching eInvoice record found for the given criteria.” when nothing matches.

Update E-Invoice Profile

FieldMeaningRequiredNotes / validation
NameThe buyer name that goes on the e-invoiceYesAlso sent as the buyer’s customer code on the guest path.
Identification TypeThe kind of identification documentYesDrop-down, exactly four values: PASSPORT, NRIC, BRN, ARMY. Nothing else can be chosen.
Identification NumberThe identification document numberYesMust contain no whitespace — “ID must not contain spaces”.
TINTax Identification NumberYesMust contain no whitespace — “TIN must not contain any space”. See Verify TIN below.
EmailWhere the e-invoice notification goesYesOn the guest path this is also where the tracking link is sent, and the address the tracking list is keyed on.
Contact NumberBuyer phoneYesMust contain no - — “Contact Number no must not contain “-””. Placeholder shows the +60… form.
Address Line 1First line of the e-invoice addressYes
CountryCountryYesDrop-down from the country master; defaults to Malaysia.

The form also asks for an optional SST Registration (the only optional identity field), Address Lines 2–5, Postal Code, City, a State chosen from the states of the selected country, and an optional Mobile Number (no -).

  • For a signed-in shopper the form opens already filled from their customer record — name, TIN, SST number, identification, e-mail and phone — and from the customer’s address marked as the default e-invoice address, billing addresses first, then shipping. A guest starts from a blank form with Malaysia selected.
  • Mobile Number does not reach the e-invoice. It is saved with the address. The buyer details written onto the receipt for a signed-in shopper carry the customer’s phone — the Contact Number — and an address block without the mobile number. Put the number LHDN should see in Contact Number.
  • A buyer with no TIN of their own can enter one of the four general TINs LHDN publishes for that case (EI00000000010, EI00000000020, EI00000000030, EI00000000040). The widget accepts it as verified without asking LHDN, and Identification Number stops being required.

Verify TIN. The Update button is disabled until the Verify TIN button has returned a positive result for the exact combination of TIN, identification type and identification number currently in the form. The hint under the TIN field reads Verified in green or Not valid in red. Changing any of the three values after verifying invalidates the result and disables Update again.

What the identity becomes

Form fieldSigned-in shopper — written to the customer entityGuest — sent in the request payload
NameThe customer’s nameThe buyer name, also used as the buyer’s customer code
Identification TypeThe customer’s ID type and its e-invoice ID typeThe buyer’s e-invoice ID type
Identification NumberThe customer’s ID number and its e-invoice ID valueThe buyer’s e-invoice ID value
TINThe customer’s e-invoice TINThe buyer’s TIN
SST RegistrationThe customer’s SST numberThe buyer’s SST number
EmailThe customer’s e-mailThe buyer’s e-mail
Contact NumberThe customer’s phoneThe buyer’s phone
Address blockA customer address flagged as the default e-invoice addressA buyer address on the request

A guest’s details are not saved anywhere as a customer record. They travel with the queue event and are written onto the document as the buyer JSON.

Lifecycle and effects

This is a request applet feature, not a document applet: nothing here creates a document line, moves stock or posts to the ledger. It changes how an existing sales document is submitted to LHDN, and it records one request.

Step 1 — BigLedger decides whether there is anything to do. Before queuing, it reads the pool entry named by the request and takes one of three courses:

CourseWhenResult
Normal requestThe pool entry has not been submitted yetThe request is queued.
Request plus consolidated rebuildA batch pool entry already submitted, whose e-invoice sits in the consolidated queueThe request is queued and a consolidated-queue rebuild is queued after it.
Nothing to doA single-general or individual pool entry already submitted, or a batch pool entry submitted with nothing in a consolidated queueThe request is refused: “Request already made by someone or submitted as consolidated”.

A pool GUID that does not exist raises “Batch Pool Container Not Found”, “Single General Pool Container Not Found” or “Individual Pool Container Not Found”. A signed-in request with no buyer entity GUID is rejected with “Entity hdr guid is null”, and one whose caller is not a login entity of that buyer returns not-authorised.

Step 2 — the queue. The request is queued and picked up straight away. It carries which pool entries are involved, the buyer (the signed-in shopper’s customer record, or the whole guest profile), the course chosen in step 1 and the storefront’s hostname.

Step 3 — what the queued run does. It branches on which pool the receipt sits in.

PoolWhat changesThe answer to “individual or consolidated”
Batch poolThe buyer is written onto the pool entry and onto the sales document, the pool entry is reset to unprocessed, and the document’s Submission Type is set to Individual. The pool entry is then processed into a submission-queue entry, and the resulting To IRB e-invoice is linked back to the document.Individual. A receipt that would otherwise have been swept into the merchant’s monthly consolidated e-invoice becomes an individual e-invoice in the shopper’s name. Where the receipt had already reached a consolidated queue, a consolidated-queue rebuild is queued so the consolidated document is reconstructed without it.
Single general poolThe buyer is written onto the pool entry, and the pool entry and its document are updated as for any submission.The submission the pool was already destined for, now carrying the buyer.
Individual poolThe same, on the individual pool entry.As above.

If the batch-pool branch produces no submission-queue entry, the request is recorded as FAILED rather than SUCCESS — and the receipt is stranded. Its batch pool entry is left processed and failed, with the document’s Submission Type already changed to Individual, so the monthly consolidation passes it by and no individual e-invoice was built: the sale is in neither the consolidated e-invoice nor an individual one until the merchant acts on that pool row (My E-Invoice Admin Applet, PROCESSED / FAILED).

SUCCESS means the e-invoice was built and queued for submission, not that LHDN has received it — the merchant’s ordinary submission run sends it, and its status is read on the e-invoice itself.

Step 4 — the request record. Either way one request record is created, carrying the request status, the sales document and its type, transaction date and amount, the invoice number, the PIN, the To IRB e-invoice, the five server and five client document numbers, and any validation message. For a guest it additionally carries the e-mail address and a 12-character access key — the first 12 characters of a random UUID.

Step 5 — the guest e-mail. When the row has both an access key and an e-mail, BigLedger sends one e-mail, subject “Trace your e-invoice request status”. On SUCCESS the body says the request has been processed and offers a Track Your Request link; on FAILED it says the request failed and to contact the relevant authority. The link first checks that the key and e-mail match a request record and then redirects the shopper to https://<website code>/page/E-Invoice?key=…&email=…. The widget reads those two query parameters and shows the guest’s requested-invoice list.

What the merchant sees. Every request is logged in the My E-Invoice Admin Applet under Internal Submission → Portal Request — one record per request, SUCCESS or FAILED, whether it came from this widget or from the customer portal, which runs the same processor. The request also surfaces as a changed pool row and a new submission-queue entry, with the buyer’s name, identification, TIN and address now on the document. There is no approval step and no notification to the merchant that a shopper asked: Portal Request is the list to read, and a FAILED row on it is the one that needs somebody.

Related applets

  • CP Commerce Admin — where the widget is placed on a page, and where every other storefront setting lives.
  • My E-Invoice Admin — the merchant’s side of the pipeline this feeds: the pools, the submission and validation queues, the cancellation requests.
  • MY E-Invoice Portal — the same request made from a tenant-side buyer account rather than a storefront. Different applet, same underlying records.
  • Customer — where a signed-in shopper’s identification, TIN and default e-invoice address are stored and can be corrected.
  • POS General — the cash bill most storefront e-invoice requests are about, and where its PIN comes from.

Troubleshooting

SymptomCauseFix
Every search fails, with an authorisation error or nothing at allThe storefront’s hostname record has no SYS_AKN_WEB_CP_COMMERCE_PUBLIC_KEY, so the app cannot authenticate any callAdd the public key extension parameter to the Host Name record for that domain. The app logs a configuration error naming Public Key on start-up when it is missing.
“No matching eInvoice record found for the given criteria.” on a receipt the shopper is holdingThe search is exact on all supplied values. Amount must match the pool entry exactly; the date is taken in Malaysian time; the invoice number is matched against every running and client number on the receipt, so check the amount and the date firstTry the By Pin search instead, which matches on invoice number and PIN only. If the document never reached a pool, it will never be found here — check the posting queue on the merchant side.
The transaction date the shopper needs cannot be selectedWith no extension period set, the picker allows the current month only. With one set, it allows every date from the start of last month onwards while today is on or before that day of the month, and from the start of this month onwards after it — there is no upper bound either wayThis is the configured request window. Set or widen the extension period in the company’s e-invoice settings, or use the By Pin search, which has no date field.
“This invoice has already been submitted. No further requests can be made.”Either the record is already submitted, or the search matched an e-invoice already sent rather than a pool entry, so there is nothing left to request againstExpected once an e-invoice exists. If the shopper’s details are wrong on it, the remedy is a cancellation request, not a second request.
A request came back Validation Error and the shopper wants to correct it and ask againThey cannot. Once a pool entry has been submitted, BigLedger refuses a second request against it, whichever pool it sits in; the search then matches the sent e-invoice and shows the amber banner with no Request buttonOnly the merchant can correct and resubmit it, and only from To IRB E-Invoice in the My E-Invoice Admin Applet — the successful submission already removed the pool entry. A shopper whose request failed (counted under In Queue for the batch and single-general pools) can correct and request again, because the pool entry never reached success.
“Request already made by a user.”Shown for every failure of the request call — a genuine duplicate, an authorisation failure, and a network error all produce these wordsTreat it as “the request did not go through”, not as proof of a duplicate. Check the merchant-side pool row before telling the shopper it already exists.
Update stays greyed out in the profile pop-upVerify TIN has not returned a positive result for the exact TIN, identification type and identification number now in the formPress Verify TIN. If it returns Not valid, the combination was rejected upstream — the identification number and TIN must belong together.
The form will not accept a TIN or identification numberBoth reject any whitespace, including a trailing space pasted from a documentRemove spaces. The same applies to - in the phone and mobile fields.
Request for Rejection does nothing in list viewThe pop-up is opened as a different kind of dialog from the list view than from the grid view, and the component only works in the grid view’s formSwitch to grid view with the toggle at the top of the list. Recorded as a product finding.
A signed-in shopper’s other billing addresses disappear after they update their e-invoice profileThe profile save builds the billing-address array from the shipping addresses when both existRecorded as a product finding. Check and repair the customer’s addresses in the Customer applet after a shopper updates their profile.
A guest never receives the tracking e-mailThe e-mail is only composed for request statuses SUCCESS and FAILED; a status outside those two sends an empty message, and any mail failure is silentLook the request up on the merchant side by invoice number. Recorded as a product finding.
The widget cannot be configured from CP Commerce AdminIt is registered in the shared catalogue with no parameter form, and the applet has no editor for itEdit the layout JSON on the node’s Json Params tab. Recorded as a product finding.

Related documentation

Last updated on