Data onboarding

File specifications, column by column

The exact shape of every file you send us: the columns, the types, the values that identify a row, and what happens when something does not validate.

14 min read9 sectionsERP developers · BI teams
Examples describe a configurable workflow, not a contractual commitment. Confirm security, retention, schedules, integrations and automation for your own deployment before relying on them.
On this page
01

How to read this page

The conventions every file follows, so you only have to learn them once.

Every file is a comma-separated text file with one header row. The rules below are the same for all of them, so your export job implements them once. Column order does not matter, and columns we do not recognise are ignored and listed back to you rather than treated as an error — you can add fields to your extract without breaking anything.

Rule; What we accept; Notes
RuleWhat we acceptNotes
FormatCSV — comma separated, double-quotedNo spreadsheets, no fixed width, no pipe or tab delimiters.
EncodingUTF-8, no byte-order markA byte-order mark corrupts the name of your first column.
Header rowRow 1, lower case with underscoresExactly the names in this page. Order is irrelevant; extra columns are ignored.
Line endingsUnix or WindowsMixed extract hosts are normal; both work.
Dates2026-07-25Year-month-day only. Never DD/MM/YYYY, never a spreadsheet date number.
Timestamps2026-07-31T22:15:00ZUTC, with the Z.
Yes / noY or Ntrue/false, 1/0 and Yes/No are also accepted, in any case.
Empty valuesLeave the field emptyNever write NULL, NA, N/A or a dash. Those four are rejected on purpose, so a broken export is loud instead of silently zero.
Numbers12.50 and -12.50No thousands separators, no currency symbols, no bracketed negatives.
Percentages0.0500 means 5%Fractions, never percents. See the warning below.
Leading zeros"0990001440016"Quote any identifier that can start with a zero, so it survives the round trip.
Several values in one fieldPipe separatedUsed only by a handful of columns, all flagged in the tables.
Compression.gz on any fileOptional below 50 MB uncompressed, required above it.
MoneyAlready convertedEvery money column, in every file, is in one reporting currency. We do not convert currencies.

Where files go, and what to call them

You write into a private folder that only your workspace can read or write — how that isolation is enforced is in Security and data protection. Each feed has its own folder, and that folder name is what tells us which feed the file is — the file name itself is a label and a cross-check, never the router. Use any unique value per delivery for the upload folder.

File names are <feed_name>_<YYYYMMDD>.csv, optionally .csv.gz, where the date is the business date the data describes rather than the date you sent it. Split parts take _p<NN>of<NN> and corrections take _r<N>; both are set out in The data we need from you.

<your-workspace>/inbox/feed=inventory_position/<upload-id>/inventory_position_20260731.csv.gz
<your-workspace>/inbox/feed=sales_weekly/<upload-id>/sales_weekly_20260731.csv.gz
<your-workspace>/control/2026-07-31/_manifest_1.json          <- written last

The words used in every table

Required
We cannot use the row without it. On a daily file the row is rejected; on a master or configuration file the whole file is.
Optional
Leave it empty and we apply the default given in the Notes column. Empty is a real answer — do not send a placeholder.
Conditional
Required only in a stated case, and it must be empty otherwise. Size curves are the only feed that uses this.
The columns that uniquely identify a row
Listed under every feed. We match what you send against what we already hold on those columns: if the row is there we update it, if it is not we add it. Sending the same file twice is safe.
What happens to a row that fails
Day-to-day files (stock, sales, orders, forecast) reject only the bad row and load the rest. Master and configuration files are all-or-nothing: one bad row and nothing loads, because a half-loaded product list quietly makes every roll-up on the dashboard wrong with no error on screen.
Rejected rows come back to you
Each delivery produces a rejects file listing the row number, the column, the value we saw, the reason, and a suggested fix — for example that store “0115” probably meant store 115, Riverside Mall.
02

Load order

Products before inventory, stores before sales. Anything that arrives early waits.

Files reference each other. A sales row names a size and a store, so both must exist first. You can drop everything into one delivery and let us work out the order — the list below is what that order is, and it is the order to use for your first load.

  1. 1
    Roots — nothing depends on anything
    fiscal_calendar, dc, vendor, product_style_color, store_group
  2. 2
    Sizes, stores and vendor terms
    product_sku, store, vendor_style_terms
  3. 3
    Mappings, curves and date windows
    store_dc_mapping, product_dc_mapping, product_store_eligibility, size_curve, store_status_period, product_status_period, product_supersession, new_store, constraint_set, product_store_rule
  4. 4
    Transactions
    inventory_position, purchase_order, sales_weekly, price_promo
  5. 5
    Forecast
    forecast_granular, then forecast_layer if you send one
  6. 6
    The completion file (manifest), last
    It says the delivery is finished. Write it only once every file above has finished uploading. Section 07 is entirely about it.
