bookkeeping2026-09-26

COD and Courier Costs for Malaysian Online Sellers: Remittances, Failed Deliveries and True Margin

A practical guide for Malaysian online sellers on cash-on-delivery fees and remittance timing, failed deliveries and returns, shipping charged vs courier invoices, and booking it all so your true margin is right.

GetPay Accounting Team
•Updated: 2026-09-26

TL;DR (Key Takeaways)

  • •A COD order is not cash yet. The buyer pays the courier, the courier settles later, and the fee comes off before the money reaches your bank. Until then, it is money the courier owes you.
  • •COD fees are usually a flat amount or a percentage, whichever is higher. At RM7 or 4%, a RM50 COD order costs RM7 to collect, which is 14% of the order. The flat fee applies to every order below RM175.
  • •Record shipping charged to the buyer as income and the courier's charge as an expense. Record COD fees as their own expense, and count the outbound courier charge on a failed delivery, plus any return charge your courier bills, as a cost with no sale behind it.
  • •Reconcile each COD payout as a batch: COD collected − COD fees − any offsets = the amount credited to your bank. Chase parcels that were delivered longer ago than the courier's settlement window and still haven't been paid out.

Why COD and courier costs quietly eat your margin

Most sellers work out profit per order as "selling price minus product cost". For a cash-on-delivery (COD) order sent by courier, that leaves out four things:

  1. The courier charge for sending the parcel.
  2. The COD fee the courier or aggregator keeps for collecting cash for you.
  3. The shipping fee the buyer paid, which may be more or less than what the courier actually charged you.
  4. Failed deliveries, where you pay to send the parcel out and back and make no sale.

None of these shows up if you only watch your bank balance. The COD money arrives days or weeks later, in one lump that covers many parcels, with the fees already taken off. This guide shows how to book each piece so your margin reflects reality, and how to check every COD payout against your orders.

It is written for sellers on their own store (WooCommerce, Shopify, EasyStore) who ship through a courier or an aggregator such as EasyParcel, and for anyone who books J&T, Ninja Van or Pos Laju directly. Marketplace payouts from Shopee, Lazada and TikTok Shop follow their own settlement reports. For those, see our Shopee, TikTok Shop and Stripe net-settlement guide and our guide to Shopee, Lazada and TikTok Shop seller fees. For the wider bookkeeping of an own-store business, see our Shopify, WooCommerce and EasyStore bookkeeping guide.

How COD money moves before it reaches your bank

With COD, the buyer pays the courier, not you. EasyParcel's Malaysia help centre shows the stages a COD amount passes through on its COD Settlement page:

EasyParcel statusWhat it means (per EasyParcel)What it means in your books
PendingYou bought a COD shipment, or the parcel is still in transitNo cash yet. The sale may not be final.
To ReleaseThe courier has settled, and you can request a withdrawalCash is owed to you. Request it.
ReleasingYou requested a withdrawal, and EasyParcel is releasing it within 3–4 working daysMoney in transit to your bank
ReleasedThe payout has been released to your bank accountMatch it to your bank statement
CancelledThe shipment was cancelled or returned to the senderNo COD cash will come for this parcel

Settlement time depends on the courier. EasyParcel's COD cost table (updated 2 September 2026) lists these charges, settlement timelines and COD limits for bookings made through EasyParcel:

Courier (via EasyParcel)COD charge (whichever is higher)Courier settlement timelineCOD amount allowed
SPX ExpressRM5 or 4%7–10 working daysRM5.30–RM500
DHL eCommerceRM6 or 4%1–3 working daysRM6.01–RM2,000
J&T ExpressRM7 or 4%7–12 working daysRM7.01–RM1,000
Pos LajuRM7 or 4%3–5 working daysRM7.42–RM2,000
Pos Malaysia MELPlusRM7 or 4%3–5 working daysRM7.42–RM2,000
LEXRM102nd and 3rd Fridays of the month (2nd, 3rd and 4th in months with five Fridays)RM10.60–RM250

After the courier settles, you still have to request the withdrawal, and EasyParcel says payouts land within 3–4 working days. A J&T COD parcel booked this way can therefore take the courier's 7–12 working days plus another 3–4 before the cash is in your account.

