Inventory Feeds

How a vendor's availability file (EDI 846) updates vendor stock levels, how that stock is projected as sellable availability for drop-ship products only, and how the full-snapshot sweep and its safety floor keep a bad file from zeroing your assortment.

An inventory feed is the vendor’s availability file — their EDI 846, or the CSV equivalent — arriving on a schedule and telling you how many units they have. It never creates products and never touches your own counted stock: it updates the vendor product on items your product feed already linked, and projects that availability as sellable only where the product is set up to be drop shipped.

What an inventory feed does

An inventory feed reads one file, resolves each row to a product through the vendor part number your product feed already stored, and writes two things:

What it writes Where it lands What it means
Vendor stock quantity, stock status, and a “stock updated” timestamp The vendor product for that item — the link between their part number and your product, shown on a product’s page as Vendor sources “This is what the vendor says they have.” Always written, for every linked item.
A vendor availability projection at the mapped location A stock row with on hand 0 and available = the vendor’s quantity, flagged as vendor-derived “This can be sold, and it will ship from the vendor.” Written only for drop-ship-eligible products.

And a list of things it deliberately never does:

  • It never creates a product. Vendor part numbers the file lists that you have not linked are counted as unknown and skipped.
  • It never writes an inventory adjustment, a ledger entry, a cost layer, or a bin movement. Nothing about a vendor feed changes your on-hand count, your inventory valuation, or anything a stock count would reconcile against.
  • It never overwrites a real stock row. If you already hold counted stock for that product at the location the feed is mapped to, the importer refuses that write and names the pair in the run log.
  • It never overwrites a kit’s computed availability. A bundle’s availability is derived from components you physically hold; a vendor’s stock is not a substitute for it, so those rows are refused too.

ℹ️ Note: A vendor can have more than one inventory feed. If the vendor drops several availability files — a different file per distribution centre, or a separate file per product line — add a second inventory feed pointed at the other directory or filename pattern rather than asking them to consolidate. Each feed carries its own location mapping, its own schedule and its own Full snapshot setting, and that independence is the reason to read Two inventory feeds on one vendor below before you add the second one.

Vendor stock is the vendor’s stock

This is the idea that makes everything else make sense, and it is the one operators most often get wrong.

The number in an availability file is a claim about somebody else’s warehouse. You do not own those units, you have not paid for them, they are not on your shelf, and they can disappear between the file being written and an order being placed. ILLUMA therefore keeps vendor stock on the vendor product — the row linking their part number to your product — and treats the sellable projection as a separate, clearly-labelled, second-class quantity.

Concretely, the projection row carries on hand 0 and available = the vendor’s quantity, and is stamped as a vendor mirror. That labelling is what lets every downstream consumer make its own decision:

  • Your storefront counts it. Ship availability sums every location’s available quantity, vendor mirrors included — otherwise a drop-ship item would show as out of stock everywhere and could never be bought. (Store-pickup availability is the separate read, and it correctly excludes vendor mirrors: a vendor’s DC is not a place a shopper collects from.)
  • Marketplace channels exclude it. Amazon, eBay, Google and Walmart quantity pushes all filter vendor-mirror rows out. A marketplace quantity is a promise with a metric attached to it, and it is not a promise you can make out of somebody else’s snapshot.
  • The Inventory screen shows it as its own status. A product with nothing on hand but vendor availability reads Dropship, not Out of Stock — so nobody re-orders stock that is actually fully sellable.
  • Costing and the ledger ignore it entirely. On hand is zero, so there is nothing to value.

A kit’s derived availability is labelled differently from a vendor mirror on purpose. Both are computed rather than counted, but a kit’s components really are on your shelf at that location, so kits publish to channels and vendor mirrors do not. That distinction is why the importer refuses to write over a kit row rather than treating every derived row as fair game.

⚠️ Warning: Never map a vendor’s warehouse code onto a location where you hold real, counted stock. The importer will refuse the write rather than mix the two — which is the correct outcome, but it also means the vendor’s availability lands nowhere and the run reports refusals you then have to go read in the run log.

Why the product must be drop ship

The projection only happens for products flagged Dropship product or Use dropship as fallback. For any other product, the feed still records the vendor’s quantity on the vendor product, and then zeroes any stale projection left over from when the product was drop-ship flagged.

The reasoning is routing. Availability is a promise that an order can be fulfilled. If a product is not drop-ship eligible, there is no path from “order placed” to “vendor ships it” — so showing the vendor’s units as sellable would advertise stock that nothing can turn into a shipment.

