Importing Size Charts

Brandmachine's Designer uses your size specs (the measurement tables you give a factory) to put real dimensions on a design. You bring them in with one REST call that takes a JSON file. This page describes that file and what happens to it.

If your specs live in Excel, PDF or a PLM system, you convert them to this JSON format first. Brandmachine does not read spreadsheets, images or PDFs, because every customer sheet is laid out differently and a guess at what a column means would end up as a wrong number on a design.

The Short Version

  1. Convert each size chart to the JSON format below. Measurements are whole numbers in hundredths of a centimetre, so 63.20 cm is 6320.
  2. Use measurement names from the closed list in Measurement Codes. A name that is not on the list rejects the file.
  3. Send the file with ?dryRun=true first. Check that the report says "dryRun": true, because a misspelled parameter is ignored and the file is imported for real. Fix what the report lists.
  4. Send it again without dryRun. Nothing is saved unless the whole file is valid.

Send a File

POST https://production.api.brandmachine.shop/api/size-charts/import

The request is multipart/form-data with the JSON file in the file field. Authenticate with an API token, as for every file upload:

curl -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -F "file=@size-charts.json" \
  "https://production.api.brandmachine.shop/api/size-charts/import?dryRun=true"

Who can import: the import changes your shared library, so it needs the Creator role or higher. This applies to an API token as well: a token only works if it was created with that role or a higher one. With a lower role the call fails with HTTP status 403 and the reason You do not have permission to do this. Reading charts back needs no more than a Viewer token.

The request body can be up to 32 MB. No smaller limit on charts, sizes or rows is enforced.

The Response

Once the file reaches the importer, the response is HTTP status 200, also when the file is invalid. A request without a file field is refused with an HTTP error before that. Problems are in the report, not in the status code.

{
  "dryRun": true,
  "imported": false,
  "charts": [
    {
      "code": "BOY-TSS-BASIC-FIT",
      "name": "TSS BASIC FIT",
      "department": "boys",
      "garmentType": "tee-short-sleeve",
      "sizes": ["104", "116", "128", "140", "152", "164", "176"],
      "baseSize": "140",
      "rowCount": 1,
      "incrementRowCount": 0,
      "action": "CREATE"
    }
  ],
  "errors": [],
  "warnings": []
}
FieldMeaning
dryRuntrue when you sent ?dryRun=true. A dry run never saves anything.
importedtrue only when the charts were saved. Always false on a dry run, and whenever errors is not empty.
chartsOne summary per chart in the file.
charts[].patternGroupPresent only when the chart has a pattern_group. Fields that have no value are left out of the report, not sent as null.
charts[].actionCREATE for a new chart code, SUPERSEDE when the code already exists in your library (see Re-importing).
charts[].incrementRowCountRows that have grade steps but no absolute value. See Rows.
errorsProblems that stop the import. Each has kind (INVALID) and a message, plus chartCode and rowKey when the problem belongs to a chart or a row.
warningsThings worth a look that never block the import.

The File Format

A file holds one or more charts. This is the smallest valid file:

{
  "format_version": 1,
  "source": { "file": "QC BOYS 26.xlsx" },
  "charts": [
    {
      "code": "BOY-TSS-BASIC-FIT",
      "name": "TSS BASIC FIT",
      "garment_type": "tee-short-sleeve",
      "product_group": "tops",
      "department": "boys",
      "pattern_group": null,
      "sizes": ["104", "116", "128", "140", "152", "164", "176"],
      "base_size": "140",
      "rows": [
        {
          "code": "SLEEVE_LENGTH",
          "origin": "CB",
          "source_label": "Sleevelength from CB",
          "convention": "full",
          "base_hundredths": 3750,
          "grade_deltas_hundredths": {
            "104": -800,
            "116": -500,
            "128": -250,
            "140": 0,
            "152": 250,
            "164": 500,
            "176": 750
          },
          "tolerance": {
            "minus_hundredths": -80,
            "plus_hundredths": 80,
            "raw": "-0,8/+0,8"
          }
        }
      ]
    }
  ]
}

The value of a measurement at any size is the base value plus the grade step for that size. In the example, the sleeve length is 37.50 cm at size 140 and 45.00 cm at size 176.

File

FieldTypeRequiredNotes
format_versionintegerYesMust be 1.
source.filestringNoThe name of the sheet the charts came from. If you leave it out, the name of the uploaded file is stored.
chartsarrayYesAt least one chart.

Other keys in the file, such as a note about where the sheet came from, are ignored.

Charts

FieldTypeRequiredNotes
codestringYesYour identifier for the spec. Unique within the file. Importing the same code again replaces the chart (see Re-importing).
namestringYesA readable name shown in the app.
departmentstringYesYour target group, for example boys or women. Free text. Brandmachine suggests charts within one department only.
garment_typestringYesYour own word for the garment, for example tee-short-sleeve or trouser. Free text, not a fixed list.
product_groupstringNoA broader grouping such as tops or bottoms. Free text.
sizesarray of stringsYesThe size labels in grading order, smallest to largest. No duplicates.
base_sizestringYesThe size the base values belong to. Must be one of sizes.
pattern_groupstring or nullNoGive charts that are readouts of one pattern (for example one tee finished with two trim widths) the same value. Use null when the chart has no siblings. An empty string is rejected.
rowsarrayYesAt least one row.