Booking a courier directly works differently:

  • Ninja Van lists a COD handling charge of 3% of the invoice value or RM4, whichever is higher. Ninja Biz app users are paid every Thursday. Shipper Dashboard users are paid on the schedule in their sales agreement (bi-weekly or end of month). Ninja Van also says that from 3 July 2025 it offsets overdue invoices against the COD funds it has collected for you. That means a payout can be smaller than your COD collections because it has also paid a courier bill.
  • Pos Malaysia's COD page (dated August 2024) advertises COD rates from RM4.00, up to three COD delivery attempts, remittance "within 2 working days after dropping off your parcel", and a maximum of RM2,000 per item. Confirm with Pos Malaysia how that timing applies to your account.
  • J&T Express's own COD page says COD is for its VIP account customers and does not publish seller fees. The RM7-or-4% rate above is what EasyParcel lists for J&T bookings made through EasyParcel.

These are the providers' published terms at the time of writing. Your account may be on different rates, and all of them change, so always go by your own statement.

What a COD order really costs: a worked example

Take one COD order. These figures are illustrative:

  • Item price RM120, and the buyer is charged RM8 for shipping, so the courier collects RM128.
  • Your product cost is RM60.
  • EasyParcel charges you RM7.50 to send the parcel.
  • The J&T COD fee is the higher of RM7 and 4% × RM128 (RM5.12), so RM7.00.
Amount (RM)
Sales (item)120.00
Shipping charged to buyer8.00
Total collected by courier128.00
Less: product cost(60.00)
Less: courier charge(7.50)
Less: COD fee(7.00)
Margin after fulfilment53.50

If you had only looked at "price minus cost", you would have seen RM60. The RM6.50 gap is small on one order, but it repeats on every COD order.

Watch the flat minimum. With "RM7 or 4%, whichever is higher", the flat RM7 applies to every COD order below RM175 (because 4% of RM175 is exactly RM7). On a RM50 COD order, RM7 is 14% of the order value. If much of your COD volume is small tickets, that minimum fee is a pricing decision, not a rounding error.

How to book COD and courier costs so your margin is right

The entries below follow one simple policy: record the sale when the parcel is delivered and the courier has collected the cash, and treat the money as owed by the courier until it is remitted. Your accountant may prefer a different point to recognise the sale. Whatever you choose, apply it the same way every month. If a connected store or accounting app books your orders automatically when they are placed, you are on the earlier point, not this one (see "How GetPay helps" below).

One more choice: where courier and COD fees sit on your profit and loss. If you want gross margin to include fulfilment, put them under cost of sales. If you keep them in operating expenses, your gross margin leaves them out, so look at the "margin after fulfilment" figure from the worked example instead. Agree the layout with your accountant and keep it the same every month.

1. Topping up courier credit

EasyParcel describes its credit as a prepaid, cashless way to pay for shipments. It is valid for one year from your latest top-up. A top-up is not yet an expense. It is money paid in advance.

AccountDebit (RM)Credit (RM)
Prepaid courier credit (asset)200.00
Bank200.00

2. Each shipment

When a parcel is booked, move its charge from the prepaid balance to expense. If you are billed by the courier instead (for example, a monthly Ninja Van invoice), credit the courier as a supplier you owe (accounts payable) instead of prepaid credit.

AccountDebit (RM)Credit (RM)
Courier and delivery expense7.50
Prepaid courier credit7.50

3. Parcel delivered, COD collected

The buyer has paid the courier. You have made the sale, and the courier now owes you the money.

AccountDebit (RM)Credit (RM)
COD receivable – courier128.00
Sales120.00
Shipping income8.00

Keep shipping income separate from sales, and don't subtract it from your courier expense. Comparing the two lines each month shows whether your shipping charges actually cover your courier bills.

4. COD remitted to your bank

The fee comes off before you are paid. EasyParcel, for example, says it deducts the COD charge when you request the withdrawal.

AccountDebit (RM)Credit (RM)
Bank121.00
COD fees (expense)7.00
COD receivable – courier128.00

Record the COD fee as its own expense account, not as a reduction of sales and not mixed into courier charges. It is the cost of offering COD as a payment method, and you will want to compare it with what you pay for FPX or card payments (see our FPX gateway MDR guide).

