← all articles

How to split and manage stock across Shopee, Lazada and a Woo store

The moment you sell the same physical unit in three places, you have a problem that has nothing to do with marketing. One carton of 24 units sits on a shelf, three storefronts each say “24 available”, and a Shopee order, a Lazada order and a Woo order can all land inside the same ten minutes. Someone is going to get a cancellation.

The question comes up constantly, including in an r/phinvest thread on multichannel stock. The honest answer is that you don’t need expensive software to start. You need one source of truth, a rule for how much of that stock each channel is allowed to show, and a buffer that stops the channels fighting over the last few units.

This tutorial is for small and mid-size sellers in Singapore, Malaysia and the Philippines who run one Shopee shop, one Lazada shop and one WooCommerce store out of the same stock. By the end you will have a safety stock number per product, a reserve you hold back centrally, a split rule per channel, and a small script that pushes the numbers out. I’m not affiliated with Shopee, Lazada or WooCommerce, and this is how I run my own setup, not a guarantee of results.

what you need

  • one shop per platform: Shopee, Lazada and TikTok Shop each have rules about multiple shops per seller. I run one shop per platform and I’m not going to suggest otherwise. Read the current seller policy on each before you set anything up.
  • a WooCommerce store on HTTPS with REST API keys (read/write) generated under WooCommerce > Settings > Advanced > REST API
  • a Shopee Seller Centre account and a Lazada Seller Center account, both with mass-update or API access
  • a Google Sheet or CSV as the master stock table (SKU, on hand, reserve, lead time, 28-day sales per channel)
  • Python 3.10 or later with the requests library, only if you want to automate the Woo side
  • 3 to 6 months of order history exported from each channel, so you can calculate demand
  • optional: API app credentials from the Shopee Open Platform and the Lazada Open Platform. Both have stock-update endpoints, but app approval, endpoint names and rate limits change, so check their current docs (as of October 2026) before you build against them
  • cost: the sheet and script are free; your existing Woo hosting is the only spend

step by step

Step 1: pick one source of truth

Action: decide where the real on-hand number lives. For most sellers I’d say a spreadsheet or the Woo product table. Do not treat any marketplace as the master. Marketplace numbers are a display, not a ledger.

Expected output: one column called on_hand that you update from physical counts and from received purchase orders, and nowhere else.

If it breaks: if two people edit stock in different places, you will drift within a week. Pick one editor per SKU, or lock the master sheet.

Step 2: count real demand per channel

Action: export 28 days of orders from Shopee, Lazada and Woo, and total the units sold per SKU per channel. Put those in three columns next to on_hand. If you want to be careful, use daily numbers so you can measure variability in the next step.

Expected output: a table where each SKU shows, for example, Shopee 60, Lazada 25, Woo 15 units over 28 days. Illustrative numbers only.

If it breaks: returns and cancelled orders inflate demand. Filter to completed orders only. If you need a refresher on how returns land in your numbers, see how to handle returns and refunds on Shopee and Lazada.

Step 3: calculate safety stock

Action: safety stock is the cushion that covers demand spikes while you wait for a restock. The textbook formula is z x standard deviation of daily demand x square root of lead time in days. A z of 1.65 corresponds to roughly a 95% chance of not running out during the lead time. It assumes bell-shaped demand, which small sellers’ demand often isn’t, so treat the output as a starting point.

import math

Z = 1.65  # about 95% service level

def safety_stock(daily_sales, lead_days):
    mean = sum(daily_sales) / len(daily_sales)
    var = sum((x - mean) ** 2 for x in daily_sales) / (len(daily_sales) - 1)
    return math.ceil(Z * math.sqrt(var) * math.sqrt(lead_days))

def reorder_point(daily_sales, lead_days):
    avg = sum(daily_sales) / len(daily_sales)
    return math.ceil(avg * lead_days) + safety_stock(daily_sales, lead_days)

Expected output: a safety_stock and reorder_point per SKU. Add them as columns in your sheet.

If it breaks: if a SKU has fewer than 14 days of history, the standard deviation is junk. Use a flat rule instead, such as one week of average sales, until you have data.

Step 4: set a kanban-style reserve

Action: kanban at its simplest is a two-bin system. Bin one is what you sell from. Bin two is the reserve, and when you start dipping into it, that is the signal to reorder. Here, bin two is your central reserve, held back from every channel. A reasonable starting reserve is your safety stock number. Channels only ever see on_hand - reserve.

Expected output: a sellable column equal to on_hand - reserve, floored at zero. When on_hand falls to the reorder point, the SKU is flagged for restock.

If it breaks: if you keep hitting the reserve before stock arrives, your lead time estimate is too optimistic. Ask your supplier for their real turnaround, including the days your own receiving takes.

Step 5: split sellable stock by channel

Action: divide sellable between channels in proportion to their 28-day sales, rounded down. The rounding leftovers stay in the central reserve.

def allocate(on_hand, reserve, sales_28d):
    sellable = max(on_hand - reserve, 0)
    total = sum(sales_28d.values()) or 1
    return {ch: int(sellable * s / total) for ch, s in sales_28d.items()}

print(allocate(40, 8, {"shopee": 60, "lazada": 25, "woo": 15}))
# {'shopee': 19, 'lazada': 8, 'woo': 4}

Expected output: with 40 on hand and a reserve of 8, 32 units are sellable. Shopee gets 19, Lazada 8, Woo 4, and 1 unit stays behind in the reserve from rounding.