Feed; How often; Needs loaded first
FeedHow oftenNeeds loaded first
fiscal_calendarOnce a year, then on change
dcOn change
vendorOn change
product_style_colorDaily
store_groupOn change
product_skuDailyproduct_style_color
storeWeekly, or on changestore_group, if you use group names
vendor_style_termsMonthly, or on changevendor, product_style_color
store_dc_mappingWeekly, or on changestore, dc
product_dc_mappingWeekly, or on changeproduct_sku, dc
product_store_eligibilityWeekly, or on changeproduct_style_color, store
size_curveOn changeproduct_style_color, product_sku, store
store_status_periodOn changestore
product_status_periodWeeklyproduct_style_color
product_supersessionOn changeproduct_style_color
new_storeOn changestore
constraint_setOn change
product_store_ruleOn change
inventory_positionDailyproduct_sku, store, dc
purchase_orderDailyproduct_sku, dc, vendor
sales_weeklyDailyfiscal_calendar, product_sku, store
price_promoWeeklyfiscal_calendar, product_style_color
forecast_granularWeeklyfiscal_calendar, product_sku, store
forecast_layerWeeklyfiscal_calendar, product_style_color
03

Master files

Your planning universe: the calendar, the locations, the range and the sizes.

You send these once at onboarding, then again whenever they change. Most teams find it easier to send a complete refresh nightly or weekly than to work out what changed; that is fine and is what we expect. A complete refresh never deletes anything — a product or store that disappears from the file is retired, not erased, so two years of history survives a bad extract.

fiscal_calendar — your retail week grid

Which calendar dates make up week 17 of your 2026. Every weekly grid in the platform is addressed by week_start_date, so this file is the root of the whole load.

File name: fiscal_calendar_20260731.csv

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
week_start_datedaterequired2026-07-25The first day of the retail week. Must fall on your week-start weekday.
week_end_datedaterequired2026-07-31Must be week_start_date plus six days. We check it rather than assume it.
fiscal_yearwhole numberrequired2026Four digits.
fiscal_week_nowhole numberrequired171 to 53, unique within the fiscal year.
week_labeltext 16optional07/25-07/31The heading shown above the week on every grid.
month_labeltext 16optionalJuly_2026How weeks roll up into months.

Uniquely identifies a row: week_start_date.

week_start_date,week_end_date,fiscal_year,fiscal_week_no,week_label,month_label
2026-07-18,2026-07-24,2026,16,07/18-07/24,July_2026
2026-07-25,2026-07-31,2026,17,07/25-07/31,July_2026
2026-08-01,2026-08-07,2026,18,08/01-08/07,August_2026

dc — your distribution centres

File name: dc_20260731.csv

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
dc_codetext 32requiredDC-CENTNo spaces. This is also the location_code you send on DC stock rows.
dc_nametext 128optionalCentral DC
citytext 64optionalColumbus
countrytext 64optionalUSTwo-letter country code preferred.
serves_channelspipe listoptionalB&M|EcomAny of B&M and Ecom. Defaults to both.
statustext 16optionalActiveActive or Inactive. Defaults to Active.
capacity_unitswhole numberoptional950000Single units, not cases.

Uniquely identifies a row: dc_code.

dc_code,dc_name,city,country,serves_channels,status,capacity_units
DC-EAST,East Coast DC,Newark,US,B&M|Ecom,Active,820000
DC-CENT,Central DC,Columbus,US,B&M|Ecom,Active,950000
DC-WEST,West Coast DC,Ontario,US,B&M|Ecom,Active,760000

store — every selling location

Including e-commerce, which you send as a store with channel set to Ecom. Nothing in the platform works without stores.

File name: store_20260731.csv

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
store_codetext 32required115Quote it if it can carry leading zeros.
store_nametext 128optionalRiverside MallShown on every store screen and in the rejects file.
channeltextrequiredB&MExactly B&M or Ecom.
regiontext 64optionalMidwestA filter everywhere, and usable in assortment rules.
statetext 64optionalMISame.
store_tiertext 32optionalAYour own grading scale. Filter and rule scope.
store_group_defaulttext 64optionalFlagshipShould match a group you send in store_group. An unknown name is a warning, not a rejection.
open_datedateoptional2011-08-19
close_datedateoptionalLeave empty unless status is Closed.
capacity_unitswhole numberoptional240Units the store can physically hold. Caps what allocation sends it.
statustext 16optionalOpenOpen, Closed or Pending. Defaults to Open. Temporary closures belong in store_status_period.

Uniquely identifies a row: store_code.

