Field reference

Full and update feed schemas in XML and JSON: envelope, product fields, format differences and per-product attributes.

All feeds share the same envelope and field semantics. The full feed carries every field below; the update feed carries only the fast-moving subset — the ✓ column — see Update feed. The SKU is the unique identifier for every product — use it as your import key.

Feed envelope

XML

<syntechstock>
  <data>
    <count>2828</count>       <!-- products in this file -->
    <currency>ZAR</currency>  <!-- currency of all prices in this file -->
  </data>
  <stock>
    <product>...</product>
    <product>...</product>
  </stock>
</syntechstock>

JSON

{
  "syntechstock": {
    "count": 2828,
    "currency": "ZAR",
    "products": [ { "sku": "..." }, { "sku": "..." } ]
  }
}

CSV has no envelope — a header row plus one row per product, with currency as a per-row column instead.

Product fields

FieldTypeUpdate feedDescription
skustring✓Unique product identifier — use as your unique key
namestring—Product name
pricedecimal✓Your cost price — what you pay Syntech for the item — excluding VAT, in the feed's currency. Always the normal cost; it does not change during a promotion (see Pricing)
rrp_incldecimal✓Recommended retail price, including VAT
recommended_margindecimal✓Suggested margin, based on the normal price (see Pricing)
promo_pricedecimal✓Promotional cost price, excluding VAT — empty (XML) / false (JSON) / N/A (CSV) when not on promotion
promo_starts / promo_endsdate✓Promotion window (inclusive) — empty (XML) / false (JSON) / N/A (CSV) when not on promotion
cptstockinteger✓Stock on hand — Cape Town
jhbstockinteger✓Stock on hand — Johannesburg
dbnstockinteger✓Stock on hand — Durban
nextshipmentetadate✓ETA of the next incoming shipment — empty when none is scheduled
urlstring—Product page on syntech.co.za
descriptionHTML—Full description — features, specifications, what's in the box
shortdescHTML—Short description
weightdecimal—Product weight in grams — 0 when not captured
length / width / heightdecimal—Product dimensions in centimetres — 0 when not captured
featured_imageURL—Primary product image. CSV header: featured image (space, not underscore)
additional_imagesURL list—Gallery images. CSV header: additional images
all_imagesstring—Every image URL, pipe-separated — convenience field for single-column importers. CSV header: all images
categoriesstring—Category names, comma-separated
categoriesaltstring—Category names, pipe-separated
categorytreestring—Hierarchy as Parent > Child; multiple trees pipe-separated. Not present in CSV
categorytreealtstring—Hierarchy as Parent/Child; multiple trees pipe-separated. Not present in CSV
attributescontainer—Product attributes — the set varies per product, see below. In CSV: one column per attribute, from a fixed legacy set
last_modifieddatetime✓ XML/JSONWhen this product's data last changed — useful for change detection on your side. Not present in CSV
currencystring✓ CSV onlyPer-row currency column — CSV has no envelope; in XML/JSON this lives in the envelope

Pricing

price (and promo_price when on promotion) is your dealer cost, excluding VAT — the amount you pay Syntech for the item. rrp_incl is the recommended retail price, including VAT. Worked example: cost 169.00, RRP incl 299.00 → 260.00 excluding VAT (15%), and (260 − 169) ÷ 260 = 35% — the recommended_margin. The margin is calculated against the normal price. Remember to add your margin and VAT when calculating your selling price.

Promotions

price always shows the normal cost — it does not switch to the promo value while a promotion runs. To price correctly, apply this rule in your importer:

If promo_price is populated and today falls between promo_starts and promo_ends (inclusive), use promo_price; otherwise use price.

Always gate on the dates rather than assuming a populated promo_price is currently active. Example: price: 8128.00, promo_price: 7999.00, window 2026-07-30 → 2026-08-30 — your cost is 7999.00 during the window and 8128.00 outside it.

Update feed

The update feed shares the envelope above and covers the same full product set (same count), but each product carries only the fast-moving fields marked ✓ — pricing, promos, branch stock, shipment ETA and last_modified. Omitting names, content, images, categories and attributes makes the file dramatically smaller, which is exactly what you want for frequent syncs.

