bookkeeping2026-09-26

Shopify, WooCommerce & EasyStore Bookkeeping in Malaysia: Month-End Checklist

Month-end bookkeeping for Malaysian web-store sellers: invoice paid orders, record gateway fees, handle partial refunds and work out cost of goods sold.

GetPay Accounting Team
•Updated: 2026-09-26

TL;DR (Key Takeaways)

  • •Your web store's sales report is not your books. Each paid order still needs a numbered invoice or receipt, the gateway fee is a separate expense, and the bank only ever sees the net payout.
  • •Worked example: a RM89.00 card order on Stripe's published Malaysian rate (3% + RM1.00 for domestic cards) costs RM3.67 in fees, so RM85.33 lands in the payout. Record sales of RM89.00 and a fee of RM3.67. Do not record RM85.33 as the sale.
  • •A partial refund reduces the sale through a credit note, and the original gateway fee usually stays spent. Stripe says its processing fees from the original transaction are not returned when you refund.
  • •Gross profit is sales minus cost of goods sold, not sales minus everything you bought this month. Cost of goods sold = opening stock + purchases − closing stock.
  • •Today GetPay connects WooCommerce self-serve. Shopify and EasyStore are in early access, set up together with you. Paid orders become issued invoices. Cancellations and refunds are flagged for your review (on WooCommerce, later order edits too), never auto-credited.

Why your store dashboard is not your books

Shopify, WooCommerce and EasyStore all show a sales dashboard, and it is tempting to treat that number as your income. For tax and profit, it is not enough. There are three reasons:

  1. The dashboard counts orders, not documents. Your books need a numbered invoice or receipt for each sale, and a credit note when you refund one.
  2. The bank sees a different number. Your payment gateway deducts its fee, groups many orders into one payout, and pays you days later. The deposit almost never equals any single day's sales.
  3. The dashboard does not know your costs. It cannot tell you what the goods you sold cost you, what the courier charged, or what your platform subscription cost this month.

This guide is for sellers who run their own web store: a sole proprietor on WooCommerce, a small Sdn Bhd on Shopify, a boutique on EasyStore. If you also sell on Shopee, Lazada or TikTok Shop, those marketplaces settle differently. See our Shopee, Lazada and TikTok Shop seller fees guide and the Shopee, TikTok Shop and Stripe net-settlement guide for that side of the business.

Step 1: Turn every paid order into an invoice or receipt

Treat one paid order as one sale document. Keep these details on it:

  • your own document number, in an unbroken sequence
  • the store's order number, so you can trace it back
  • the date the order was paid
  • the items, quantities and the price the customer actually paid after any discount
  • shipping charged to the customer, if any
  • tax, only if you are registered to charge it

Why a separate number? Store order numbers can have gaps. Abandoned checkouts, failed payments and test orders all use up numbers. LHDN's e-invoice FAQ notes that MSMEs with annual gross takings above RM150,000 from goods sold must issue serially numbered receipts under section 82(1)(b) of the Income Tax Act 1967. Keeping an unbroken invoice sequence in your books is the simplest way to show that, even when the store's own numbers skip. Ask your tax agent whether the threshold applies to you.

Only paid orders count. A WooCommerce order in "Pending payment" or "On hold" is not yet a sale. Book it when the payment is confirmed. Cash-on-delivery orders need a clear rule of their own: decide whether you book the sale on dispatch or on collection, and apply it the same way every month. Our COD and courier costs guide covers remittances and failed deliveries.

Keep the evidence. LHDN's FAQ for individuals says records and supporting documents should be kept for seven years. A Sdn Bhd should plan on the same seven years; confirm the exact period that applies to you with your tax agent. Export your store's order report each month and file it with your bank statements and gateway reports.

What about e-invoicing?

LHDN's implementation timeline page (last updated 30 August 2026) says taxpayers with annual turnover or revenue below RM3,000,000 are exempted from e-invoice implementation. The FAQ explains that the exemption depends on meeting set criteria, so check them rather than assume. For example, the exemption does not apply if your business has a non-individual (for example corporate) shareholder with annual turnover or revenue of RM3 million or more, is a subsidiary of a holding company with RM3 million or more, or has a related company or joint venture with RM3 million or more (FAQ Q99; Q103 explains when companies count as related). Those businesses were required to start e-invoicing from 1 July 2026, or from the date operations start if later (FAQ Q12, Q14 and Q99).