This produces the single most common support question about inventory feeds: the run says thousands of rows applied and the storefront still shows nothing in stock. That is not a feed problem. Those products are not drop-ship flagged. “Applied” counts the vendor products the feed updated, which it does whether or not the product can be drop shipped.

Where the flags come from:

  • The product feed’s Fulfillment setting. On a product feed, under Fulfillment, the choice is Fallback — drop ship when local stock hits zero, Always drop ship — the vendor fulfills every order, or Leave alone — don’t touch the product’s drop ship settings. The default is Fallback. The setting takes effect when a match is applied from the review queue, not merely when the feed runs. Choosing Leave alone means this vendor’s inventory feed can run forever and never make a single unit sellable, which is exactly what the hint under that dropdown warns.
  • The product itself. On a product, under Dropship, tick Dropship product (the vendor ships every order). Use dropship as fallback (drop ship when your own stock reaches zero) appears only while Dropship product is unticked — a product that always drop ships has nothing to fall back from. Either flag is enough. A vendor must also be selected on the product, or the page tells you so: “Please select a vendor above to enable dropship.”

💡 Tip: Fallback is the right default for a distributor you buy from occasionally. Your own shelf is used first and the vendor covers what it cannot — the vendor’s projection sits at its own location and only contributes once your own quantity runs out.

Before you build the feed

Three things must already be true, or the first run fails.

  1. The product feed has run and its matches are applied. Inventory rows resolve by the stored vendor part number and nothing else — there is no fuzzy matching, no UPC fallback, no guessing. If no links exist yet, the run fails immediately with “no vendor_products aliases exist for this vendor — run the catalog feed first” (the message’s “catalog feed” is the vendor’s product feed). See Product Feeds.
  2. A connection exists. Inventory feeds are pulled over SFTP; there is no spreadsheet-upload option for them — the delivery picker offers Spreadsheet upload on a product feed only. Add the endpoint once under Connections on the vendor and every feed can share it. See Vendor Connections.
  3. You have a location for this vendor’s stock. Create one under Inventory → Locations that represents the vendor’s warehouse, and do not reuse a location you pick and ship from yourself. For a multi-warehouse vendor whose codes you want to keep separate, create one per code.

Setting up the feed

  1. Open the vendor — go to Purchasing → Vendors, open the vendor, and select the Integration tab. Feeds live there, under Products and Inventory.
  2. Add the feed — in the Inventory panel, click + Add Feed, then choose the SFTP endpoint. (When the vendor has several endpoints, each one is its own button, so the feed is never silently bound to the wrong host.) The setup form opens with Feed Type already set to Inventory — stock quantities per vendor warehouse. The type cannot be changed after the feed is created.
  3. Name it — give it a Label you will recognise in a list, e.g. “Ace nightly 846”. With more than one inventory feed on a vendor the label is the only thing telling the two rows apart, so name it for the file it reads.
  4. Point it at the files — under Files, set the Directory the vendor drops into (required), optionally an Archive Directory (checked as a fallback if the vendor moves files after pickup), and a Filename Pattern as a glob, e.g. *_Inventory_*.csv. Leave the pattern blank to take every file in the directory.
  5. Describe the format — under File Format, choose the Delimiter (comma, pipe, tab or semicolon), optionally set Expected Columns as a row-shape check, and leave First row is a header ticked. A vendor feed requires a header row; without one the run fails.
  6. Name the part-number column — under Identity, set Vendor Part-Number Column to the column carrying the vendor’s own item number. It must be the same part number the product feed linked, or nothing will resolve.
  7. Map the quantity — click Read columns from the vendor to pull the real headers off the endpoint, then add one mapping row: the vendor’s quantity column → Quantity On Hand. That is the only field an inventory feed maps.
  8. Map the locations — see the section below. At least one mapping is required.
  9. Decide the snapshot behaviour — tick Full snapshot — items missing from a file are treated as out of stock at the vendor if the vendor’s file lists everything they carry, which is what an 846 normally is. It is on by default. Untick it if the vendor sends deltas, or if this feed only ever covers part of their catalog. This is the highest-stakes setting on the feed — read Full snapshot and The safety floor before you leave it on for a partial file.
  10. Set the schedule — under Schedule, choose how often to Check For New Files Every: 15 minutes, hour, 6 hours, 12 hours, or day.
  11. Save — click Create Feed (stays off until enabled). Creating a feed never starts it.