store_code,store_name,channel,region,state,store_tier,store_group_default,open_date,close_date,capacity_units,status
115,Riverside Mall,B&M,Midwest,MI,A,Flagship,2011-08-19,,240,Open
704,Northgate Center,B&M,East,VA,A,Flagship,2009-11-12,,250,Open
ECOM01,Ecom - National,Ecom,National,,Online,Ecom,2015-01-01,,,Open

vendor — the suppliers you raise orders on

File name: vendor_20260731.csv

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
vendor_idtext 64requiredV-100
nametext 128requiredApex Footwear Co.Shown on every purchase order.
incotermtext 16optionalFOBFOB, DDP, EXW, CIF or DAP.
currencytext 8optionalUSDThree-letter code.
statustext 16optionalActiveActive or Inactive. Defaults to Active.

Uniquely identifies a row: vendor_id.

vendor_id,name,incoterm,currency,status
V-100,Apex Footwear Co.,FOB,USD,Active
V-200,Northwind Athletic,DDP,USD,Active
V-300,Corso Leather Works,FOB,USD,Active

product_style_color — every style-colour you plan

The thing a buyer orders and an allocator allocates: 994257 “Trailblazer Runner White/Frost”, not the style behind it and not the individual size.

File name: product_style_color_20260731.csv

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
style_color_idtext 64required994257Quote it to preserve leading zeros.
descriptiontext 255optionalTrailblazer Runner White/FrostShown on every grid. Worth sending.
style_idtext 64optional9942The parent style.
colortext 64optionalWhite/FrostUsable as a rule scope.
divisiontext 64optionalFootwearSee the note below — optional, but stocking rules scope on it.
departmenttext 64optionalMen's FootwearSame.
classtext 64optionalRunningThe header is class, not class_name.
subclasstext 64optionalRoad Running
product_typetext 32optionalCoreYour own vocabulary — Core, Seasonal, Fashion.
lifecycle_statustext 32optionalReg Mid LifeYour own vocabulary — New, Reg Mid Life, Clearance.
product_grouptext 64optionalPerformance Running
launch_datedateoptional2025-10-18Drives the New Products alert for the first four weeks.
image_urltext 1024optionalhttps://cdn.example.com/img/994257.jpgMust start https. Plain http is rejected because it breaks the page it is shown on.
unit_costdecimaloptional54.00Falls back to the cost on the purchase order line when empty.
unit_retaildecimaloptional120.00Used for value KPIs when net_sales is absent.
active_flagY/NoptionalYDefaults to Y. N means retired and excluded from planning.

Uniquely identifies a row: style_color_id.

style_color_id,description,style_id,color,division,department,class,subclass,product_type,lifecycle_status,product_group,launch_date,image_url,unit_cost,unit_retail,active_flag
994257,Trailblazer Runner White/Frost,9942,White/Frost,Footwear,Men's Footwear,Running,Road Running,Core,Reg Mid Life,Performance Running,2025-10-18,https://cdn.example.com/img/994257.jpg,54.00,120.00,Y
998503,Dash Runner K Blue/Volt,9985,Blue/Volt,Footwear,Kids' Footwear,Running,Kids Running,Core,Reg Mid Life,Kids Performance,2026-01-10,https://cdn.example.com/img/998503.jpg,28.00,65.00,Y

product_sku — every size of every style-colour

The thing that is physically counted. Stock, sales, orders and forecast all reference a size, so nothing transactional loads before this file does.

File name: product_sku_20260731.csv

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
sku_idtext 64required99425703Unique across your whole range, not just within the style.
style_color_idtext 64required994257Must already exist in product_style_color.
sizetext 32required8As shown to the customer. Spell it identically here and in size_curve.
size_sort_orderwhole numberoptional2Left-to-right order of size columns. Defaults to the order sizes first appear.
barcodetext 64optional"0990001440016"Quote it — barcodes start with zeros.

Uniquely identifies a row: sku_id. A size may appear only once within a style-colour; two rows claiming size 9 make the size curve unresolvable and the file is rejected.

sku_id,style_color_id,size,size_sort_order,barcode
99425701,994257,6,0,"0990001440016"
99425702,994257,7,1,"0990001440023"
99425703,994257,8,2,"0990001440030"

vendor_style_terms — how the vendor actually ships

The four numbers that turn “we need 137 pairs” into an order you can place: lead time, minimum, pack size and order multiple.

File name: vendor_style_terms_20260731.csv

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
vendor_idtext 64requiredV-100Must exist in vendor.
style_color_idtext 64required994257Must exist in product_style_color.
lead_time_dayswhole numberoptional21Vendor to distribution centre. Defaults to 21.
moq_eacheswhole numberoptional48Minimum order in single units, not packs. Defaults to 0.
order_multiple_packswhole numberoptional1Defaults to 1.
pack_size_eacheswhole numberoptional6Units per pack. Defaults to 1.
order_cycletext 16optionalmonthlyweekly or monthly. Defaults to monthly.
valid_fromdateoptional2026-01-01
valid_todateoptionalEmpty means open-ended.

