OKAYA runs haulage and trading out of Malaysia. When the last MyInvois band came into force, the interesting problem was not the API. It was that a paper haulage invoice has never carried the fields LHDN now requires, so there was nothing to submit even if a submission client had existed.
The instinct when e-invoicing is mandated is to go looking for an API client. We started somewhere less exciting: what does LHDN require on an invoice that a haulage invoice has never carried, and does OKAYA hold any of it?
The answer was almost none of it. A paper haulage invoice carries a company name, an address, a trip and an amount. LHDN's Invoice v1.1 specification wants the buyer's TIN, an identification scheme and number, a SST registration where one exists, a state code, and a contact — fields that never appeared on the document, and therefore were never collected when the customer was created.
That reframes the project. Every route to compliance passes through the same gate, including the free one: even keying an invoice into LHDN's portal by hand requires the buyer's identity. If the data is not held, no amount of integration work helps. So the first thing built was not a client. It was a checklist.
Every customer record is assessed against the mandatory buyer fields, and the screen answers one question per firm: if an e-invoice had to go out for this customer tomorrow, what would still be blank?
Two states are deliberately kept apart. A blank field is work not done yet. A field that is filled but malformed — a TIN of the wrong shape, a state code that is not on LHDN's list — is work done wrong. They read differently and they need different words, because the person looking at the screen has to pick up the phone and ask for something specific.
The rules come off LHDN's published field specification rather than an assumption about it. One limit is stated on the screen itself: a TIN of the right shape can still be the wrong TIN. Only LHDN can say so at submission. The gap check tells you what is missing, not what is true.
The second half of readiness is where the invoice comes from. In OKAYA's system it is generated from unbilled trips — the operational record is the source, and the invoice is derived from it rather than assembled by hand in a separate package.
This matters more for compliance than it looks. When invoices are retyped between systems, two things drift: the figures, and the set of invoices that exist at all. An invoice that exists on paper but in no system is invisible until someone reconciles booked against validated, and by then it is a historical problem rather than a current one.
Seven modules run live on the same ledger, so the trip, the invoice and the accounting entry are three views of one record rather than three records that have to be made to agree.
The system does not submit to MyInvois. There is no API client, no OAuth, no XAdES signing and no QR code, and none of that can responsibly be written until OKAYA holds an ERP registration with LHDN and a digital certificate from a Malaysian licensed CA. Building a submission client against credentials that do not exist yet produces code nobody can test.
What it does instead is export the current slice of the ledger as LHDN's own batch workbook, for upload. The export refuses to be naive about it: ask it to check first and it answers how many invoices would go, which are held back, and what each is short of. That question is asked before the download, because the alternative is a file LHDN rejects an hour later with a row number instead of a customer name.
When the registration and certificate are in place, the submission client is a well-defined addition on top of data that is already correct. That is the order the work should happen in, and it is the opposite of how most e-invoicing projects are sold.
Fix capture at the source before building anything downstream. The unglamorous step — getting buyer TIN, SST registration and classification codes captured when a customer is created rather than chased at month end — is what determines whether everything after it works.
State the limits on the screen, not in a footnote. A compliance tool that overstates its own certainty is worse than a spreadsheet, because people stop checking it.