Rows

A row is one measurement across all sizes.

FieldTypeRequiredNotes
codestringYesA code from Measurement Codes.
originstring or nullNoWhere the measurement is taken from, from the list in Origins.
source_labelstringYesThe row's name in your sheet, for example 1/2 Chest. Kept as written.
conventionstringYeshalf if the value is half of the full girth (a flat-laid chest, for example), otherwise full. Lower case. Brandmachine does not check this against the measurement.
base_hundredthsinteger or nullNoThe value at the base size. null makes an increment row that has grade steps only.
grade_deltas_hundredthsobjectYesThe difference to the base value, one entry per size, keyed by size label. The entry for the base size must be 0.
toleranceobject or nullNoSee below. Leave it out when your sheet gives none.
positionintegerNoDisplay order. Defaults to the row's place in the array. Unique within the chart.

Row identity. A row is addressed by its code together with its origin, written CODE@origin, for example SLEEVE_LENGTH@CB. The same code with a different origin is a different measurement, and two rows in one chart cannot share a code and origin. If a design has two constructions of the same garment, put them in separate charts that share a pattern_group.

Increment rows. A row with base_hundredths: null is allowed. The chart then counts as incomplete: that row shows no values and cannot be adjusted in the app.

Tolerance.

FieldTypeNotes
minus_hundredthsintegerZero or negative.
plus_hundredthsintegerZero or positive.
rawstringThe tolerance as it appears in your sheet. Kept for reference.
parse_failedbooleanOptional. If you set it to true, both bounds must be null.

Send both bounds or neither. A tolerance with no bounds and no raw text is rejected.

Units

Every number is an integer in hundredths of a centimetre. There is no inch input. If your sheet uses inches, convert to centimetres first. Round to two decimals of a centimetre before scaling, so 63.204 cm becomes 63.20 and then 6320. Brandmachine cannot detect a wrong rounding order, so the converter has to get this right.

Measurement Codes

Measurement names are a closed list, because rows have to be comparable between charts. Free-text names are exactly what makes two customers' charts impossible to line up. Map your own spellings to these codes in your converter. A code that is not on the list rejects the whole file, and the error names the code it did not recognise and suggests up to three close ones (Unknown POM code X (normalised: Y). Did you mean A, B, C?).

ARMHOLE_DEPTH, ARMHOLE_HALF, ARMHOLE_LEN_BACK, ARMHOLE_LEN_FRONT,
ARMHOLE_RAGLAN_BACK, ARMHOLE_RAGLAN_FRONT, ARMHOLE_STRAIGHT,
ARTWORK_HEIGHT, ARTWORK_POS_ARMHOLE, ARTWORK_POS_CB, ARTWORK_POS_CF,
ARTWORK_POS_HSP, ARTWORK_POS_RIB, ARTWORK_POS_SS, ARTWORK_WIDTH,
BACK_LENGTH, BACK_NECK_DROP, BACK_POCKET_HEIGHT, BACK_POCKET_POS_CB,
BACK_POCKET_POS_WB, BACK_POCKET_WIDTH, BACK_RISE, BACK_WELT_POCKET_HEIGHT,
BACK_YOKE, BICEP, BOTTOM_CUFF_HEIGHT, BOTTOM_WIDTH, BOTTOM_WIDTH_RELAXED,
BOTTOM_WIDTH_STRETCHED, BUTTON_1_FROM_BOTTOM, BUTTON_1_FROM_TOP,
BUTTON_SPACING, CHEST, COLLAR_HEIGHT, COLLAR_LENGTH, COLLAR_POINT,
COLLAR_STAND, CORD_LENGTH, CUFF_HEIGHT, ELBOW, ELBOW_POSITION,
FIRST_BUTTON, FLAP_HEIGHT, FLAP_LENGTH, FLY_LENGTH, FLY_WIDTH,
FRONT_NECK_DROP, FRONT_POCKET_INSERT_LEN, FRONT_POCKET_INSERT_WB,
FRONT_POCKET_LEN_INSIDE, FRONT_POCKET_LEN_SS, FRONT_POCKET_LEN_WB,
FRONT_POCKET_WIDTH_SS, FRONT_POCKET_WIDTH_WB, FRONT_RISE, HIP,
HIP_POSITION, HOOD_HEIGHT, HOOD_WIDTH, INSEAM, KNEE, KNEE_POSITION,
LEG_OPENING, LEG_OPENING_RELAXED, LEG_OPENING_STRETCHED, LOWER_ARM,
MIN_NECK_STRETCH, NECK_RIB_HEIGHT, NECK_WIDTH, OUTSEAM, PLACKET_LENGTH,
PLACKET_WIDTH, POCKET_HEIGHT_CENTRE, POCKET_LENGTH, POCKET_POS_CF,
POCKET_POS_HSP, POCKET_POS_SS_BOTTOM, POCKET_POS_SS_TOP, POCKET_WIDTH,
POCKET_WIDTH_BOTTOM, POCKET_WIDTH_MIDDLE, POCKET_WIDTH_TOP, SHOULDER,
SHOULDER_FORWARD, SIDE_POCKET_LENGTH, SIDE_POCKET_POS, SIDE_POCKET_WIDTH,
SLEEVE_LENGTH, SLEEVE_LENGTH_INCL_CUFF, SLEEVE_OPENING,
SLEEVE_OPENING_RELAXED, SLEEVE_OPENING_STRETCHED, SLIT_LENGTH, THIGH,
TRIM_WIDTH, WAIST, WAISTBAND_HEIGHT, WAIST_HEIGHT, WAIST_RELAXED,
WAIST_STRETCHED