Uniquely identifies a row: vendor_id + style_color_id. One row per pair — a style sourced from two vendors gets two rows.

vendor_id,style_color_id,lead_time_days,moq_eaches,order_multiple_packs,pack_size_eaches,order_cycle,valid_from,valid_to
V-100,994257,21,48,1,6,monthly,2026-01-01,
V-100,994258,21,48,1,6,monthly,2026-01-01,
V-100,994260,21,48,1,6,monthly,2026-01-01,
04

Daily files

Stock, orders and sales — the three files that decide what tonight's run recommends.

These arrive every night before the overnight run. They are large and they come from operational systems, so we reject bad rows one at a time rather than losing a whole night’s position to one size that exists in the till system but not yet in your product file.

inventory_position — where the stock is right now

How many of each size are sitting in each store and each distribution centre. This is the single most important file you send.

File name: inventory_position_20260731.csv.gz

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
sku_idtext 64required99425703Must exist in product_sku.
location_typetextrequiredSTORESTORE or DC, upper case.
location_codetext 32required115A store_code when STORE, a dc_code when DC. Checked against both lists.
ohwhole numberrequired0On hand, single units. May be negative — that is a real till condition and it loads.
itwhole numberoptional6In transit. Defaults to 0.
oowhole numberoptional0On order. Defaults to 0. On DC rows this should agree with your open orders.
as_of_datedaterequired2026-07-31The date the position was taken. Always send it, even when nothing moved.

Uniquely identifies a row: sku_id + location_type + location_code.

sku_id,location_type,location_code,oh,it,oo,as_of_date
99425703,STORE,115,0,6,0,2026-07-31
99425704,STORE,115,2,6,0,2026-07-31
99425703,STORE,704,4,0,0,2026-07-31
99425703,DC,DC-CENT,312,144,300,2026-07-31

purchase_order — what is on the water

Every open order on a vendor: what is coming, to which distribution centre, and when. One row per order line, with the order-level columns repeated on each line.

File name: purchase_order_20260731.csv

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
po_idtext 64required99425703DC-CENT202617Your order number, whatever shape it is. We keep it verbatim and never parse it.
vendor_idtext 64optionalV-100An unknown vendor loads with a blank vendor and a warning — we would rather keep the units.
dc_codetext 32requiredDC-CENTMust exist in dc. An unknown one rejects the row.
order_placed_datedateoptional2026-07-06
po_statustextoptionalApprovedApproved, Pending, Received or Cancelled. Defaults to Approved.
sku_idtext 64required99425703The line is at size level.
style_color_idtext 64optional994257Derived from the size when empty. If it disagrees with the size's real parent the row is rejected.
po_delivery_datedaterequired2026-08-08Expected receipt at the distribution centre. Drives the inbound week in the projection.
on_order_unitswhole numberrequired300Single units. May be negative for a cancellation.
line_statustextoptionalApprovedSame four values. Defaults to the order status.
costdecimaloptional54.00Landed cost per unit.

Uniquely identifies a row: po_id + sku_id + po_delivery_date. Whenever an order appears in a file we replace all of its lines with the ones in that file, so re-sending your whole open order book every night is safe and is what we recommend.

po_id,vendor_id,dc_code,order_placed_date,po_status,sku_id,style_color_id,po_delivery_date,on_order_units,line_status,cost
99425703DC-CENT202617,V-100,DC-CENT,2026-07-06,Approved,99425703,994257,2026-08-08,300,Approved,54.00
99425704DC-CENT202617,V-100,DC-CENT,2026-07-06,Approved,99425704,994257,2026-08-08,360,Approved,54.00
99425703DC-EAST202618,V-100,DC-EAST,2026-07-13,Approved,99425703,994257,2026-08-15,180,Approved,54.00

sales_weekly — what actually sold

Units and money, per size, per store, per retail week. At onboarding send 104 weeks if you can and never fewer than 52. After that, send the last four weeks every night — restating the recent weeks absorbs late postings, voids and returns without any risk of double counting.

File name: sales_weekly_20260731.csv.gz

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
week_startdaterequired2026-07-25Must be a week_start_date in fiscal_calendar.
sku_idtext 64required99425703Must exist in product_sku.
store_codetext 32required115Must exist in store.
unitsdecimalrequired6Net of returns. May be negative — a returns-only week is a legitimate row.
net_salesdecimaloptional684.00After discount, excluding tax.
cogsdecimaloptional324.00
margindecimaloptional360.00Defaults to net_sales minus cogs. Send it only if your margin definition differs.
discount_pctdecimaloptional0.0500A fraction. 0.0500 is 5%.

Uniquely identifies a row: week_start + sku_id + store_code.