One point matters for web stores in particular. LHDN's FAQ says that for sales made through an e-commerce platform, the platform provider carries the e-invoice obligation. Your own Shopify, WooCommerce or EasyStore site is software you use to sell directly, and there is no marketplace in the middle. If you are within scope, plan on issuing the e-invoice yourself. For customers who don't ask for one, the FAQ allows a monthly consolidated e-invoice, issued within seven calendar days after the month ends. Our e-invoice guide for online sellers covers the dates and exemption criteria, and the consolidated B2C e-invoice guide covers the mechanics. These rules have changed several times, so confirm your position with LHDN or your tax agent.

And SST?

Most small resellers do not charge SST at checkout. Under the Royal Malaysian Customs Department's SST background page, sales tax is charged on taxable goods manufactured in Malaysia by a registered manufacturer, and on imports. The registration threshold for manufacturers is RM500,000. Service tax is a separate question. If you deliver goods to customers yourself and charge for it, Customs' logistics guide (June 2025) can treat those delivery charges as a taxable logistics service at 6%, with the RM500,000 threshold counted on delivery charges only. Whether simply passing on a courier's charge counts is less clear. Our SST guide for online sellers explains when you need to register. If your store adds "tax" to orders, make sure you are actually registered. Our SST invoicing and credit-note guide covers invoicing once you are.

Step 2: Record the gateway fee as its own expense

Here is a single order, worked through:

ItemAmount
2 × scarf at RM45.00RM90.00
10% discount code−RM9.00
Shipping charged to customerRM8.00
Customer paysRM89.00

The customer pays by domestic card through Stripe. Stripe's Malaysian pricing page lists 3% + RM1.00 per successful transaction for domestic cards, plus 1% for international cards and 2% more if currency conversion is needed. On RM89.00 that works out to:

3% × RM89.00 = RM2.67
+ fixed fee  = RM1.00
Gateway fee  = RM3.67
Net payout   = RM89.00 − RM3.67 = RM85.33

Record it like this:

AccountDebitCredit
Gateway clearing (money Stripe holds for you)RM85.33
Payment gateway fees (expense)RM3.67
Sales — goodsRM81.00
Shipping incomeRM8.00

When Stripe pays out, move the money from gateway clearing to your bank account. Because one payout covers many orders, check it as a batch: gross collections − refunds − fees = payout. Our FPX gateway MDR reconciliation guide walks through that proof step by step.

Every gateway prices differently. Billplz, for example, publishes a fixed fee per FPX transaction and a percentage for cards and e-wallets. Its FPX and card rates vary by plan, and payout timing depends on the payment method: FPX pays out the next business day and cards at T+2 business days. Always take the fee from your own settlement report, never from a rate you remember.

Watch for platform fees too. Shopify's Malaysian pricing page lists an extra transaction fee when you use a third-party payment provider: 2% on Basic, 1% on Grow, 0.6% on Advanced and 0.2% on Plus. Plans are priced in US dollars. Shopify's Help Center says third-party transaction fees are charged on your Shopify bill, not taken from the gateway payout, so record them from the Shopify invoice as a separate expense.

Step 3: Handle partial refunds without rewriting history

Say one of the two scarves arrives damaged and you refund its discounted price of RM40.50 through Stripe.

  • Don't edit the original invoice. Issue a credit note for RM40.50 that points to the original invoice. Your sales for the month drop by RM40.50.
  • The fee usually stays spent. Stripe's pricing page says the payment processing fees from the original transaction are not returned when you refund. The RM3.67 remains an expense.
  • Shopify's own fee works differently. Shopify Payments isn't available in Malaysia, so Malaysian stores use a third-party provider. Shopify's refund help page says that in that case the third-party transaction fee is credited back in proportion to the refund, but only when you refund through the Shopify admin, not when you refund directly in your gateway. But Shopify's own help pages disagree here: its billing page says third-party transaction fees aren't returned when you refund an order. Treat your next Shopify bill as the answer, and record only what was actually credited.
  • The refund comes out of your gateway balance. Stripe's refund documentation says refunds use your available Stripe balance, so a later payout will be RM40.50 smaller. Expect that when you reconcile.
  • Decide what happens to the stock. WooCommerce gives you a "Restock refunded items" checkbox. Tick it only if the item can really be sold again. A damaged scarf is a stock loss, not stock back on the shelf.