A note on service tax. The Royal Malaysian Customs Department's current guide on logistics services (Panduan Perkhidmatan Logistik, 6 June 2025, published in Malay) treats licensed courier services as part of taxable logistics services. It also names delivery of goods, documents or parcels using an e-commerce platform, including on behalf of any person, as taxable. The guide says logistics became a taxable service under Group J at 6% from 26 February 2024, and providers who were already registered, such as courier companies, charge it from 1 March 2024. A provider only has to register once the value of its logistics services exceeds the RM500,000 threshold, so an invoice from a small provider may carry no service tax. Shopee's Help Centre likewise says a 6% SST applies to logistics services (shipping fees) on its platform from 1 March 2024. Check the tax line on each courier invoice. Unless your tax agent tells you otherwise, treat any service tax on courier invoices as part of your delivery cost. Whether you need to register for SST yourself is a separate question, covered in do online sellers need to register for SST?.

Failed deliveries and returns: the cost with no sale behind it

COD parcels are more exposed to failed deliveries, because the buyer has not paid anything up front. EasyParcel's help centre says that if the courier cannot reach the receiver after three attempts, the parcel is returned to the sender, and the sender bears the shipping fee. Its COD Settlement page then shows the parcel as Cancelled, and no COD cash will come.

Under the "sale on delivery" policy above, a failed COD parcel needs no sale reversal, because no sale was ever booked. What you do record:

  • The outbound courier charge, already booked as an expense when you shipped.
  • Any return charge the courier bills you, as courier and delivery expense.
  • The stock coming back. Inspect it. If you took the stock out of inventory when you shipped, put resaleable goods back. If you only count stock at month-end, just include them in the count. Write off damaged goods either way.

If your system books the sale earlier, for example when the order is packed, a failed parcel means reversing that sale with a credit note or cancellation. Otherwise your sales are overstated and the COD receivable never clears.

Measure the damage as a rate. Say 100 COD parcels go out in a month, 8 come back, and each failure costs RM7.50 out plus RM7.50 back (illustrative figures). That is RM120 of courier cost with no sale. Spread across the 92 successful orders, it adds about RM1.30 to the true cost of each successful COD order. Whether your courier also keeps a COD fee on a returned parcel is not stated in the EasyParcel article, so check your own courier statement.

EasyParcel suggests checking the receiver's contact details and address, and telling buyers how COD payment works and roughly when the parcel will arrive (by tracking SMS, email or WhatsApp notifications). Both reduce failures.

Shipping charged to buyers vs what the courier actually charges

The shipping fee on your checkout is an estimate. The courier's charge is based on the parcel it actually receives. The gap goes one of two ways:

  • You undercharge. You set shipping by the item's weight but forget the box, or the courier bills by volumetric (size-based) weight. You pay the difference.
  • You overcharge. A flat RM10 shipping fee on a parcel that costs RM6.50. This becomes income, and that's fine, as long as you record it.

Shopee spells this out for marketplace orders. Its Seller Education Hub explains an overcharged shipping fee: when the logistics partner charges more than the shipping fee Shopee calculated for the order, you bear the difference. Shopee says this usually happens when the weight or dimensions entered for the product are wrong, so the fee it calculated was wrong too. Shopee deducts it from your payout using this formula:

Shipping fee charged by the logistics provider
− shipping fee paid by the buyer (excluding SST)
− Shopee shipping fee rebate
+ seller-paid shipping fee SST
= overcharged shipping fee deducted from the seller

Shopee's own example: the buyer paid RM1.90, the logistics provider charged RM8.00, the Shopee rebate was RM3.00 and SST was RM0.19. The seller was charged RM3.29 (RM8.00 − RM1.90 − RM3.00 + RM0.19). Check the final shipping fee in your Shopee income statement rather than relying on the order screen. Our Shopee, Lazada and TikTok Shop seller-fees guide covers how to book marketplace shipping fees and subsidies.

For your own store, run the same comparison each month:

Monthly checkAmount (RM)
Shipping income (charged to buyers)1,840.00
Courier and delivery expense(2,215.00)
Net shipping subsidy(375.00)

A negative number is not necessarily wrong, because free-shipping promotions cost money on purpose. But it should be a choice. If it isn't, check whether your listing weights include packaging.

How to reconcile a COD remittance to your orders

