# Publish a complete draft

```http
POST /v1/garments/{garment_id}/publish
```

Source: https://docs.tryyoursize.com/api/reference/operations/publishcataloggarment/

**Key scopes:** `garments:publish`. A secret key (`sk_`) has every scope; a restricted key (`rk_`) needs the scopes listed.

The version shoppers are fitted against from now on, for every product of its fit group. The same checks as Studio: every required point of measure for every size, fabric, the fit approval when the store requires it, every shop size mapped, and the plan's styles (402). Test answers drafts, live answers published versions only.

## Authentication

Secret key (`sk_…`) or restricted key (`rk_…`) from your server: `Authorization: Bearer sk_…`.

## Parameters

- `garment_id` (path, `string (uuid)`, required): A garment *version* (garment_versions.id). A fit group (garments table) is `fit_group_id`.
- `Idempotency-Key` (header, `string`, optional): A unique value per logical request (a UUID v4 is ideal), 1-255 printable ASCII characters. With a secret or restricted key, the first response is stored for 24 hours per store and mode: a retry with the same key and the same body gets the stored response back (header `Idempotent-Replayed: true`); the same key with a different body is `422 idempotency_key_reused`; a retry while the first request still runs is `409 idempotency_key_in_use`. Responses with a 5xx status are not stored, so a retry runs again.

## Responses

### 200

Published (`GarmentVersion`)

- `id` (`string (uuid)`, required)
- `product_id` (`string (uuid)`, required)
- `version` (`integer`, required)
- `status` (`"draft" | "published" | "retired"`, required)
- `category` (`"tshirt" | "shirt" | "sweater" | "jacket" | "dress" | "skirt" | "jeans" | "trousers" | "shorts" | "leggings" | "polo" | "hoodie" | "footwear"`, required): The garment type; it sets which POMs are needed (`footwear` has a size chart instead).
- `fit_intent` (`"skinny" | "slim" | "regular" | "relaxed" | "oversized"`, required): The designer's intended silhouette; sets the ease targets the fit judgement compares against.
- `sizes` (`string[]`, required)
- `poms` (`POMTable`, required): Garment measurements per size: size label → POM code → millimetres. Widths are flat half-measurements. See GET /v1/studio/garment_dictionary for codes and plausible ranges.
- `grading` (`GradingRule`, optional): How the POM table was derived: the base size's values plus, per POM, the increment (mm) between each pair of consecutive sizes (len = number of sizes - 1). The table stays the source of truth.
  - `base_size` (`string`, required)
  - `increments_mm` (`object`, required)
- `fabric` (`Fabric`, required): What the tech pack / mill sheet says.
  - `name` (`string`, optional)
  - `construction` (`"jersey" | "rib" | "interlock" | "fleece" | "pique" | "plain_weave" | "twill" | "denim" | "satin" | "other"`, optional)
  - `composition` (`FiberShare[]`, required)
    - `fiber` (`"cotton" | "polyester" | "elastane" | "viscose" | "modal" | "lyocell" | "wool" | "linen" | "polyamide" | "silk" | "acrylic" | "other"`, required)
    - `pct` (`number (double)`, required)
  - `weight_gsm` (`number (double)`, optional): Areal density, g/m².
  - `stretch_warp_pct` (`number (double)`, optional): Stretch along the warp (lengthwise), percent.
  - `stretch_weft_pct` (`number (double)`, optional): Stretch along the weft (crosswise), percent.
  - `notes` (`string`, optional)
- `import_id` (`string (uuid)`, optional)
- `issues` (`GarmentIssue[]`, required): What still blocks publishing (errors) or deserves a look (warnings).
  - `severity` (`"error" | "warning"`, required)
  - `code` (`string`, required): e.g. out_of_range, not_graded, missing_pom, composition_total
  - `field` (`string`, required): category | fit_intent | sizes | poms | grading | import | fabric.<field>
  - `size` (`string`, optional)
  - `pom` (`string`, optional)
  - `params` (`IssueParams`, optional): The values in `message`, for clients that word the finding in their own language (keys depend on `code`, e.g. value_mm, min_mm, max_mm, prev_size, fiber, max). Numbers are plain decimals ("." separator); lengths in mm.
  - `message` (`string`, required): English text; clients in other languages can word it from code, size, pom and params.