week_start,sku_id,store_code,units,net_sales,cogs,margin,discount_pct
2026-07-18,99425703,115,7,798.00,378.00,420.00,0.0500
2026-07-25,99425703,115,6,684.00,324.00,360.00,0.0500
2026-07-25,99425703,704,5,600.00,270.00,330.00,0.0000
05

Weekly files

Your demand forecast, and the prices you plan to sell at.

forecast_granular — your demand forecast

Your forecasting engine’s answer: how many of each size each store will sell each week. One file is one version of the forecast; the newest one becomes the version every screen uses, and we keep the previous ones so accuracy can be measured against them.

File name: forecast_granular_20260731.csv.gz

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
week_startdaterequired2026-08-01Must be a week in fiscal_calendar.
sku_idtext 64required99425703Must exist in product_sku.
store_codetext 32required115Must exist in store.
channeltextoptionalB&MB&M or Ecom. Defaults to B&M.
forecast_unitsdecimalrequired6.400Zero or more. Decimals are expected and kept.
forecast_retaildecimaloptional768.00Forecast value at retail.
lower_bounddecimaloptional4.100Low end of your prediction interval.
upper_bounddecimaloptional9.200High end. Must be at least lower_bound.
launched_flagY/NoptionalYDefaults to Y. N marks pre-launch weeks, which are left out of cover calculations.
model_versiontext 64optionalfc-2026.07.3The same value on every row of the file. Two values in one file rejects it.
generated_attimestampoptional2026-07-31T22:15:00ZWhen you produced the forecast. Defaults to when we receive it.

Uniquely identifies a row: week_start + sku_id + store_code, within one forecast version.

week_start,sku_id,store_code,channel,forecast_units,forecast_retail,lower_bound,upper_bound,launched_flag,model_version,generated_at
2026-08-01,99425703,115,B&M,6.400,768.00,4.100,9.200,Y,fc-2026.07.3,2026-07-31T22:15:00Z
2026-08-01,99425704,115,B&M,7.100,852.00,4.600,10.100,Y,fc-2026.07.3,2026-07-31T22:15:00Z
2026-08-01,99425703,704,B&M,5.200,624.00,3.300,7.500,Y,fc-2026.07.3,2026-07-31T22:15:00Z

forecast_layer — the planner’s view, if you already hold one

The forecast stack per style-colour: the engine number, the planner override, the financial plan, and which of them is being used. Send it only if your own planning system already holds overrides or plan numbers we would otherwise lose. If you do not send it, we build the same view by adding up forecast_granular, and planner edits apply on top of that.

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
week_startdaterequired2026-08-01Must be a week in fiscal_calendar.
style_color_idtext 64required994257Must exist in product_style_color.
channeltextrequiredB&MB&M or Ecom.
original_enginedecimaloptional112.400The raw engine number.
adjusted_enginedecimaloptional112.400After your engine's own adjustments.
multiplierdecimaloptional1.000Defaults to 1. Zero is meaningful — it suppresses the week — and is kept as zero.
adjusted_userdecimaloptional120.000A planner override.
mfpdecimaloptional118.000Merchandise financial plan.
demand_sourcetextoptionalENGINEENGINE, MFP or USER — which number is in force. Defaults to ENGINE.
final_forecastdecimaloptional112.400The number you want planned against.
ly_actualsdecimaloptional98.000Last year, for the comparison column.

Uniquely identifies a row: week_start + style_color_id + channel.

price_promo — planned price and markdown

What you plan to charge, per style-colour, per channel, per week. Without it the discount panel on the forecast screen is empty: markdown still drives demand, the planner just cannot see why.

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
week_startdaterequired2026-08-01Must be a week in fiscal_calendar.
style_color_idtext 64required994257Must exist in product_style_color.
channeltextrequiredB&MB&M or Ecom.
regular_pricedecimaloptional120.00
effective_pricedecimaloptional114.00After markdown. Higher than regular_price raises a warning.
discount_pctdecimaloptional0.0500A fraction. Defaults to 0.
promo_nametext 128optionalBack to School

Uniquely identifies a row: week_start + style_color_id + channel.

06

Configuration files

Sourcing lanes, size curves, assortment and stocking rules.

store_dc_mapping — which centre ships to which store

Without this the allocation engine cannot pick a source and the transfer engine cannot work out a lane. Both steps skip and the Action Center is empty, so treat it as required even though it sits with the configuration files.

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
store_codetext 32required115Must exist in store.
dc_codetext 32requiredDC-CENTMust exist in dc.
primary_flagY/NoptionalYExactly one Y per store. Zero or two rejects the file.
sourcing_prioritywhole numberoptional11 is first choice. Unique within a store.
transit_lead_time_dayswhole numberoptional2Centre to store. Defaults to 7. Not the same as vendor lead time.
active_flagY/NoptionalYDefaults to Y.

