Premium Apparel API — Changelog

Every change to the API surface, newest first, with the date it reached production.

API reference · Integration FAQ · Error reference


Versioning policy

What counts as breaking

What we commit to

What is not breaking, and ships without notice

Additive changes are still recorded here, so this page is worth watching even if you never expect to be broken by it.


2026-11-14

Added — product images on GET /v1/feeds/products: image_url (the colour's main image), image_urls (all of the colour's images) and hero_urls (the style's lead images), as full public HTTPS URLs from the website catalogue. Products not on the website have image_url: null and empty lists.

2026-11-13

Added — more product fields on POST and PUT /v1/products (privileged): sales_account, cog_account, asset_account, stocked_type, article (text), pieces_per_unit (whole number), exclude_from_api, we_stock_this, we_buy_this (booleans). A product created without duplicate_id can now be given the values the template product does not carry.

Added — GET /v1/feeds/purchase-orders (privileged). A paged sync feed of purchase orders with their lines, for planning systems. Backfill returns every open PO plus POs invoiced in the last 24 months (from to change it); since returns every PO whose header or any line changed. Cursor paging (limit up to 200, next_cursor), an as_of to feed back as the next since, and removed for PO numbers that stopped being purchase orders. Lines carry the original, received and outstanding quantity, cost, purchase_line_pk and the line's received date. Needs purchase_orders.read.

Added — GET /v1/feeds/products and GET /v1/feeds/suppliers (privileged), same paging contract. Products: supply data (supplier and code, buy price and currency, NZD average and last cost, lead time, minimum buy quantity, carton quantity, flags) and per-SKU stock on hand, allocated and available; since includes stock movements. Suppliers: the supplier master (no bank details). Products need products.read; suppliers need purchase_orders.read.

Added — GET /v1/feeds/sales-orders (privileged), same paging contract. Orders and invoices by order date (default 24 months back), with per-SKU lines: quantity, shipped, list and net price ex GST, discount, line total. Credits are negative-quantity invoices with the original invoice where known. since catches header and line changes. Needs orders.see_all.

2026-11-12

Added — more product attributes on POST /v1/products and PUT /v1/products (privileged). All optional, and on create each overrides the value copied from duplicate_id:

Added — size_group_name on POST /v1/products. The exact name of an existing GarmentWorks size group, as an alternative to size_group. It never creates a group and must match exactly one, otherwise that product fails with unknown_size_group or ambiguous_size_group. Sending both fails with size_group_conflict.

Documented — what duplicate_id copies: every field of the source product, before the request's own values are applied. See POST /v1/products in the partner reference.

Added — product website data: GET, POST, PUT and DELETE /v1/product-attributes (privileged). Read, create, change and delete the per-style and per-colour records the website uses (Title, Body, Tags, Hero, Images, metafields, Price A-D and so on). Up to 25 items per write, best-effort with per-item results. Records kept by the Shopify sync are read-only. GET needs products.read, POST and PUT need products.write, and DELETE needs the new scope products.delete_attributes.

Changed — PMS is held per colour on /v1/product-attributes: it needs colour_code, and the Shopify push writes it to each variant of that colour as custom.pms. No PMS records existed before the change.

Added — POST /v1/colour-codes (privileged). Adds Dye colour codes. Never overwrites an existing code. Needs products.write.


2026-11-10

Added — paid on order reads (GET /v1/orders/{our_ref}, GET /v1/orders?order_no=): true when the order is marked as paid. Staff can change it in GW, so it reflects the order as it stands now.

Added — paid on POST /v1/orders (privileged). Send paid: true to create the order already marked as paid, for orders taken after payment. true needs a separate permission on your token and is refused with 403 forbidden without it; false changes nothing. Ask your account contact if you need it.

Added — invoice_to on POST /v1/orders (privileged). Sets the debtor name and postal address printed on the order's packing slip and invoice, for an order placed under one customer on behalf of another. company is required; leave the address fields out to keep the customer's own postal address. The order's customer, pricing and tax are unchanged, and no customer record is changed. It needs a separate permission on your token and is refused with 403 forbidden without it.


2026-11-04

Added — POST /v1/orders/{our_ref}/line-items (privileged) adds lines to an existing order and leaves every line already on it untouched, so it also works on an order that holds the same product on more than one line. Line items take the POST /v1/orders shape, description included, and are grouped the same way. It needs the same line-amendment permission as the PUT. It is not idempotent: sending the same request twice adds the lines twice. Added — add_order_lines, the same operation as an MCP tool.


2026-10-08

Added — discount lines with a negative quantity on POST /v1/orders. A line for the discount product RETDIS may carry a whole negative quantity at a positive price (RETDIS-Uni, quantity -1, price 4.50 takes 4.50 off the order). Every other line still needs a quantity of at least 1, and a negative line without a price is refused. With taxes_included: true the discount price is read GST-inclusive, like every other price on that order.

Changed — how line items become order lines on POST /v1/orders. Line items for the same product that send the same description and the same price (or neither) form one order line, and a size sent twice is now added up. Previously the later quantity replaced the earlier one. Line items for the same product with a different description or price now become separate order lines, so one SKU can appear on several lines. Previously different descriptions were refused with 422, and different prices fell back to the price book.

Added — on_hold on the POST /v1/orders response (order reads have it since 2026-10-07). A token can be set up so that every order it creates is placed on Hold, to be released by staff before it can be picked. Ask your account contact.

Added — catalogue fields on /v1/products: per size barcode (string), units_per_carton and rrp (GST-inclusive); per style packing_units. Each is null where not held. Because every style's content changed, the first ?since= poll after this shows every style as changed, once.

Changed — PUT /v1/orders/{our_ref}/line-items (privileged) needs the line-amendment permission on your token, and refuses with 409 conflict (details.reason: "ambiguous_lines") an order that holds more than one line for the same product, since it cannot tell those lines apart. Added — set_order_lines, the same operation as an MCP tool.


2026-10-07

Added — dispatch details on order reads (GET /v1/orders/{our_ref}, GET /v1/orders?order_no=): shipments (one { carrier, tracking_number } per courier consignment), courier_ticket_no, ship_via, date_shipped, on_hold, and quantity_shipped on each line. Each line's price is now filled in when the line holds one; the field was already in the published schema but came back empty. See Dispatch information on order reads.


2026-10-06

Fixed — POST /v1/orders no longer reports a created order as a failure. A large order could take longer than the 5-second upstream timeout. The API then answered 503 upstream_unavailable, while the order was still created. Order creation now has 30 seconds. If it still runs out, the API looks the order up by order_no before answering: you get the normal 201 if it exists, otherwise a 503 with details.reason: "outcome_unknown", which means "look it up before retrying". See /docs/errors.

Changed — PUT /v1/orders/{our_ref}/line-items (privileged) only amends an order your token can read, under the same visibility rules as GET /v1/orders/{id}. Any other order returns 404. A moved_to order your token cannot read is refused with the same 422 as a moved_to that does not exist.


2026-10-05

Added — product attributes on POST /v1/products and PUT /v1/products (privileged). All optional:

Changed — a product created from duplicate_id no longer inherits the template's comment or barcodes. Both start empty and take only what you send, because a template's spec text and GTINs describe the template: inherited barcodes made every clone scan as its source product. Every other attribute is still inherited when omitted.

Added — update_products over MCP. PUT /v1/products is now available to AI assistants as a tool. As over REST, it needs the products write permission on your account and is refused with 403 forbidden without it.


2026-10-01

Fixed — line_items[].price on POST /v1/orders is now honoured. The price was validated and accepted but never reached the order line, so every line was priced from the price book. A line with a price is now created at that price, with the price book and customer discount set aside for it; a line without one is priced from the price book as before. 0 creates a free line.

Added — line_items[].description on POST /v1/orders. Optional. When present and not blank it replaces the product's own description on that order line, so a generic code can name the actual job ("Embroidery - Left Chest"). One order line holds one product, so lines of the same product share a description: the first non-blank one is used, and two different descriptions on the same product are refused with 422 validation_error before anything is created. Not accepted by PUT /v1/orders/{our_ref}/line-items.

Additive: a new optional request field, and a documented field that now does what it said.


2026-09-21

Added — PATCH /v1/orders/{our_ref}. Amends the header of an order that already exists: the Attention contact, the delivery address, the required-by date and the internal message. Until now nothing in the API could touch an order after creation, so an order pushed or imported with a detail missing had to be finished by hand.

Only the fields you send are changed; an omitted field is left alone and a field sent as "" is cleared. Two of them behave differently on purpose, and both are worth reading before you call it:

Changing the required-by date carries it down onto the order's lines, as changing it in GW does.

Only orders still in the Order state can be amended; once converted to an invoice the call returns 409 conflict with details.reason = order_not_amendable. An order somebody has open for editing answers 409 conflict too, with details.reason = conflict — that one is transient and safe to retry. The response names the fields that actually changed, so a field sent with the value it already held comes back absent rather than as an error. See the error reference for both.

Additive: a new endpoint, no change to any existing one.


2026-09-15

Added — Integration FAQ. A new documentation page answering the questions integrators ask before they build: rate limits, GST treatment of prices, incremental-sync semantics, recovering removals, telling discontinued apart from out of stock, read-only tokens, and testing without a sandbox.

Added — this changelog, and the versioning policy above. Both are new commitments, not a change to the API surface.

Clarified — prices are exclusive of GST. No behaviour changed; this was always the case and is now stated in the reference and the FAQ. The one exception is the no-token RRP catalogue, whose prices are GST-inclusive. See Are prices exclusive of GST?.

Clarified — rate limits. There is no enforced rate limit and no endpoint returns 429. If one is introduced it will be announced here first and will use 429 with Retry-After.


Earlier history

Per-change dates were not recorded before this page existed, so the entries below are grouped by month rather than by day. Everything listed is live.

2026-08

2026-06

2026-04