📷 Screenshot: The Add Automated Feed form with Feed Type set to “Inventory — stock quantities per vendor warehouse”, showing the Files and File Format sections filled in and the “Read columns from the vendor” button with a green “filename — N columns” result beside it (placeholder — replace with /docs-images/vendors/inventory-feeds-setup.png)

The quantity column

An inventory feed maps exactly one field. In the Column Mapping section the only choice in the field dropdown is Quantity On Hand.

  • The value must parse as a whole number. A row whose quantity is blank, textual, or decimal fails with bad quantity “…” and is written to the failure report — the rest of the file still applies.
  • A negative quantity is clamped to zero. Some vendors ship negatives as a backorder artefact; treating them as zero is right, and clamping also keeps that item counted as listed so the snapshot sweep does not treat it as dropped.
  • If no quantity column is mapped, the whole run fails before reading a row: no quantity column mapped (expected a mapping to ‘quantity’).

Locations and multi-warehouse vendors

Every projected quantity has to land at a location, so at least one location mapping is required — the feed cannot be saved without one.

Control What it does
Location Code Column The feed column naming the vendor’s warehouse, e.g. a DC or RSC code. Leave blank if the file has one implicit location.
Location mapping rows Vendor code → one of your locations. Add one row per warehouse code you want to receive.

Two shapes are supported:

  • Single-warehouse vendor. Leave Location Code Column blank and configure exactly one mapping row. Every row in the file goes to that location. If the column is blank and there is more than one mapping, every row fails with feed has no location column and location_mapping is not a single entry.
  • Multi-warehouse vendor. Set Location Code Column and add one mapping row per code. Each row goes to the location its code maps to. A code in the file with no mapping fails that row with no location mapping for vendor DC code “…” — the rest of the file still applies, so an unmapped DC shows up as a block of failures rather than a broken run.

Codes are matched against the file byte for byte. Enter only the code, exactly as it appears — no label, no arrow, no surrounding text, and no spaces. Pasting something like CA02 → Main DC is rejected when you save, with a message saying so. After you read the vendor’s columns, the form shows the actual value sitting in that column so you can copy a real code instead of typing one from memory.

The location must be one of yours. The mapping is validated against your own locations on save, so a stale or foreign id is refused rather than silently routing stock somewhere unexpected.

📷 Screenshot: The Locations section of an inventory feed, showing the Location Code Column filled in, two mapping rows (vendor code → your location), and the hint below reading “The file’s <column> column reads <code> — enter exactly that, with no label or arrow.” (placeholder — replace with /docs-images/vendors/inventory-feeds-locations.png)

What multi-warehouse changes

With more than one mapped location, the projections are per location and are the per-location truth. The vendor product’s single stock quantity holds whichever location was written last — it is a summary, not an inventory. Read per-location availability from the Inventory screen, not from the vendor product row.

The snapshot sweep is also per location: an item still listed for one warehouse but dropped from another keeps its quantity at the first and has the second zeroed. Only an item missing from every mapped warehouse has its vendor product zeroed as well.

Two inventory feeds on one vendor

Nothing stops a vendor from having two or more inventory feeds, and for a vendor who drops one file per DC that is the right shape. Two rules make the difference between that working and the two feeds fighting each other:

  • Give each feed its own locations. The snapshot sweep runs over every linked item for the vendor, at the locations this feed maps. If two feeds map the same location and both have Full snapshot on, each run zeroes at that location everything the other feed had just loaded, and the availability flaps on every cycle. One location (or set of locations) per feed, no overlap.
  • Turn Full snapshot off on any feed that only covers part of the catalog. The safety floor below compares what the file matched against everything linked to the vendor, not against this feed’s share of it. A feed that legitimately covers a third of the vendor’s items will look like a broken file every single run.

A feed you got wrong can be deleted from the ⋯ menu on its row. Deleting removes its settings and file history; the products it helped create, their vendor part numbers and their costs stay.

Full snapshot: what “missing means gone” means

The Full snapshot — items missing from a file are treated as out of stock at the vendor checkbox is the difference between a feed that only ever raises and lowers numbers and one that can also take an item to zero.

It is on by default for new inventory feeds, and it is the correct setting for a vendor whose file is a complete availability snapshot — which is what an 846 normally is.

  • On. After the file is applied, every linked item the file did not list is set to zero, at every mapped location. An item that disappeared from the vendor’s file has gone out of stock at the vendor; silently keeping yesterday’s number is how you oversell something the vendor cannot ship.
  • Off. Items missing from the file keep their last known quantity indefinitely. Only use this if the vendor sends deltas rather than a full list — and understand that nothing will ever take an item to zero except the vendor explicitly sending a zero.