One WooCommerce detail catches many sellers out. WooCommerce's refund documentation says that if the full order value is not refunded, the order status does not change to "Refunded". A partially refunded order still shows as Processing or Completed, so a status filter alone will miss it. Look for orders that have refund lines.

Also check how the refund was made. WooCommerce says a manual refund does not return money through the gateway, so you still have to send the money back yourself. A manual refund entered in the store means nothing until the money has actually gone back to the customer.

Step 4: Get discounts and shipping right

  • Line discounts such as a sale price or a per-item promotion: book the price the customer actually paid. You don't need a separate discount line.
  • Order-level vouchers such as "RM10 off your order": make sure the invoice total equals what the customer paid. If you spread the voucher across the lines, do it the same way every time.
  • Free shipping promotions: you charged nothing, but the courier still billed you. The courier cost is an expense, and there is no shipping income to record.
  • Shipping charged to the customer: this is income. The courier's charge to you is a separate expense. Don't net the two against each other.

Step 5: Work out cost of goods sold properly

The most common mistake in online-seller books is treating everything you bought this month as this month's cost. If you bought RM5,500 of stock but sold only part of it, the rest is still an asset on your shelf.

Use the periodic method:

Cost of goods sold = Opening stock + Purchases − Closing stock

For this you need a stock count, or a reliable stock report, on the last day of every month. Value each item at what it cost you, including inbound shipping on your purchases if you treat it that way consistently. Don't use your selling price. How to value closing stock for tax purposes is something to confirm with your tax agent.

Step 6: Close the month with a real P&L

Here is a sample month for a small web store:

LineRM
Sales of goods (after discounts)12,400
Shipping charged to customers960
Less: refunds and credit notes(520)
Net sales12,840
Opening stock 6,000 + purchases 5,500 − closing stock 5,200(6,300)
Gross profit6,540
Payment gateway fees(410)
Courier charges(1,050)
Store subscription and app fees(180)
Advertising(1,200)
Packaging(150)
Net profit before tax3,550

If you had recorded net payouts as sales and every stock purchase as a cost, this month would look very different, and wrong.

