---
title: How stock reaches your channels
summary: >
  Your storefront does not count stock; it repeats the last number Mossery sent
  it. Every stock movement queues an update for that product at that location,
  and a background worker sends it within about a minute. Nothing is sent
  unless the product and the location are both matched to that store and the
  connection is switched on.
type: concept
group: sync
step: 7
permission: null
prerequisites: []
related:
  - /help/sync/product-shows-zero-online
  - /help/fulfil/when-stock-actually-moves
  - /help/make/the-three-numbers-of-a-built-product
last_updated: 2026-08-07
---

**A storefront is a noticeboard, not a scoreboard.**

It does not watch the warehouse. It shows the last thing somebody pinned to it.
Mossery holds the original count, and everything a shopper sees is a copy that was
sent outward at some point in the past.

Once you see it that way, the whole Sync stage stops being mysterious. Copies
can be late, copies can be missing, and copies can be sent to the wrong
noticeboard — but the original is the original, and this app owns it.

This page covers:

- [What sets an update going](#what-sets-an-update-going)
- [Three things must line up](#three-things-must-line-up)
- [Which locations a storefront may advertise](#which-locations-a-storefront-may-advertise)
- [What number actually goes out](#what-number-actually-goes-out)
- [The nightly check heals in one direction only](#the-nightly-check-heals-in-one-direction-only)
- [When a push fails](#when-a-push-fails)

## What sets an update going

Every stock movement queues an update. Nothing is sent the instant it happens.

When anything changes what you own — a delivery, a count, a transfer, an
assembly, a fulfilment — a permanent entry is written to the stock ledger, and
that entry drops a job onto an outgoing queue. The job says only *this product,
at this location, needs re-sending*. It carries no quantity.

That last detail is what makes the whole thing safe. When the job is picked up,
the current level is read fresh and sent as an **absolute value** — "this
product now has 42 here" — rather than "add three". Sending the same job twice
therefore changes nothing, and two jobs for the same product and location
collapse into one rather than queueing behind each other.

The queue is drained twice over:

- **Immediately**, by whatever just changed the stock, so a big flow like a receiving or an approved count goes out inside the same action.
- **On a sweep**, roughly every minute, catching anything the first pass missed because it crashed, timed out, or errored.

Each pass takes a bounded batch and leaves the rest for the next one, so a
thousand-line change becomes a few minutes of steady sending rather than a
burst your storefront would rate-limit anyway.

A queue that is long but moving is healthy. A queue whose oldest item has not
budged in days is stuck, and that is worth escalating rather than retrying.

## Three things must line up

An update is only attempted when all three are true. Any one missing and the
push is a silent no-op — not an error, because nothing was ever attempted.

**1. The product is matched to that store.** A product page can show a
"syncing" badge and still have nothing behind it. The badge means a link
exists; the thing that actually carries stock outward is a separate record
holding the store's own identifiers for that item. When one is present and the
other is missing, every update quietly does nothing.

**2. The location is matched to a location on that store.** Your warehouse has
to correspond to a specific place in the storefront's own list of places.
Without that pairing there is no address to send the number to. Crucially, the
app will **not** guess: no match means no target, and the update is skipped.

That refusal is the scar of a real failure. When guessing was allowed, a system
handed one store's location identifier to a different store, and the rejected
pushes piled up unnoticed for weeks — hundreds of thousands of error records,
a full disk, and eventually an outage. Skipping is boring and correct.

**3. The connection is switched on.** Each connected store sits in one of three
states:

| State | What happens |
| --- | --- |
| Live | Updates are sent |
| Shadow | Everything is calculated and recorded, nothing is sent |
| Paused | Nothing happens at all |

Shadow is the deliberate halfway house used while you validate a new
integration: the app shows what it *would* have sent without touching the live
store, so you can compare against whatever is currently in charge. A single
product can be promoted out of shadow to prove the path end to end before the
whole catalogue follows.

## Which locations a storefront may advertise

Stock is real where it sits, and not all of it is yours to offer.

Only locations you actually sell from are pushed. A warehouse, yes. But stock
held by a consignment partner, sitting on a stall at a weekend event, parked
with a production partner, or half-consumed inside an assembly in progress is
never advertised — no matter how the mappings are configured.

The reason is simple. Those units are already promised to someone, or are not
in a saleable state. Offering them online would sell the same physical item
twice: once to a shopper, once to the partner already holding it.

This is also the usual answer to "we clearly have stock, why does the store say
none". If the units live somewhere that store cannot sell from, the store is
correct to ignore them. The fix is either to map that location to the store, if
it genuinely fulfils online orders, or to transfer the stock somewhere already
mapped.

## What number actually goes out

For most products it is simply the finished units at that location.

### Built products send their capacity too

A product assembled from components would read as sold out the moment its
finished units ran out, even with a shelf full of parts. So a built product
advertises its **derived availability**: finished units on hand, plus how many
more its components could produce right now.

Two rules keep that honest:

- The capacity is worked out from the components **at that same location**. Parts sitting in two different buildings cannot become one finished unit, and treating them as if they could once made a kit advertise thirteen when the site that would build it could manage three.
- The capacity is added **only at the location where assembly happens**. Everywhere else sends finished units only. Otherwise the same build capacity would be counted once per location and the storefront's total would multiply it.

A product whose components are all made to order has no stock-bound limit at
all, and is sent out with a generous standing figure instead of a calculated
one.

### Selling at zero is a separate instruction

Alongside the quantity, each product carries an instruction about what the
store should do when that quantity hits zero.

A ready-stock product should stop selling — zero means sold out. A made-to-order
or hybrid product should keep selling — zero is its normal resting state, and
refusing orders would be refusing the business the product exists for. That
instruction mirrors the product's stock mode, and it is set when the listing is
created, so an older listing built before the rule existed can sit there
denying orders. A periodic pass finds those and corrects them.

## The nightly check heals in one direction only

Once a night, the app compares itself against each live store, item by item.

Anything that disagrees is recorded as drift, with both figures side by side, so
you can see whether the gap is one product or a systemic problem. Then it
corrects — but **upward only**.

- **The store reads lower than you.** The app re-sends its own number. This is the "we have stock and it still says sold out" case: a stale push, a failed send, or somebody editing the store by hand. Re-asserting is safe.
- **The store reads higher than you.** Nothing is corrected automatically. The drift is recorded and left alone.

That asymmetry is deliberate and worth understanding, because it is the single
most common surprise in the Sync stage. Correcting downward at night would
clobber a legitimate in-flight change — the store may be right and the app may
be a few seconds behind. So the app only ever pushes a number *up* on its own
initiative, and every overcount is left for a human.

The practical consequence: **an overcount does not self-heal.** If a store is
advertising more than you hold, it will keep doing so until the underlying
cause is fixed and a real stock movement re-triggers a push. Waiting another
night will not help.

The nightly pass is also capped by both count and time, so a large backlog
cannot become a write storm against your store. Whatever it does not reach
tonight is re-detected and picked up tomorrow.

## When a push fails

Failures are recorded, not swallowed, and always against one specific store.

Each failure writes an entry naming the product, the store, the location and
the reason. That per-store detail matters: a fault on one channel used to be
filed against another, which is how a month-long failure on one storefront was
misread as a problem with a completely different one.

One refusal is worth knowing about because it looks like a failure and is
actually a safety catch. When a product was first linked, the app remembered
which item on the store it pointed at. If that item is later renamed or reused
for a different product, the link now points at somebody else's listing. Rather
than write your stock onto it, the app **refuses the push** and records why.
Re-linking the product repairs it.

Everything else follows the ordinary shape: fix the cause the error names,
then let a real stock movement re-queue the item, or retry it directly.

## Explore

**A product shows 0 online, but you have stock.** The three checks to run, in
order, when a specific product disagrees with a specific store.
[Learn more →](/help/sync/product-shows-zero-online)

**When stock actually moves.** What creates the ledger entries that set all of
this in motion.
[Learn more →](/help/fulfil/when-stock-actually-moves)

**The three numbers of a built product.** Where the derived availability a built
product advertises comes from.
[Learn more →](/help/make/the-three-numbers-of-a-built-product)