A duplicate is not a second opinion. Vendors routinely repeat the same part number several times in one snapshot; the first row for a given (part number, location) wins and later repeats are skipped and counted separately in the run summary, so the tallies stay explicable.

The safety floor

A full snapshot is a dangerous instrument pointed at your entire drop-ship assortment. If the file cannot be read the way the feed expects — the vendor added a column, the delimiter changed, the download truncated, an HTML error page got staged where a CSV should be, or the part-number column was mis-set — then almost nothing resolves, and “zero everything I didn’t see” would take the whole assortment out of stock everywhere at once.

So before it zeroes anything, the importer checks its own coverage. If the file matched fewer than half of the linked items for that vendor, it refuses:

refusing to zero unlisted stock: the feed matched only 812 of 13,204 known items (6%) —
expected the vendor's full catalog, so this file looks wrong (column count, delimiter,
or a truncated download) [0 rows failed]

What that means in practice:

  • The run fails. You see it on the feed row as an error, and the file is released so it can be re-driven once the cause is fixed.
  • The quantities the file did carry are already applied. The refusal stops the zero sweep, not the per-row updates that ran before it. Nothing is rolled back and nothing is lost.
  • Nothing was zeroed. That is the entire point.
  • A dry run trips it too. The floor is enforced on every run, so a misconfigured feed fails at the dry-run step rather than in production.

⚠️ Warning: Do not “fix” this by turning off Full snapshot to push the file through. A file that matched 6% of your items is a file you cannot read, and applying it as a delta silently accepts whatever handful of quantities it did parse. Find out why coverage collapsed first — compare the file’s column count against Expected Columns, re-run Read columns from the vendor, and check the part-number column still names a real header.

The floor measures the file against every item linked to the vendor, which is why it is also the thing that catches a Full-snapshot feed pointed at a partial file. There are two legitimate ways to be permanently below half: a vendor that genuinely sends a partial file every night, and one inventory feed among several that each carry a slice of the catalog. Neither should have Full snapshot on.

Zero quantities and stock status

When a row’s quantity is zero, the vendor product’s stock status is set to backordered rather than available. Every other quantity sets it to available. The projected sellable quantity is zero either way — the status is a label on the vendor product describing why it is zero, not a separate switch on whether the item can be sold.

ℹ️ Note: This behaviour is enabled when the feed is created and there is no control for it in the feed editor today. If you have a vendor whose zeros mean “unknown” rather than “none”, contact ILLUMA support rather than working around it in the file.

Running it

A new feed is off, and it cannot be switched on until it has run once. Until then the row reads “Not verified yet — run a dry run to see what this feed would do. It writes nothing.” and the toggle is locked, labelled Dry run first.

  1. Dry run — click Dry run on the feed row (or pick Dry run — writes nothing from the ⋯ menu). It reads the newest matching file, computes the entire outcome, and writes nothing at all: no vendor products, no projections, no zeroing. It still enforces every check, including the safety floor, so a misconfigured feed fails here instead of in production. The run is queued and picked up by the worker on its next cycle, so it can take a few minutes to start and a large file takes a while to read.
  2. Read the result — the row shows the last run’s tallies. If they look right, continue.
  3. Enable it — flip the toggle. A newly enabled feed does not run immediately; the first scheduled run lands one full interval later, and the toast says so. That is deliberate: enabling should never fire a live import against your stock before anyone has looked at it.
  4. Run now — for an out-of-schedule run, use Run now, which replaces Dry run as the row’s primary button once the feed is enabled. It confirms first (“This will update stock levels from the vendor’s current file”), because unlike a dry run it writes. If there is no new file waiting, it re-reads the last ingested file rather than doing nothing quietly. A live run is refused while the feed is off — “Enable the feed before running it for real. A dry run works either way and writes nothing.”

A feed will not start a second job while one is still running — you will see skipped: a job for this feed is still running instead.

📷 Screenshot: An inventory feed row after a successful run, showing the “Last run” badge, the rows count, the applied / unknown SKU / failed stat tiles, the “View run details →” link, and the Enabled toggle (placeholder — replace with /docs-images/vendors/inventory-feeds-run-result.png)

Reading the results

The feed row summarises the last run in three tiles:

Tile What it counts Is it a problem?
applied — stock levels set Distinct (part number, location) pairs written. Not rows: a vendor that lists every item twice does not double this. No. This is the number you want.
unknown SKU — no catalog link yet Rows for items the vendor sells and you have not linked. Normally no. A vendor lists their whole catalog and you carry a subset, so on most feeds this is the biggest number in the run. It only matters if it is rising — that means the product feed has fallen behind.
failed — rows we could not read Rows rejected for a concrete reason: unreadable quantity, empty part number, unmapped warehouse code, wrong column count, a torn line. Yes, look at these.

Duplicate rows are counted too, but they are not one of the three tiles — they are recorded on the run summary and in the worker log, because a vendor repeating a part number is normal and does not need a stat of its own.

View run details → opens the full run, with total rows, processed, successful, errors, timings, and — when anything failed — a Download report button. The report is a CSV with one row per rejection:

row,vendor_sku,error_reason
1043,7241503,"bad quantity ""N/A"""
1044,7241511,"no location mapping for vendor DC code ""CA07"""
2210,,empty vendor SKU

A very broken file is not allowed to build a hundred-thousand-row report; beyond a large cap the remainder is kept as a count and reported alongside.

Writes are diffed, so a steady state is cheap and quiet: a quantity that has not changed is not rewritten, which also means it does not emit a pointless channel update. A run that applies few changes on a large file is usually healthy, not broken.

📷 Screenshot: The run detail page for a vendor inventory job, showing Total Rows / Processed / Successful / Errors and the amber “Some rows didn’t import — Download report” panel (placeholder — replace with /docs-images/vendors/inventory-feeds-run-detail.png)

Troubleshooting

What you see What it means What to do
no vendor_products aliases exist for this vendor — run the catalog feed first Nothing links this vendor’s part numbers to your products yet. Run the vendor’s product feed and apply its review, then re-run this one.
refusing to zero unlisted stock: the feed matched only N of M known items Coverage fell below half. Either the file did not parse the way the feed expects, or this feed only ever covers part of the vendor’s catalog. Check delimiter, column count and the part-number column against the real file. If the file is genuinely partial, untick Full snapshot on that feed — never to force a file you cannot read.
feed has no column “…” The part-number column named in the feed is not in the file’s header. The message lists the headers that are there. Re-run Read columns from the vendor and pick the column from the list.
no quantity column mapped No column is mapped to Quantity On Hand. Add the mapping row.
vendor feeds require a header row First row is a header is unticked, or the file arrived without one. Tick it, or ask the vendor for a headered file.
expected N columns, got M (many rows) The vendor changed the file’s shape and Expected Columns still holds the old number. Confirm the new shape is intentional, then update Expected Columns.
no location mapping for vendor DC code “…” The file carries a warehouse code you have not mapped. Add a mapping row for that code, or accept that DC’s rows will be skipped.
feed has no location column and location_mapping is not a single entry Location Code Column is blank but several locations are mapped. Either name the location column, or reduce the mapping to one entry.
Location code “…” looks like a label (on save) A mapping row holds more than the bare code — an arrow, a name, or a space. Enter only the code, exactly as it appears in the file.
real (non-derived) inventory row exists at this location — refusing to project vendor stock onto it The mapped location already holds your own counted stock for that product. Map the vendor to a location of its own. Never share a picking location with a vendor mirror.
a kit’s derived inventory row exists at this location The mapped location holds a bundle’s computed availability for that product. Same fix: give the vendor its own location.
Enable the feed before running it for real Run now was used on a feed that is still off. Dry run it, then enable it, then run.
Rows applied, storefront shows nothing in stock The products are not drop-ship eligible. Set Dropship product or Use dropship as fallback on the products, or set the product feed’s Fulfillment mode to something other than Leave alone and re-apply the matches.
Quantities look right in ILLUMA but a marketplace still shows zero Working as designed. Vendor-mirror availability is deliberately excluded from Amazon, eBay, Google and Walmart quantity pushes. If you want marketplace quantity for these items, they need real stock you hold.
Availability flaps between the vendor’s number and zero every cycle Two inventory feeds on this vendor map the same location and both have Full snapshot on, so each run zeroes what the other loaded. Give each feed its own location, or turn Full snapshot off on the partial one.
Queued run never seems to start The worker claims requested runs on its own poll cycle. Give it a few minutes. If the row still shows a queued spinner long after, check the feed’s last error.

More symptoms, across every kind of vendor feed, are in Troubleshooting Vendor Feeds.

Next

Once availability is flowing, the pieces that use it are Product Feeds for keeping the links and costs current, The Review Queue for applying the matches that make a product drop-ship eligible in the first place, and Bulk Import for the stock you actually own and count yourself.

← PreviousThe Review QueueNext →Vendor Categories