A COD payout is a batch, not a single order. EasyParcel's COD payout statement shows the total released to your bank, and EasyParcel notes that one release may include several COD shipments. Treat each payout like a marketplace settlement:

COD amounts collected for the parcels in the payout
− COD fees
− any courier invoices offset against the payout
= amount credited to your bank

Worked example. A payout statement covers three J&T parcels booked through EasyParcel:

OrderTracking no.COD amount (RM)COD fee (RM7 or 4%)Net (RM)
#1041JT…001128.007.00121.00
#1043JT…01459.007.0052.00
#1047JT…027240.009.60230.40
Total427.0023.60403.40

The bank shows one credit of RM403.40. One entry clears all three:

AccountDebit (RM)Credit (RM)
Bank403.40
COD fees (expense)23.60
COD receivable – courier427.00

Step by step:

  1. Download the payout statement from your courier or aggregator (on EasyParcel, the COD Payout Listing page has the COD Payout Statement and COD Invoice).
  2. Tie each tracking number to an order number. Keep the tracking number on the order or invoice when you ship. Without it, matching by amount alone quickly goes wrong when two orders have the same COD value.
  3. Recalculate each fee from your rate card. A fee that doesn't match your rate is a question for the courier, not a rounding difference.
  4. Look for offsets. If the courier deducted an unpaid invoice (as Ninja Van says it may), debit the courier's payable balance for that amount instead of COD fees.
  5. Match the net to the bank credit by amount, date and reference.
  6. Age what's left. Any parcel delivered longer ago than the courier's settlement window, and not yet in a payout, is a debt to chase. EasyParcel does not say whether its window runs from delivery or from pickup, so use the delivery date as a conservative trigger and ask the courier if in doubt. If you record sales on delivery, returned or cancelled parcels never enter the COD receivable, so just confirm none were booked as delivered by mistake. If you record sales earlier, reverse them with a credit note so they drop out.

At month-end, your COD receivable – courier balance should equal the COD value of parcels delivered but not yet remitted. If it doesn't, something is missing: a payout you haven't booked, a parcel booked as delivered that actually came back, or cash the courier hasn't paid you.

Records to keep

Keep the courier invoices, top-up invoices, COD payout statements, COD invoices and your reconciliation schedule together, month by month. LHDN's FAQ says individuals should keep records and relevant documents for seven years for audit purposes, starting from the year the tax return is submitted. That FAQ is about an individual's return. If you run a business, whether as a sole proprietor or a company, confirm the retention period for your business records with your tax agent. Sole proprietors can see how these costs feed into the annual return in income tax for online sellers: Form B. If your buyers don't ask for e-invoices, our consolidated B2C e-invoice guide covers how retail sales are reported. For tax on your own invoices, see the SST invoicing and credit-note guide.

Month-end checklist for COD sellers

  • Download every COD payout statement for the month and tie each one to a bank credit.
  • Recalculate COD fees from your rate card, and question any that don't match.
  • Book COD fees as their own expense, separate from courier charges and from sales.
  • Keep shipping charged to buyers as income, and compare it with courier expense.
  • Clear failed and returned parcels: book return charges, and put resaleable stock back into inventory (or your month-end count).
  • Age the COD receivable, and chase anything past the courier's settlement window.
  • Record courier invoices that were offset against a COD payout.
  • Treat courier top-ups as prepaid until the shipments are used.
  • Keep statements and invoices for the retention period your tax agent confirms.

How GetPay helps