If it breaks: a channel with tiny sales can be allocated zero and look out of stock. Give every active channel a floor of 1 or 2 units, taken out of the biggest channel’s share, or the smaller channel looks dead.

Step 6: push the Woo number via the REST API

Action: Woo is the easiest of the three because its REST API is open and well documented. The WooCommerce REST API docs cover the product update endpoint. Set manage_stock to true and send stock_quantity.

import os, requests

def push_woo(product_id, qty):
    r = requests.put(
        f"{os.environ['WOO_URL']}/wp-json/wc/v3/products/{product_id}",
        auth=(os.environ["WOO_KEY"], os.environ["WOO_SECRET"]),
        json={"manage_stock": True, "stock_quantity": qty},
        timeout=20,
    )
    r.raise_for_status()
    return r.json()["stock_quantity"]

Expected output: the function returns the quantity Woo now holds, matching your allocation. Store the keys in environment variables, never in the sheet or the script.

If it breaks: a 401 usually means the key is read-only or the site is on HTTP. A 404 means the product ID is wrong, since variations have their own IDs and endpoint. For variable products, update the variation, not the parent.

Step 7: update Shopee and Lazada

Action: you have two routes. The first is the official APIs on the Shopee and Lazada open platforms, which let you update stock programmatically once your app is approved. The second, which is what I’d start with, is the bulk edit in each Seller Centre: export the SKU list, paste in the allocated quantities, and upload. Do this once a day at a fixed time while you are small.

Expected output: each channel shows the quantity from your allocate result.

If it breaks: bulk uploads fail on mismatched SKU codes more than anything else. Keep one SKU code format across all three channels, and read how to keep listings consistent across brand stores if your naming has drifted. If you’re on Lazada’s pre-sale mode for a SKU, stock behaves differently, so check how Lazada’s pre-sale mode works for sellers first.

Step 8: reconcile every day

Action: when orders come in, deduct them from on_hand in your master. The simplest version: once a day, add up completed and pending orders from all three channels, subtract from the previous count, and compare with a physical count of your fast movers. Then rerun the allocation and push.

Expected output: a reconciliation row per SKU with expected vs counted. A difference of 0 or 1 is normal. More than that needs investigating.

If it breaks: if counts are consistently short, check whether fulfilment-by-platform stock is in the mix. Units sitting in a marketplace warehouse are not on your shelf. Fulfilment options for Shopee, Lazada and TikTok Shop explained covers how to keep those pools separate in your sheet.

Step 9: optional, check the seller apps on a real device

Action: some checks are easier in the mobile seller apps. If you’re a Singapore seller who wants a dedicated phone with a persistent Singapore mobile IP, cloudf.one rents real Android phones in Singapore on dedicated hardware, controlled from the browser. It’s Singapore-only, so it won’t help with a Malaysian or Philippine connection. It does not change the rule above: one shop per platform, and nothing here is a way around any platform’s policies.

Expected output: you can open the seller app, see the same stock numbers as your sheet, and fix a quantity from a phone.

If it breaks: if the app logs you out or asks for verification, complete it with your own account details. Don’t work around it.

common pitfalls

  • mirroring full stock everywhere: showing all 24 units on all three channels works only if you sync within seconds. In a daily batch routine it guarantees oversells on fast movers.
  • no central reserve: if every unit is allocated, a single late supplier delivery turns into cancellations across three channels at once.
  • trusting the platform number: the quantity on Shopee or Lazada is whatever you last sent, minus orders. It doesn’t know about damaged units, samples or offline sales.
  • allocating by gut feel: a channel that was strong in last year’s mega-sale month may be small now. Recalculate shares from the trailing 28 days.
  • ignoring returns: a returned unit isn’t sellable until you’ve inspected it. Keep a “returns pending” column outside on_hand so you don’t resell damaged stock.

scaling this

At 10x, meaning a few dozen SKUs and under a hundred orders a day, the sheet and a once-a-day bulk upload are fine. The work is discipline: count the top ten SKUs weekly, rerun the allocation daily.

At 100x, you’ll feel the lag. Move the master into a small database, and use the APIs for all three channels so stock pushes happen every few minutes or on every order. Shopee and Lazada offer order push mechanisms, but check the docs as of October 2026 before you design around them. Add per-SKU service levels: a high-margin item can have a z of 2.05, a slow clearance item can run on less.

At 1000x, buy rather than build. A dedicated inventory or order management system with warehouse locations, batch tracking and proper audit trails becomes cheaper than your own time.

If your volume grows across borders, remember that tax treatment differs. For Singapore GST questions see GST basics for Singapore marketplace sellers. This is not legal/tax advice, and you should check with an accountant for your situation.

where to go next

Written by Xavier Fok

disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-10-23.

free download
Multi-store setup checklist for Shopee, Lazada and TikTok Shop

What each platform allows for running more than one shop, and what to set up per store, as of September 2026. Leave your email and we will also tell you when we publish a new guide, a few times a month at most.

from the team behind this site
A dedicated real phone for each store you run

cloudf.one hosts real Android phones in Singapore, each on its own persistent Singapore mobile IP, and you open them from the browser. Useful if you run Singapore stores and want one phone per store or brand instead of a drawer of handsets.

see how cloudf.one works →
read on
More from the desk

Store operations, platform rules, fees and pricing for Shopee, Lazada and TikTok Shop sellers, with dates on anything that can change.

browse all articles →