Uniquely identifies a row: store_code + dc_code.

store_code,dc_code,primary_flag,sourcing_priority,transit_lead_time_days,active_flag
115,DC-CENT,Y,1,2,Y
115,DC-EAST,N,2,4,Y
704,DC-EAST,Y,1,2,Y

size_curve — how demand splits across the size run

One row per size, with each size’s share as a fraction. You can send one curve for a style-colour everywhere, or a different curve for a store group, or for a single store — the most specific one wins when the allocator reads it.

Column; Type; Required; Example; Notes
ColumnTypeRequiredExampleNotes
style_color_idtext 64required994257Must exist in product_style_color.
scope_typetextoptionalGLOBALGLOBAL, STORE_GROUP or STORE. Defaults to GLOBAL.
store_codetext 32conditionalRequired when scope_type is STORE, must be empty otherwise.
store_group_nametext 128conditionalRequired when scope_type is STORE_GROUP, must be empty otherwise.
sizetext 32required9Must be a size this style-colour actually has in product_sku.
contribution_fractiondecimalrequired0.237000A fraction. The sizes in one curve must add up to 1.
sourcetext 8optionalUSERDefaults to USER for files you send.
curve_versionwhole numberoptional1Defaults to 1.
approved_flagY/NoptionalYDefaults to Y. Curves marked N are ignored by the allocator.

Uniquely identifies a row: style_color_id + scope_type + store_code + store_group_name + size.

style_color_id,scope_type,store_code,store_group_name,size,contribution_fraction,source,curve_version,approved_flag
994257,GLOBAL,,,6,0.065000,USER,1,Y
994257,GLOBAL,,,7,0.129000,USER,1,Y
994257,GLOBAL,,,8,0.204000,USER,1,Y
994257,GLOBAL,,,9,0.237000,USER,1,Y
994257,GLOBAL,,,10,0.204000,USER,1,Y
994257,GLOBAL,,,11,0.108000,USER,1,Y
994257,GLOBAL,,,12,0.053000,USER,1,Y

The remaining configuration files

All optional, all the same shape as the files above, all all-or-nothing. Send them when the underlying policy exists in your systems; skip them and we fall back to the behaviour in the last column.

Feed; What it is; Columns; Identified by; If you skip it
FeedWhat it isColumnsIdentified byIf you skip it
product_dc_mappingWhich centre may hold which size.sku_id, dc_code, eligible_flagsku_id + dc_codeEvery centre may hold everything, so regional exclusives get ordered into centres that never ship them.
product_store_eligibilityYour assortment matrix, stated explicitly.style_color_id, store_code, eligible_flagstyle_color_id + store_codeEligibility comes from your rules instead. With neither, the store dashboard is empty.
store_groupNamed groups of stores — Flagship, Metro, Outlet. One row per store per group.group_name, store_codegroup_name + store_codeGroup-level size curves and rules cannot be used.
product_status_periodDate windows when a style-colour is switched off.style_color_id, status, status_from, status_tostyle_color_id + status_fromA style is either always on or always off; no seasonal suspension.
store_status_periodDate windows when a store is shut for a refit or move.store_code, status (Open, TempClosed, Closed), status_from, status_tostore_code + status_fromA refitting store keeps receiving stock and reads as a stockout for weeks.
product_supersessionThis style-colour replaces that one; carry the history across.old_style_color_id, new_style_color_id, effective_date, transfer_demand_flag, transfer_history_flag, statusold_style_color_id + new_style_color_idReplacement colourways start with no history and trigger new-product alerts.
new_storeStores opening soon and the existing store they copy their plan from.store_code, store_name, opening_date, status, action_required, sister_store_code, sister_scope_division, sister_scope_department, sister_scope_classstore_codeThe New Store Setup screen is empty and an opening store gets no first allocation.
constraint_setMinimum display units and the weeks-of-cover band each part of the range should sit in.name, the nine scope_ columns, min_presentation_units, max_units, target_wos, min_wos, max_wos, priority, valid_from, valid_to, activenameEvery style is held to the same defaults — 2 weeks minimum, 4 target, 8 maximum — so a clearance line and a core runner get identical cover.
product_store_ruleRules that decide assortment automatically: all Running to every A-tier Midwest store.name, priority, the nine scope_ columns, five store_scope_ columns, eligible_flag, valid_from, valid_to, activenameAssortment comes from the explicit matrix instead. With neither, nothing is eligible anywhere.
07

The completion file

One small JSON file that says your delivery is finished and nothing was lost on the way.

Write the completion file (manifest) last. It tells us your delivery is finished, so we do not start loading a stock file that is still uploading, and it lets us check that nothing was lost in transit. It goes in the control folder for the business date, and it is the only JSON file in the whole contract. What we do with it on the night, and what happens when it never arrives, is in How your data flows.

