Size charts and variant groups
Two more areas of the catalog can be managed through the API: selection guides, which are the size charts shown on product pages, and variant groups, which link separate products together on the storefront (for example, one product per colour).
Selection guides
Reading selection guides needs selection-guides:read. Creating, updating, deleting and attaching them needs selection-guides:write.
List size charts
| Parameter | Type | Meaning |
|---|---|---|
| search | string | Matches the guide name. |
| category | string | tops, bottoms, dresses, outerwear, footwear, accessories or other. |
| enabled | boolean | true or false. |
| updatedSince | ISO 8601 time | Guides changed at or after this time. Inclusive. |
| includeProductCount | boolean | Adds productCount to each guide. Off by default. |
| page, pageSize, after | Paging, as for products. |
Results are newest updatedAt first, with the same pagination object as GET /products.
Get, create, update and delete
GET /selection-guides/{id}returns one guide, includingproductCount.POST /selection-guidescreates a guide and returns it with status201. Onlynameis required.PATCH /selection-guides/{id}changes only the fields you send. A body with no writable field returns400.DELETE /selection-guides/{id}deletes a guide and returns{ "deleted": true, "id": 17 }. It's refused with409 conflictwhile products still use the guide, and the error carriesproductCount. Detach it first.
POST always creates a new guide. Guide names don't have to be unique, so there's no upsert by name. Keep the id you get back and use PATCH for later changes.
How size-chart data works
- Cells are free text.
36-38,One sizeand38are all valid, because a size chart is a published table, not a set of measurements. - The cell shape follows
defaultUnit. WithdefaultUnitset toimperialormetric, a cell is{ columnId, imperial, metric }. WithdefaultUnit: nullthe guide has no units and a cell is{ columnId, value }. This matches what your storefront receives. - Rows refer to columns by
columnId. If you leave out ids, they're generated by position:c1,c2for columns,r1,r2for rows andm1,m2for measurements. - A cell that names a column that doesn't exist is rejected, not dropped, so a chart can't silently lose a column.
- On
PATCH,columns,rowsandmeasurementsreplace the whole list. Send the complete list each time. - Validation lists every problem at once in the error's
errorsarray.
Other fields: label (link text on the product page), itemTitle, brandLogo (an https URL), measurements (how-to-measure entries with name, description and diagramUrl), additionalNotes (HTML), isEnabled and syncEnabled. syncStatus, lastSyncedAt and syncError are read-only.
| Limit | Value |
|---|---|
| Columns | 50 |
| Rows | 500 |
| Measurements | 50 |
| Name, label, item title | 255 characters |
| Column name, size label | 100 characters |
Attach a size chart to products
Send up to 1,000 SKUs and a mode:
| Mode | What it does |
|---|---|
| add | Attaches the guide to the listed products. This is the default. Other products are left alone. |
| remove | Detaches the guide from the listed products. Other products are left alone. |
| set | Makes the listed products the complete list carrying the guide. Products not listed lose it. |
set is idempotent: sending the same list again changes nothing, which suits a scheduled job. set with an empty list detaches the guide from every product.
matchedis how many SKUs were found, andchangedhow many products were actually written.detachedis reported insetmode only.- SKUs that match no product come back in
unknownSkusrather than failing the call.
Attaching or detaching a guide updates the products' updatedAt, so updatedSince polling sees the change. It doesn't fire a webhook.
GET /selection-guides/{id}/products lists the products carrying a guide as { id, sku, name }, ordered by product id and paged with page and pageSize.
Variant groups
Creates variant groups and their swatches, images or text labels from the same rows the CSV upload in Fulify accepts, sent as JSON. It needs products:write. Each row is one product's membership of a group. A group is created if no group with that name exists (ignoring case); otherwise the existing group is used.
| Column | Required | Meaning |
|---|---|---|
| group | Yes | Group name. |
| sku | Yes | The member product's SKU. A SKU can appear once per group. |
| label | Yes | This product's option value, such as Blue. |
| display_name | No | The option label shoppers see, such as Colour. Defaults to the group name. |
| display_type | No | swatch (default), image or text. Must be the same on every row of a group. |
| color_hex | For swatch | A colour as #RRGGBB. |
| image_url | For image | The image to show. |
| sort_order | No | Position within the group. |
Column names are forgiving, because spreadsheets vary. For example group_name, option_value, colour_hex and position all work. Values can be strings or numbers.
Validation is all or nothing
If any row fails validation, nothing is written. The response is 422 validation_failed and lists the first 100 problems with line numbers, counting the first row as line 2 as if it sat under a CSV header:
Rows whose SKU matches no product aren't a validation error. They're skipped and listed in unknownSkus, and the other rows are imported.
Result
Send "dryRun": true to validate the rows and see the counts without writing. A missing, empty or oversized rows array (more than 5,000 rows) returns 400 invalid_request. This endpoint is limited to 60 requests a minute per key; see Errors and rate limits.