Recommended pattern: import and refresh content from the full feed periodically, then run the update feed on your frequent schedule — match on sku and update only the fields present. Field semantics are identical to the full feed, including the not-on-promotion representations (false in JSON, empty in XML, N/A in CSV).

XML

<product>
  <sku>DM-12</sku>
  <price>169.00</price>
  <rrp_incl>299.00</rrp_incl>
  <recommended_margin>35.00</recommended_margin>
  <promo_price/>
  <promo_starts/>
  <promo_ends/>
  <cptstock>0</cptstock>
  <jhbstock>0</jhbstock>
  <dbnstock>0</dbnstock>
  <nextshipmenteta>2026-10-02</nextshipmenteta>
  <last_modified>2026-08-18 03:25:40</last_modified>
</product>

JSON

{
  "sku": "DM-12",
  "price": 169,
  "rrp_incl": 299,
  "recommended_margin": 35,
  "promo_price": false,
  "promo_starts": false,
  "promo_ends": false,
  "cptstock": 0,
  "jhbstock": 0,
  "dbnstock": 0,
  "nextshipmenteta": "2026-10-02",
  "last_modified": "2026-08-18 03:25:40"
}

CSV

sku,price,rrp_incl,recommended_margin,promo_price,promo_starts,promo_ends,cptstock,jhbstock,dbnstock,nextshipmenteta,currency
DM-12,169.00,299.00,35.00,N/A,N/A,N/A,0,0,0,2026/10/02,ZAR

CSV specifics to note when parsing: fields that are empty (XML) or false (JSON) are the literal string N/A — don't feed them straight into a number parser; dates use YYYY/MM/DD (slashes, not dashes); currency is a per-row column; and there is no last_modified column.

On promotion — XML example

<product>
  <sku>ELA6470GL</sku>
  <price>8128.00</price>
  <rrp_incl>10999.00</rrp_incl>
  <recommended_margin>15.02</recommended_margin>
  <promo_price>7999.00</promo_price>
  <promo_starts>2026-07-30</promo_starts>
  <promo_ends>2026-08-30</promo_ends>
  <cptstock>0</cptstock>
  <jhbstock>0</jhbstock>
  <dbnstock>0</dbnstock>
  <nextshipmenteta/>
  <last_modified>2026-08-18 13:11:16</last_modified>
</product>

Note price still shows the normal 8128.00 even though the promotion is active, and nextshipmenteta is empty when no shipment is scheduled.

Delisted products

End of life or delisted products drop out of the feeds entirely, there is no status flag or tombstone record. To detect removals, diff the feed's SKU set against your catalogue after a sync and deactivate/draft anything no longer present.

Before acting on absences, validate that your download parsed completely by comparing the number of products you parsed against the envelope's count . A truncated or partial file should never trigger mass deactivation on your store.

Format differences

Field names match across formats, with the CSV exceptions noted here and in the table above; the shapes differ:

XMLJSONCSV
Envelope<data> block, products as <stock><product> elementscount / currency at top level, products arraynone — header row + one row per product; currency is a per-row column
Numbers (prices, stock, dimensions)text contentnative JSON numberstext
Not on promotionempty <promo_price/> elementsfalse (boolean) — test for false, not nullliteral string N/A
DatesYYYY-MM-DDYYYY-MM-DDYYYY/MM/DD
Image fieldsfeatured_image etc., underscoresfeatured_image etc., underscoresfeatured image, additional images, all images — spaces in the headers
attributeskebab-case elements, CDATA-wrapped — completeobject of kebab-case keys → string values — completeone column per attribute, fixed legacy set — incomplete (see below)
description / shortdescCDATA-wrapped HTMLHTML stringHTML inside quoted cells — use a proper CSV parser, never split on commas
categorytree / categorytreealtpresentpresentnot present
last_modifiedpresentpresentnot present

Full-feed CSV columns