{
  "manifest_version": "1.0",
  "workspace": "your-workspace",
  "delivery_id": "5f2b6c1e-9d3a-4a7c-8f10-6b2d9e4c1a77",
  "business_date": "2026-07-31",
  "generated_at": "2026-07-31T23:40:12Z",
  "source_system": "RETAIL-ERP",
  "sequence": 20260731001,
  "is_complete": true,
  "files": [
    {
      "feed_type": "inventory_position",
      "key": "inventory_position_20260731.csv.gz",
      "bytes": 41533712,
      "sha256": "3b1f8a0c9d47e2a5b6c8f1d0e9a2b4c6d8e0f2a4b6c8d0e2f4a6b8c0d2e4f6a8",
      "row_count": 1842551,
      "encoding": "UTF-8",
      "compression": "gzip",
      "mode": "full",
      "extract_watermark": "2026-07-31T22:00:00Z"
    },
    {
      "feed_type": "sales_weekly",
      "key": "sales_weekly_20260731.csv.gz",
      "bytes": 9822104,
      "sha256": "a7c3e1b5d9f2048a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a",
      "row_count": 412887,
      "encoding": "UTF-8",
      "compression": "gzip",
      "mode": "restate",
      "restate_from": "2026-07-18",
      "restate_to": "2026-07-31"
    },
    {
      "feed_type": "purchase_order",
      "key": "purchase_order_20260731.csv",
      "bytes": 2210344,
      "sha256": "c1e5a9d3b7f0246e8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f",
      "row_count": 18422,
      "encoding": "UTF-8",
      "compression": "none",
      "mode": "full"
    }
  ]
}
Field; Required; What it means
FieldRequiredWhat it means
manifest_versionrequiredAlways 1.0 today.
workspacerequiredYour workspace name, exactly as it appears in your folder path. A mismatch stops the whole delivery.
delivery_idrequiredAny unique value per delivery. Send the same one twice and we record it and do nothing — no double loading.
business_daterequiredThe day this delivery is for. Where it disagrees with the data, the data wins and we raise a warning.
generated_atoptionalWhen your export finished.
source_systemoptionalWhatever you call the system it came from. It goes in the audit trail.
sequenceoptionalIncrement it if you send more than one delivery in a day.
is_completerequiredfalse lets you stream a big delivery in pieces without us starting early. We wait for true.
files[].feed_typerequiredThe feed name, exactly as on this page.
files[].keyrequiredThe file name you uploaded.
files[].row_countrequiredData rows, not counting the header. See below.
files[].sha256requiredChecksum of the file as uploaded. See below.
files[].bytesrequiredSize of the file as uploaded.
files[].encodingoptionalUTF-8.
files[].compressionoptionalgzip or none.
files[].moderequiredfull, delta or restate — see below.
files[].restate_from / restate_toconditionalRequired when mode is restate. The window your file replaces; the rows in the file must actually fall inside it.
files[].extract_watermarkoptionalThe moment your extract read the source system. Useful when a number is questioned months later.

Why the row count and the checksum are there

They are a safety net, not paperwork. The most common real-world failure is not a badly formatted file — it is a truncated one. A stock extract that dies two-thirds of the way through still parses perfectly, still passes every column rule, and quietly tells us that a third of your estate has no stock. Nothing inside the file can catch that. A row count and a checksum can, in one comparison, before a single row is loaded. If either disagrees we load nothing and tell you, rather than half-loading a day.

The three delivery modes

full
The file is the complete current picture for that feed. Anything absent from it is zeroed (stock) or retired (masters), never left behind. inventory_position must always be full.
delta
Only what changed. Anything absent is left exactly as it was. Safe for masters, never accepted for stock.
restate
The file replaces a bounded window completely — used for sales_weekly, price_promo and forecast_granular. State the window in restate_from and restate_to.
08

Validation rules and what they mean

What we reject, what we warn on, what we correct for you.

Three outcomes are possible for anything that does not validate: the row is rejected and the rest of the file loads, the whole file is stopped, or we load it and tell you. Which one applies depends on the file, and it is chosen so that a small operational mess never costs you a day and a systematic mistake never loads quietly.