Month-end checklist for web-store sellers

  • Export the month's paid orders from your store and compare the count and total with the invoices or receipts in your books.
  • Find orders with refund lines, including partially refunded ones that still show as Processing or Completed, and make sure each has a credit note.
  • Download every gateway settlement report. Prove gross collections − refunds − fees = payout for each batch.
  • Match every payout to a bank credit. Payouts still in transit at month-end stay in gateway clearing.
  • Record gateway fees, platform transaction fees (such as Shopify's third-party provider fee), subscriptions and app charges from their own invoices.
  • Record courier charges from the courier's invoices, separately from shipping you charged customers.
  • Count stock, or check your stock report, and work out cost of goods sold.
  • Check that SST is on invoices only if you are registered, and that your e-invoice (or consolidated e-invoice) duty is handled if you are in scope.
  • File the order export, settlement reports, bank statement and courier invoices together. Plan on keeping records for seven years (see Step 1).

How GetPay helps

GetPay is built for this workflow, with some honest limits:

  • Store connections. WooCommerce is live: enter your store address, approve GetPay in WooCommerce, and processing and completed orders become invoices. By default, WooCommerce cash-on-delivery orders move to Processing at checkout, so they are booked then (some plugins change this). If your policy is to book COD sales on collection, adjust failed deliveries with a credit note. Shopify and EasyStore are in early access, which means the connection has been built and tested end to end on our own test stores and we set it up together with you. TikTok Shop, Shopee and Lazada are not connected yet.
  • Paid orders become issued invoices with the store's order number in the notes. They are not marked paid automatically. You record each payment yourself. GetPay's bank reconciliation proposes a match when a bank credit carries an invoice number or equals one invoice's outstanding balance, and you confirm every match. A batched payout that is net of gateway fees won't match on its own. Record the fee from your settlement report and clear the invoices as described in our net-settlement guide.
  • Discounts and shipping. Line-level discounts are booked at the price the customer paid. Shipping and order-level differences are not invented as invoice lines. GetPay writes the order total and the difference into the invoice notes and marks the note for review. So an auto-booked invoice's total excludes shipping (RM81.00 in the example above, not RM89.00), and an issued invoice's lines cannot be changed afterwards. Record shipping income separately, for example as its own invoice. An EasyStore order whose voucher is not carried on its lines is not booked automatically, and you invoice it yourself.
  • Refunds. Cancellations and refunds are flagged for your review. On WooCommerce, partial refunds and order edits made after booking are flagged too. GetPay never posts a credit note on its own, so you decide.
  • Gateway fees are not guessed. GetPay does not work out MDR from the gap between an invoice and a lower deposit. You record the fee from your settlement report.
  • Cost of goods sold. When an order line's product name exactly matches a product name in your GetPay catalogue, the product's cost at that moment is saved on the invoice line. A line with no match is booked by name with no cost, so the Cost of Sales report shows no cost for it. Matching SKUs alone is not enough today. The Cost of Sales report then shows revenue against that cost, with margin, for any month. Profit & Loss, stock-on-hand and sales reports are included too.
  • Couriers. With the EasyParcel connection (early access), each charged shipment becomes a courier bill at the price EasyParcel charged you.
  • Tax and e-invoicing. Store tax is booked only when it matches 8% service tax or 10% sales tax on every line, the tax sits on the item lines (not on shipping), and your company has an SST registration on file. Otherwise the order is left for you to invoice by hand. On a paid plan, you can submit e-invoices to LHDN MyInvois yourself, including consolidated B2C e-invoices.
  • Refused orders are shown, not hidden. Paid orders GetPay could not book, such as orders placed before you connected or orders with tax it cannot book faithfully, are listed under Orders not booked yet so you can invoice them by hand. Orders in a currency other than MYR are refused and appear under Rejected & pending events on the Sell online → Channel analytics page; invoice those by hand too.

Open the live demo below, go to Sell online → Marketplaces, and send a sample Shopify or WooCommerce order to watch it become an invoice, no store needed. Or start free and connect your WooCommerce store today.

This guide is general information, not tax advice. Fees and LHDN rules change. Check your own gateway agreement and confirm your tax position with LHDN or a licensed tax agent.

Frequently Asked Questions

Should I record my web store sales at the gross amount or the net payout?

Gross. The customer paid the full order amount, so that is your sale. The payment gateway's fee is a separate expense. If you record only the net payout, both your sales and your expenses are understated, and your figures stop matching your invoices.

Do I get the payment gateway fee back when I refund a customer?

Usually not, but check your own gateway. Stripe's Malaysian pricing page says the payment processing fees from the original transaction are not returned when you issue a refund. Other gateways set their own terms, so read your merchant agreement and your settlement report.

My web store already sends order confirmation emails. Is that enough as a receipt?

Not necessarily. LHDN's e-invoice FAQ explains that MSMEs with annual gross takings above RM150,000 from goods sold must issue serially numbered receipts under section 82(1)(b) of the Income Tax Act 1967. Store order numbers can skip, for example on abandoned or cancelled checkouts, so many sellers keep a separate, unbroken invoice or receipt sequence in their books. Confirm what applies to you with your tax agent.

Does the marketplace e-invoice rule cover my own Shopify or WooCommerce store?

Be careful here. LHDN's FAQ says that for sales made through an e-commerce platform, the platform provider is responsible for issuing the e-invoice. Sales on your own website have no marketplace in the middle, so plan on the e-invoice (or monthly consolidated e-invoice) being your responsibility unless you are exempt. Confirm your position with LHDN or your tax agent.

Which web stores can GetPay connect to today?

WooCommerce is live: any merchant can connect their own store self-serve. Shopify and EasyStore are in early access, meaning the connection has been built and tested end to end on GetPay's own test stores, and GetPay sets it up together with you. EasyParcel, a courier booking platform, is also in early access and turns shipments into courier bills.

Sources & Ground Truth

See GetPay with a sample business

Open the live demo: a sample Malaysian business with invoices, bank matching and payroll already set up. No signup, nothing to install.

Start free

Related Articles