GetPay handles part of this for you today. Here is what it does, and where you still need to step in:

  • Store orders become invoices, at order time. WooCommerce is live. Processing and completed orders become issued invoices to the buyer, and a WooCommerce COD order is booked as soon as it reaches processing, which is before the parcel ships. That is the "record the sale earlier" approach above, not the delivery entry in step 3. If GetPay books your store orders, don't also post the step-3 entry by hand, or you will count the same sale twice. Shopify and EasyStore are in early access. EasyStore orders are booked only once their payment status is paid.
  • Shipping is not an invoice line. The invoice covers the items, not the shipping the buyer paid. GetPay writes the order total and the difference into the invoice notes, with a "review" marker. In the example above the invoice is RM120, not RM128, so it will not equal the COD amount collected. Record shipping income yourself, for example as its own invoice. Our Shopify, WooCommerce and EasyStore guide explains this in more detail.
  • Failed parcels need your action. GetPay does not hear about returns from the courier. When a COD parcel comes back, mark the order cancelled or failed in WooCommerce (or cancelled or refunded in EasyStore). GetPay then flags the invoice for you to review, and you issue the credit note. GetPay never posts a credit note on its own, and a returned parcel whose store order you never update stays an open invoice.
  • EasyParcel shipments become courier bills (early access). Each charged shipment becomes one bill from EasyParcel, at the price EasyParcel charged you, normally dated by the day the courier picks up the parcel (EasyParcel's collection date). Later status updates don't add a second bill. A shipment that is already cancelled when GetPay reads it is not billed. If you cancel a shipment after its bill was created, void that bill yourself, because EasyParcel returns the credit to you. Shipments from before you connected are not billed, so record those by hand. These bills replace the manual step-2 entry. Your top-ups are still the prepaid credit from step 1. GetPay pays bills from an account in the bank range of the chart (codes starting with 11), so to pay EasyParcel bills from your credit, set the credit up as its own asset account in that range, record each top-up as a transfer from your bank, and pay each EasyParcel bill from it. Agree the setup with your accountant.
  • Set up the accounts for your margin. In the default chart, EasyParcel bills go to 6300 Service Expense, an operating expense that other services also use, and COD fees are not booked for you. If you want the margin in this guide on your profit and loss, add your own Courier and delivery, COD fees and Shipping income accounts, and record COD fees from each payout statement.
  • Bank matching you confirm. Upload your bank statement, and GetPay proposes matches between bank credits and open invoices for you to confirm. It does not read courier COD payout statements or work out COD fees, and it will not propose a match for a batched COD payout that is net of fees. Record each invoice's payment yourself from the payout statement, and book the COD fee as its own expense.
  • Not connected yet: Shopee, Lazada and TikTok Shop are waiting on platform approval. There is no direct J&T, Ninja Van or Pos Laju connection, so record their invoices as bills.

Try the live demo below to see invoices and bank matching on a sample Malaysian business, or start free and connect your WooCommerce store.

This guide is general information, not tax or accounting advice. Courier fees, settlement timelines and SST rules change. Check your own courier agreement and statements, and confirm your treatment with LHDN, the Royal Malaysian Customs Department or a licensed tax agent.

Frequently Asked Questions

When should I record a COD sale?

Pick one point and use it every time. Many small sellers record the sale once the parcel is delivered and the courier has collected the cash, and book it as money owed by the courier (a COD receivable) rather than by the buyer. If you record the sale earlier, for example when the order is packed, you must reverse it when a COD parcel fails. Agree the policy with your accountant.

How much does COD cost a Malaysian seller?

It depends on the courier and the channel. EasyParcel's Malaysia help centre lists COD charges of RM5 or 4% for SPX Express, RM6 or 4% for DHL eCommerce, RM7 or 4% for J&T Express and Pos Laju, and a flat RM10 for LEX, whichever is higher where two figures are given. Ninja Van's own page lists a COD handling charge of 3% or RM4, whichever is higher. Check your own account, because rates change.

How long until COD money reaches my bank?

It depends on the courier. Through EasyParcel, the COD amount first waits for the courier's settlement (listed as anywhere from 1–3 to 7–12 working days depending on the courier, or set Fridays for LEX). You then request a withdrawal, and EasyParcel says payouts are released within 3–4 working days. Ninja Van says Ninja Biz app users are paid every Thursday, and Shipper Dashboard users follow the schedule in their sales agreement.

Who pays when a COD parcel is rejected or cannot be delivered?

Usually you do. EasyParcel's help centre says that if the courier cannot reach the receiver after three attempts, the parcel goes back to the sender and the sender bears the shipping fee. No COD cash is collected, so the courier cost is spent with no sale behind it. Check your courier's terms for whether any COD fee still applies.

Should I net the shipping fee the buyer paid against my courier bill?

No. Record the shipping charged to the buyer as income and the courier's charge as an expense, then compare the two each month. Netting hides a shipping subsidy. On Shopee, the platform itself deducts an overcharged shipping fee from your payout when the logistics partner charges more than the shipping fee Shopee calculated for the order, which Shopee says usually happens when the weight or dimensions entered for the product are wrong.

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