Situation; Outcome; Why
SituationOutcomeWhy
A sales, stock or forecast row names a size or store we have never seenrow rejectedInventing a placeholder product would give it a blank hierarchy, and every division and class total on the dashboard would then leak units into an unnamed bucket. Because these files are complete or restated, the row comes back by itself on the next delivery once the master catches up.
A stock row names a location code that is not one of your stores or centresrow rejectedOtherwise the position simply vanishes from every store screen with no error anywhere.
A week in a sales, price or forecast file is not in your calendarrow rejectedA one-off bad week is a data error, not a reason to lose the file.
An order line names a vendor we do not knowloaded, with a warningAn order with no vendor label is still an order. Losing the inbound units would be worse than losing the name.
An order line names a distribution centre we do not knowrow rejectedThere is nowhere for the stock to arrive, so there is no usable row.
More rows fail than the file's error budget allows, usually all on the same rulefile stoppedThat is a systematic export problem — every week starting on a Monday when your weeks start on a Saturday — not a scattering of bad rows. Loading the survivors would look like a normal day. The budget per file is listed below.
A master or configuration row references something that does not existfile stoppedThese files define the identity space everything else joins to. A half-loaded product list makes every roll-up wrong with nothing on screen to say so.
A store has no primary distribution centre, or two of themfile stoppedAllocation would be non-deterministic — the same night could source the same store differently.
Status windows for one store or style overlap, or a supersession chain loopsfile stoppedTwo contradictory statuses on one date cannot be resolved, and a loop would never finish.
A complete master file would retire more than 10% of your live products or storesfile stoppedAlmost always a truncated extract rather than a real range cull. We ask you before acting on it.
The row count, size or checksum does not match the completion filefile stoppedA truncated or corrupted upload. Never partly loaded.
Columns we do not recogniseignored, listed backYou add fields to your extracts all the time. Treating that as a failure would train everyone to ignore alerts.
Negative on-hand stockloaded, with an alertIt is a real till condition, not a typo. We load it and raise it if it becomes common.

What we correct for you

  • Header names are trimmed, lower-cased, and spaces become underscores — so Week_Start and week start both land on week_start. Column order never matters.
  • margin defaults to net_sales minus cogs when both are present.
  • style_color_id on an order line is filled in from the size when you leave it empty; line_status defaults to the order status.
  • Yes/no columns accept true, false, 1, 0, Yes and No in any case.
  • A byte-order mark at the start of the file is stripped rather than corrupting your first column name.

How many bad rows are too many

Each file has an error budget. Below it, the bad rows are rejected and the file loads; above it the whole file is held, because at that point the file is telling you something about your extract rather than about your business.

File; Budget; Reasoning
FileBudgetReasoning
inventory_position0.5% of rowsThe stock position is the decision surface. One row in 200 wrong is already too many.
sales_weekly2% of rowsLate product setup is normal and self-heals on the next restatement.
purchase_order2% of rowsSame.
forecast_granular2% of rowsSame.
price_promo2% of rowsSame.
product_store_eligibility2% of rowsAn assortment matrix is transaction-sized; one retired style must not block it.
size_curve5% of curvesCounted per curve, not per row, because a curve is only meaningful whole.
Master and configuration filesZeroAll-or-nothing by design.

The volume check

This is the one that saves the most days. We compare each file’s row count against the median of your last eight successful deliveries of that feed. If it is more than 40% away in either direction, we hold the file and ask you to confirm before loading it. Nothing is rejected and nothing is lost — it simply waits for a yes.

Getting the rejected rows back

Every delivery produces a rejects file you can read from your folder, one row per rejection, with the row number, the column, the value we saw, the reason, and where we can work it out, a suggestion — "0115" did you mean 115 (Riverside Mall)? Most rejects turn out to be a leading zero, a date format, or a product that has not been set up yet, and the suggestion column usually resolves them without anyone opening a support ticket.

09

Download templates

A complete, consistent example set. Every row below is real and loads end to end.

These are the exact files described above, for a small footwear range: five style-colours, the full size 6 to 12 run for 994257, six stores, three distribution centres and three vendors. Every transactional row references only masters that are present in the same set, so you can load the whole thing end to end and see what a good delivery looks like before you write a line of export code.

File; Rows; What is in it
FileRowsWhat is in it
fiscal_calendar.csv7Weeks 13 to 19 of 2026, Saturday to Friday.
dc.csv3DC-EAST, DC-CENT and DC-WEST.
store.csv6Five shops and the e-commerce channel as a store.
vendor.csv3Three suppliers with incoterms.
product_style_color.csv5Men's, women's and kids' running.
product_sku.csv7The complete adult size run 6 to 12 for 994257.
vendor_style_terms.csv5Lead time 21 days, minimum 48, packs of 6.
store_dc_mapping.csv7Includes a secondary centre for store 115.
size_curve.csv7One curve for 994257 that adds to exactly 1.000000.
inventory_position.csv6Store and centre rows, with 994257 engineered as a stockout at store 115.
sales_weekly.csv6Two weeks, with sales, cost and margin that reconcile.
purchase_order.csv6Order and line columns in one file, including a received and a pending order.
forecast_granular.csv6Two forward weeks from one forecast version.
_manifest.example.json3 filesThe completion file, with checksums, row counts and modes.