- `created_at` (`string (date-time)`, required)
- `updated_at` (`string (date-time)`, required)
- `published_at` (`string (date-time)`, optional)
- `season` (`string`, optional)
- `tolerances_mm` (`TolerancesMM`, optional): Spec-sheet tolerance per POM code, ± mm (e.g. {"chest_width": 10}). Optional; the flat preview uses ±5 mm when a POM has none.
- `spec_source` (`SpecSource`, optional): Where the POM table came from, kept for audit. Set by Studio's paste/import.
  - `kind` (`"manual" | "paste" | "xlsx" | "csv" | "pdf" | "workbook" | "clo" | "browzwear"`, required)
  - `filename` (`string`, optional, max length 255)
- `footwear` (`FootwearChart`, optional): A footwear version's size chart (category `footwear`). The version's `sizes` must be the chart's labels in the chart's `size_system`, in row order (fittings collapsed). Footwear has no POMs and no 3D fit check.
  - `shoe_type` (`"sneaker" | "dress" | "boot" | "sandal"`, required): Sets the room left in front of the toes that a size is chosen for.
  - `size_system` (`"eu" | "uk" | "us_men" | "us_women" | "mondopoint"`, required): A shoe size system: `eu` (Paris points), `uk`, `us_men`, `us_women`, or `mondopoint` (foot length in mm).
  - `basis` (`"foot_length" | "foot_length_max" | "last_length"`, required): What `length_mm` is: the foot length each size is made for (`foot_length`), the longest foot for the size (`foot_length_max`, "up to 25.5 cm"), or the shoe's inside (last) length (`last_length`).
  - `rows` (`FootwearChartRow[]`, required, max 120 items)
    - `labels` (`object`, required): The size's label in each system the brand uses, e.g. {"eu": "40", "uk": "6.5"}. The label in the chart's `size_system` is the size shoppers and the store see.
    - `length_mm` (`number (double)`, required): The length the chart's `basis` names (foot length, longest foot, or the shoe's inside length).
    - `fitting` (`string`, optional, max length 16): Optional width fitting, e.g. narrow, regular, wide, E, EE. Rows of one size share its length.
    - `width_mm` (`number (double)`, optional): Optional width at the ball (inside the shoe, or the foot width the fitting is made for).
    - `girth_mm` (`number (double)`, optional): Optional ball girth.
- `elastic_waist` (`boolean`, optional): Waistband: true = elastic pull-on, false = fixed band (button or zip), null = not stated.
- `elastic_waist_inferred` (`boolean`, optional): True when elastic_waist was inferred from text, not stated by the brand.
- `fit_group_id` (`string (uuid)`, optional): The fit group (garments row) this version belongs to (absent until grouped).
- `rise_type` (`"low" | "mid" | "high"`, optional): Where the waistband is worn (bottoms); null = not stated.
- `rise_type_inferred` (`boolean`, optional): True when rise_type was inferred from text, not stated by the brand.
- `worn_at_mm` (`number (double)`, optional): Height of the waistband top relative to the natural waist, mm, negative = below; null = derived from the rise measurements.

### 401

Missing or invalid credentials (`Error`)

### 403

Not allowed (`Error`)

### 404

Not found (`Error`)

### 409

Conflicts with the current state (duplicate SKU, editing a published version) (`Error`)

### 422

Values to fix (each issue points at the field, size and POM) (`GarmentRejected`)

## Example

```bash
curl -X POST https://api.tryyoursize.com/v1/garments/<garment_id>/publish \
  -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \
  -H "TYS-Version: 2026-10-25"
```

## In the SDKs

- Node.js: [`tys.garments.publish()`](https://docs.tryyoursize.com/reference/node/garments-publish.md)
- Python: [`tys.garments.publish()`](https://docs.tryyoursize.com/reference/python/garments-publish.md)