New measurements are added when a customer's sheet needs one. If you need a code that is missing, contact support@brandmachine.shop.

Origins

origin says where a measurement is taken from. It is not interchangeable: a sleeve length from centre back includes half the shoulder, one from the shoulder point does not. Leave it null when the measurement has no such reference. The allowed values are case-sensitive:

CB, CF, HSP, armhole, armpit, bottom, crotch, cuff, neckline seam,
ribbing seam, seam to seam, shoulder point, side seam, waistband

Validation

The import is all or nothing. If anything in the file produces an error, nothing is saved, including the charts that were fine. A file that is not valid JSON, or does not fit the format, comes back as one error: The file is not in the size chart upload format: followed by the reason.

Errors you may see, in the message of an entry in errors:

MessageFix
Unsupported format_version N; this backend reads version 1.Set format_version to 1.
The file contains no charts.Add at least one chart.
Chart code appears more than once in this file.Give each chart its own code.
code is empty., name is empty., department is empty., garment_type is empty.Fill the field.
sizes is empty., sizes contains a size more than once.List each size once.
base_size X is not one of sizes [...].Use a label that appears in sizes.
The chart has no rows.Add rows.
pattern_group is empty; leave it null when the chart has no siblings.Use null instead of an empty string.
Two rows share position N. Every row needs its own position.Make positions unique, or leave them out.
Unknown POM code X ... Did you mean ...?Use a code from the list.
Unknown origin X. Allowed: ...Use one of the origins, spelled exactly.
Two rows share the key K. ...Split the constructions into separate charts with the same pattern_group.
source_label is empty.Fill the field.
convention must be half or full, got X.Use half or full, lower case.
grade_deltas_hundredths must have exactly one entry per size in [...].Give one step per size, keyed by label.
grade_deltas_hundredths must be 0 at the base size X.Set the base size's step to 0.
tolerance bounds have the wrong sign: minus must be ≤ 0 and plus ≥ 0.Check the signs.
tolerance bounds must be both set or both null.Send both bounds or neither.
tolerance is marked parse_failed but has bounds; an unreadable tolerance must have null bounds.Remove the bounds or the flag.
tolerance has neither bounds nor raw text; leave tolerance out when the source gives none.Remove the empty tolerance.

Warnings do not stop the import. They point at values that look like typos:

kindWhen
UNREADABLE_TOLERANCEA tolerance has raw text but no bounds. It is stored as text and never used as a limit.
IMPLAUSIBLE_TOLERANCEA tolerance bound is wider than 1.00 cm and more than 10% of the base value.
GRADING_REVERSES_DIRECTIONThe values get smaller where they should get larger (or the other way round) between two sizes. The warning lists the values and the size where it turns.

Re-importing

The chart code is the key. When you import a code that is already in your library, the new chart replaces it: the old one is marked as superseded and stays on the designs that were already made from it, and new designs use the new one. Charts that are not in the file are left alone, so you can send only the charts that changed.

The report shows SUPERSEDE for these charts, so a dry run tells you what will be replaced before anything changes.

What Happens After the Import

Imported charts are your library of standard specs. They are not matched to Shopify products by size label.

In the Designer, you pick a department for a design, and Brandmachine shortlists up to three candidates from that department based on the design description (charts that share a pattern_group count as one candidate). You choose one, and the design gets its own copy of the rows. You can then adjust values on that copy, and the Designer draws the base-size measurements onto the technical drawings. Your uploaded charts stay untouched, because they are your standard specs.

The chart operations are in the GraphQL reference: sizeCharts and sizeChart to read, matchSizeChart, createDesignerSizeChart, setSizeChartAdjustments and annotateSizeChart on a design, and deleteSizeChart.

Checklist for Your Converter

  • Output centimetres as integers in hundredths, rounded to two decimals first.
  • Map every measurement name to a code from the list, and keep the original name in source_label.
  • Set convention to half for flat-laid girths.
  • Include grade_deltas_hundredths for every size, with 0 at the base size.
  • Keep the same code for a chart across imports so it supersedes the old one.
  • Build each code from what makes the chart different (for example the trim width), never from its position in the sheet. Otherwise a reordered sheet swaps the data between sibling charts.
  • Run with ?dryRun=true in your pipeline and fail on a non-empty errors array.