The full-feed CSV flattens attributes into one column per attribute name — but the column set is fixed and is not extended as new attribute types are added. Newer attributes (for example size-class, surface-type, stitched-edges, model-number, manufacturer-part-number, rgb-lighting) never appear in the CSV, even though they exist on those products in XML and JSON.

❗️

If attribute data matters to your integration, use the XML or JSON feed. The CSV will carry legacy attributes.

Within the columns that do exist, any given product only populates the attributes that apply to it. Map columns by header name, never by position. The header row as currently generated:

sku,name,price,rrp_incl,recommended_margin,promo_price,promo_starts,promo_ends,cptstock,jhbstock,dbnstock,nextshipmenteta,url,description,shortdesc,weight,length,width,height,"featured image","additional images","all images",categories,categoriesalt,3g-support,adjustable-pillow,amperage-a,android-version,aspect-ratio,audio-channels,battery-capacity,battery-type,battery-weight,bays,bluetooth,brand,buttons,cable-length-cm,cable-length-m,cable-type,cache,capacity,capacity-mah,channels,charging-port,charging-technology,class,colour,compatibility,connectivity,controller-included,cooler-included,cpu,cpu-cooler-height-mm,cpu-cores,cpu-series,cpu-socket,cpu-speed,curvature,dimm-slots,direction,disk-speed-rpm,dpi,ean,ecc,edging,enclosure,fan-size,fans,form-factor,format,fps,generation,hardness,hardware,has-adapter,hot-swappable,included-controller,input-interface,interface,ir,items,iteration,lighting,lock-type,material,maximum-resolution,memory-bus,memory-capacity,memory-clock-speed,memory-form-factor,memory-generation,memory-speed,microphone,module-type,motherboard-brand,motherboard-support,multiple-displays,noise-cancelling,number-of-fans,number-of-keys,number-of-lithium-ion-cells,output-interface,panel-type,pcie-862,platform,plug,poe,ports,power-delivery,power-delivery-w,power-va,profile,psu-energy-efficient,quickcharge,raincover-resistant,range-m,rank,read-speed,refresh-rate,remote-included,requirement,resolution,screen-size,series,side-panel,size,slots-size,socket,socket-support,software-series,software-version,speed,style,supported-cooler-height,supported-gpu-length-mm,surface,switch-brand,switch-cap,switch-colour,switch-height,switch-quantity,switch-series,thickness,tip,touch,usb-ports,voltage-v,warranty,water-resistant,watt-hours,wattage-w,weight-limit-kg,write-speed,currency

Full-feed JSON example (trimmed)

{
  "sku": "DM-12",
  "name": "Keychron Desk Mat - Pink",
  "price": 169,
  "rrp_incl": 299,
  "recommended_margin": 35,
  "promo_price": false,
  "promo_starts": false,
  "promo_ends": false,
  "cptstock": 0,
  "jhbstock": 0,
  "dbnstock": 0,
  "nextshipmenteta": "2026-10-02",
  "url": "https://www.syntech.co.za/product/keychron-desk-mat-pink/",
  "additional_images": ["...02.png", "...03.png"],
  "categories": "Computer peripherals, Mousepads, Coming Soon",
  "categorytree": "Computer peripherals > Mousepads|Coming Soon",
  "attributes": {
    "colour": "Pink",
    "surface-type": "Cloth (Control)",
    "brand": "Keychron",
    "warranty": "None"
  },
  "last_modified": "2026-08-18 03:25:40"
}

Attributes vary per product

Attribute names are kebab-case, and the set differs by product type — a keyboard exposes different attributes to a power station. Full feed only. Don't hardcode a fixed attribute list; discover them dynamically or map only the ones you need. brand, warranty, model-number and manufacturer-part-number are common across most products.

<attributes>
  <colour><![CDATA[ Pink ]]></colour>
  <size-class><![CDATA[ XXL / Desk ]]></size-class>
  <surface-type><![CDATA[ Cloth (Control) ]]></surface-type>
  <brand><![CDATA[ Keychron ]]></brand>
  <warranty><![CDATA[ None ]]></warranty>
</attributes>

Did this page help you?