# TryYourSize Node.js SDK reference --- # Node.js reference (@tryyoursize/node) > The server SDK for Node.js 18+: recommendations, catalog, orders and returns, audit log, webhooks. Source: https://docs.tryyoursize.com/reference/node/ *SDK* · `@tryyoursize/node` · v0.1.0 The official Node.js SDK for the TryYourSize server API. Use it **on your server** with a secret key (`sk_test_…` / `sk_live_…`) or a restricted key (`rk_…`); publishable keys (`pk_…`) are refused. Typed from our OpenAPI spec, with retries, idempotency keys and auto-pagination built in. Node 18 or newer (or pass your own `fetch`). ## Install **npm** ```bash npm install @tryyoursize/node ``` **pip** ```bash pip install tryyoursize ``` ## Initialize **Node.js** ```ts const tys = new TryYourSize(process.env.TRYYOURSIZE_SECRET_KEY!, { maxRetries: 2, // network errors, timeouts, 429, 5xx timeoutMs: 30_000, }); ``` **Python** ```python tys = tryyoursize.TryYourSize(os.environ["TRYYOURSIZE_SECRET_KEY"], max_retries=2, timeout=30.0) ``` Every method maps to one HTTP operation of the [HTTP API reference](https://docs.tryyoursize.com/api/reference.md). Errors are typed: see [Errors](https://docs.tryyoursize.com/reference/node/errors.md) and the [API error codes](https://docs.tryyoursize.com/api/errors.md). ## Client | | | |---|---| | [`new TryYourSize()`](https://docs.tryyoursize.com/reference/node/client.md) | Creates a client for one secret or restricted key. | | [`mode`](https://docs.tryyoursize.com/reference/node/mode.md) | "test" or "live", from the key prefix. | | [`lastResponse`](https://docs.tryyoursize.com/reference/node/last-response.md) | Meta of the last answered request (success or API error). | | [`RequestOptions`](https://docs.tryyoursize.com/reference/node/request-options.md) | Options of one call: the last argument of every method. | ## Recommendations | | | |---|---| | [`recommendations.create()`](https://docs.tryyoursize.com/reference/node/recommendations-create.md) | handle comes from the browser SDK (await tys.recommendationHandle()), products are your SKUs / style IDs. | ## Products | | | |---|---| | [`products.list()`](https://docs.tryyoursize.com/reference/node/products-list.md) | Newest first. | | [`products.create()`](https://docs.tryyoursize.com/reference/node/products-create.md) | tys.products.create() | | [`products.retrieve()`](https://docs.tryyoursize.com/reference/node/products-retrieve.md) | tys.products.retrieve() | | [`products.update()`](https://docs.tryyoursize.com/reference/node/products-update.md) | Replaces the SKU, name and category (all three required). | | [`products.sizeMap.retrieve()`](https://docs.tryyoursize.com/reference/node/products-size-map-retrieve.md) | tys.products.sizeMap.retrieve() | | [`products.sizeMap.save()`](https://docs.tryyoursize.com/reference/node/products-size-map-save.md) | Replaces the size map. | | [`products.garments.list()`](https://docs.tryyoursize.com/reference/node/products-garments-list.md) | Garment versions, newest first (a single page: has_more is always false). | | [`products.garments.createDraft()`](https://docs.tryyoursize.com/reference/node/products-garments-create-draft.md) | Starts a new draft version (sizes, POMs in mm, grading, fabric). | ## Garments | | | |---|---| | [`garments.retrieve()`](https://docs.tryyoursize.com/reference/node/garments-retrieve.md) | tys.garments.retrieve() | | [`garments.updateDraft()`](https://docs.tryyoursize.com/reference/node/garments-update-draft.md) | Replaces a draft's content (published versions never change: 409). | | [`garments.publish()`](https://docs.tryyoursize.com/reference/node/garments-publish.md) | Publishes a complete draft. | ## Fit groups | | | |---|---| | [`fitGroups.list()`](https://docs.tryyoursize.com/reference/node/fit-groups-list.md) | tys.fitGroups.list() | | [`fitGroups.create()`](https://docs.tryyoursize.com/reference/node/fit-groups-create.md) | tys.fitGroups.create() | | [`fitGroups.retrieve()`](https://docs.tryyoursize.com/reference/node/fit-groups-retrieve.md) | tys.fitGroups.retrieve() | | [`fitGroups.linkProducts()`](https://docs.tryyoursize.com/reference/node/fit-groups-link-products.md) | Moves products into the group (they then use its garment). | ## Outcomes | | | |---|---| | [`orders.create()`](https://docs.tryyoursize.com/reference/node/orders-create.md) | tys.orders.create() | | [`returns.create()`](https://docs.tryyoursize.com/reference/node/returns-create.md) | tys.returns.create() | ## Audit log | | | |---|---| | [`auditEvents.list()`](https://docs.tryyoursize.com/reference/node/audit-events-list.md) | tys.auditEvents.list() | ## Webhooks | | | |---|---| | [`webhooks.constructEvent()`](https://docs.tryyoursize.com/reference/node/webhooks-construct-event.md) | Verifies a delivery's TYS-Signature header against the raw request body and returns the parsed event. | | [`webhooks.verifySignature()`](https://docs.tryyoursize.com/reference/node/webhooks-verify-signature.md) | Checks the signature only (throws when it does not verify). | | [`webhooks.generateTestHeader()`](https://docs.tryyoursize.com/reference/node/webhooks-generate-test-header.md) | Builds a valid TYS-Signature header for a payload, to test your webhook handler. | ## Pagination and errors | | | |---|---| | [`PagePromise`](https://docs.tryyoursize.com/reference/node/page-promise.md) | What every list() returns: await it for one page ({ data, has_more, next_cursor }), or iterate it with for await to walk every item of every page. | | [`Errors`](https://docs.tryyoursize.com/reference/node/errors.md) | Every error of an API call is a TryYourSizeError subclass, by HTTP status: InvalidRequestError (400, 422), AuthenticationError (401), PermissionError (403), NotFoundError (404), ConflictError (409), R | --- # tys.auditEvents.list() > tys.auditEvents.list() Source: https://docs.tryyoursize.com/reference/node/audit-events-list/ *Method* · `@tryyoursize/node` ```ts list(params: AuditEventListParams = {}, options?: RequestOptions): PagePromise ``` ## Parameters - **`params`** (`AuditEventListParams`, optional, default `{}`): `action` (a trailing `.` matches a prefix), `actor`, `store_id`, `target`, `from`, `to`, `limit` (≤ 200), `cursor`. - **`options`** (`RequestOptions`, optional) ## Returns `PagePromise`: Audit events, newest first. Await it for one page (`{ data, has_more, next_cursor }`), or `for await` over every item. See [PagePromise](https://docs.tryyoursize.com/reference/node/page-promise.md). ## Example **Node.js** ```ts for await (const e of tys.auditEvents.list({ action: "api_key." })) { console.log(e.created_at, e.actor_type, e.action); } ``` **Python** ```python for event in tys.audit_events.list(action="api_key.").auto_paging_iter(): print(event["created_at"], event["actor_type"], event["action"]) ``` **cURL** ```bash curl "https://api.tryyoursize.com/v1/audit_events?action=api_key." \ -H "Authorization: Bearer $TRYYOURSIZE_RESTRICTED_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [auditEvents.list (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/listauditeventswithkey.md) --- # new TryYourSize() > Creates a client for one secret or restricted key. Source: https://docs.tryyoursize.com/reference/node/client/ *Constructor* · `@tryyoursize/node` Creates a client for one secret or restricted key. Create it once and reuse it. ```ts constructor(apiKey: string, options: TryYourSizeOptions = {}) ``` ## Parameters - **`apiKey`** (`string`, required): A secret key (`sk_test_…` / `sk_live_…`) or a restricted key (`rk_…`). Keep it in an environment variable. - **`options`** (`TryYourSizeOptions`, optional, default `{}`) - **`apiVersion`** (`string | undefined`, optional): TYS-Version sent with every request (default: the version this SDK was built against). - **`maxRetries`** (`number | undefined`, optional): Retries of network errors, timeouts, 429, 5xx and 409 idempotency_key_in_use (default 2). - **`timeoutMs`** (`number | undefined`, optional): Per-attempt timeout in ms (default 30,000). - **`baseUrl`** (`string | undefined`, optional): API origin (default https://api.tryyoursize.com). - **`fetch`** (`typeof fetch | undefined`, optional): A fetch implementation (default: the global fetch of Node 18+). ## Errors `TypeError` for a missing key, a publishable key, or no `fetch`. ## Example **Node.js** ```ts const tys = new TryYourSize(process.env.TRYYOURSIZE_SECRET_KEY!, { maxRetries: 2, // network errors, timeouts, 429, 5xx timeoutMs: 30_000, }); ``` **Python** ```python tys = tryyoursize.TryYourSize(os.environ["TRYYOURSIZE_SECRET_KEY"], max_retries=2, timeout=30.0) ``` --- # Errors > Every error of an API call is a TryYourSizeError subclass, by HTTP status: InvalidRequestError (400, 422), AuthenticationError (401), PermissionError (403), NotFoundError (404), ConflictError (409), R Source: https://docs.tryyoursize.com/reference/node/errors/ *Class* · `@tryyoursize/node` Every error of an API call is a `TryYourSizeError` subclass, by HTTP status: `InvalidRequestError` (400, 422), `AuthenticationError` (401), `PermissionError` (403), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429, with `retryAfter`), `APIError` (5xx) and `ConnectionError` (no answer). Webhook checks throw `SignatureVerificationError`. ```ts class TryYourSizeError extends Error ``` ## Properties - **`status`** (`number | undefined`, required) - **`code`** (`string | undefined`, required) - **`docUrl`** (`string | undefined`, required) - **`requestId`** (`string | undefined`, required) - **`raw`** (`unknown`, required) - **`headers`** (`Headers | undefined`, required) - **`issues`** (`GarmentIssue[] | undefined`, required): Values to fix, for 422 answers of the garment endpoints (schema GarmentRejected). ## Example **Node.js** ```ts try { await tys.products.retrieve("NO-SUCH-SKU"); } catch (err) { if (err instanceof RateLimitError) await sleep((err.retryAfter ?? 1) * 1000); else if (err instanceof TryYourSizeError) console.error(err.status, err.code, err.requestId); } ``` **Python** ```python try: tys.products.retrieve("NO-SUCH-SKU") except tryyoursize.NotFoundError: pass except tryyoursize.APIError as err: print(err.status, err.code, err.request_id) ``` ## See also - [API error codes](https://docs.tryyoursize.com/api/errors.md) --- # tys.fitGroups.create() > tys.fitGroups.create() Source: https://docs.tryyoursize.com/reference/node/fit-groups-create/ *Method* · `@tryyoursize/node` ```ts create(input: FitGroupInput, options?: RequestOptions): Promise ``` ## Parameters - **`input`** (`FitGroupInput`, required) - **`name`** (`string`, required) - **`product_ids`** (`string[]`, optional): Products to put in the new group (create only). - **`source_product_id`** (`string`, optional): "Use the garment of…": the new group takes over this product's garment versions (create only). - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The fit group. ## Example **Node.js** ```ts const group = await tys.fitGroups.create({ name: "Basic tee", product_ids: [navy.id, black.id], // colourways that share one garment }); ``` **Python** ```python group = tys.fit_groups.create(name="Basic tee", product_ids=[navy["id"], black["id"]]) ``` **cURL** ```bash curl -X POST https://api.tryyoursize.com/v1/fit_groups \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"name":"Basic tee","product_ids":["",""]}' ``` ## See also - [fitGroups.create (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createcatalogfitgroup.md) --- # tys.fitGroups.linkProducts() > Moves products into the group (they then use its garment). Source: https://docs.tryyoursize.com/reference/node/fit-groups-link-products/ *Method* · `@tryyoursize/node` Moves products into the group (they then use its garment). ```ts linkProducts(id: string, params: LinkProductsRequest, options?: RequestOptions): Promise ``` ## Parameters - **`id`** (`string`, required): The fit group ID. - **`params`** (`LinkProductsRequest`, required) - **`product_ids`** (`string[]`, required) - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The fit group. ## Example **Node.js** ```ts await tys.fitGroups.linkProducts(group.id, { product_ids: [white.id] }); ``` **Python** ```python tys.fit_groups.link_products(group["id"], product_ids=[white["id"]]) ``` **cURL** ```bash curl -X POST https://api.tryyoursize.com/v1/fit_groups//products \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"product_ids":[""]}' ``` ## See also - [fitGroups.linkProducts (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/linkcatalogfitgroupproducts.md) --- # tys.fitGroups.list() > tys.fitGroups.list() Source: https://docs.tryyoursize.com/reference/node/fit-groups-list/ *Method* · `@tryyoursize/node` ```ts list(params: FitGroupListParams = {}, options?: RequestOptions): PagePromise ``` ## Parameters - **`params`** (`FitGroupListParams`, optional, default `{}`): `limit` and `cursor`. - **`options`** (`RequestOptions`, optional) ## Returns `PagePromise`: Fit groups. Await it for one page (`{ data, has_more, next_cursor }`), or `for await` over every item. See [PagePromise](https://docs.tryyoursize.com/reference/node/page-promise.md). ## Example **Node.js** ```ts for await (const g of tys.fitGroups.list()) console.log(g.id, g.name); ``` **Python** ```python for group in tys.fit_groups.list().auto_paging_iter(): print(group["id"], group["name"]) ``` **cURL** ```bash curl https://api.tryyoursize.com/v1/fit_groups \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [fitGroups.list (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/listcatalogfitgroups.md) --- # tys.fitGroups.retrieve() > tys.fitGroups.retrieve() Source: https://docs.tryyoursize.com/reference/node/fit-groups-retrieve/ *Method* · `@tryyoursize/node` ```ts retrieve(id: string, options?: RequestOptions): Promise ``` ## Parameters - **`id`** (`string`, required): The fit group ID. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The fit group. ## Example **Node.js** ```ts const group = await tys.fitGroups.retrieve(groupId); ``` **Python** ```python group = tys.fit_groups.retrieve(group_id) ``` **cURL** ```bash curl https://api.tryyoursize.com/v1/fit_groups/ \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [fitGroups.retrieve (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/getcatalogfitgroup.md) --- # tys.garments.publish() > Publishes a complete draft. Source: https://docs.tryyoursize.com/reference/node/garments-publish/ *Method* · `@tryyoursize/node` Publishes a complete draft. Key scope: `garments:publish`. ```ts publish(id: string, options?: RequestOptions): Promise ``` ## Parameters - **`id`** (`string`, required): The draft's ID. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The published version. Shoppers get sizes for it from now on. ## Errors `InvalidRequestError` (422) with `issues` listing what is missing. ## Example **Node.js** ```ts try { await tys.garments.publish(draft.id); } catch (err) { if (err instanceof InvalidRequestError) console.log(err.issues); // what is missing } ``` **Python** ```python try: tys.garments.publish(draft["id"]) except tryyoursize.InvalidRequestError as err: print(err.issues) # what is missing ``` **cURL** ```bash curl -X POST https://api.tryyoursize.com/v1/garments//publish \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [garments.publish (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/publishcataloggarment.md) --- # tys.garments.retrieve() > tys.garments.retrieve() Source: https://docs.tryyoursize.com/reference/node/garments-retrieve/ *Method* · `@tryyoursize/node` ```ts retrieve(id: string, options?: RequestOptions): Promise ``` ## Parameters - **`id`** (`string`, required): The garment version ID. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The garment version. ## Example **Node.js** ```ts const version = await tys.garments.retrieve(garmentId); ``` **Python** ```python version = tys.garments.retrieve(garment_id) ``` **cURL** ```bash curl https://api.tryyoursize.com/v1/garments/ \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [garments.retrieve (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/getcataloggarment.md) --- # tys.garments.updateDraft() > Replaces a draft's content (published versions never change: 409). Source: https://docs.tryyoursize.com/reference/node/garments-update-draft/ *Method* · `@tryyoursize/node` Replaces a draft's content (published versions never change: 409). ```ts updateDraft(id: string, garment: GarmentInput, options?: RequestOptions): Promise ``` ## Parameters - **`id`** (`string`, required): The draft's ID. - **`garment`** (`GarmentInput`, required) - **`category`** (`GarmentCategory`, required): The garment type; it sets which POMs are needed. - **`fit_intent`** (`FitIntent`, required): The designer's intended silhouette; sets the ease targets the fit judgement compares against. - **`sizes`** (`string[]`, required): Size labels, smallest to largest. - **`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. - **`fabric`** (`Fabric`, required): What the tech pack / mill sheet says. - **`import_id`** (`string`, optional): Pattern import linked to this version (omit to unlink). - **`season`** (`string`, optional): Season tag, e.g. "SS27". - **`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. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The updated draft. Published versions never change (409 `conflict`). ## Example **Node.js** ```ts await tys.garments.updateDraft(draft.id, { ...garment, season: "SS27" }); // replaces the draft ``` **Python** ```python tys.garments.update_draft(draft["id"], {**garment, "season": "SS27"}) # replaces the draft ``` **cURL** ```bash curl -X PUT https://api.tryyoursize.com/v1/garments/ \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"category":"tshirt","fit_intent":"regular","sizes":["S","M","L"],"poms":{"S":{"chest_width":480},"M":{"chest_width":510},"L":{"chest_width":540}},"fabric":{"composition":[{"fiber":"cotton","pct":100}],"weight_gsm":180}}' ``` ## See also - [garments.updateDraft (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/updatecataloggarmentdraft.md) --- # tys.lastResponse > Meta of the last answered request (success or API error). Source: https://docs.tryyoursize.com/reference/node/last-response/ *Property* · `@tryyoursize/node` Meta of the last answered request (success or API error). ```ts lastResponse: ResponseMeta | undefined; ``` ## Properties - **`method`** (`string`, required) - **`path`** (`string`, required) - **`status`** (`number`, required) - **`requestId`** (`string | undefined`, required) - **`apiVersion`** (`string | undefined`, required): TYS-Version the API answered with. - **`idempotentReplayed`** (`boolean`, required): True when the answer is a stored idempotent replay. - **`idempotencyKey`** (`string | undefined`, required) - **`rateLimit`** (`RateLimit`, required) - **`limit`** (`number | undefined`, required) - **`remaining`** (`number | undefined`, required) - **`reset`** (`number | undefined`, required): Unix seconds when the window resets (as sent by the API). - **`headers`** (`Headers`, required) ## Example **Node.js** ```ts await tys.products.list(); console.log(tys.lastResponse?.requestId, tys.lastResponse?.rateLimit.remaining); ``` --- # tys.mode > "test" or "live", from the key prefix. Source: https://docs.tryyoursize.com/reference/node/mode/ *Property* · `@tryyoursize/node` `"test"` or `"live"`, from the key prefix. ```ts get mode(): "test" | "live" | undefined ``` ## Example **Node.js** ```ts if (tys.mode === "live") enableOrderSync(); ``` **Python** ```python if tys.mode == "live": enable_order_sync() ``` --- # tys.orders.create() > tys.orders.create() Source: https://docs.tryyoursize.com/reference/node/orders-create/ *Method* · `@tryyoursize/node` ```ts create(order: OutcomeOrderInput, options?: RequestOptions): Promise ``` ## Parameters - **`order`** (`OutcomeOrderInput`, required) - **`id`** (`string`, required): Your order ID. - **`ordered_at`** (`string`, required) - **`currency`** (`string`, optional): ISO 4217, e.g. EUR. - **`visitor_id`** (`string`, optional): The SDK's anonymous visitor ID (`(await tys.experiment())?.visitorId`), saved with the cart. TryYourSize recomputes the A/B arm from it and stores only its hash. Never a customer ID. - **`experiment_arm`** (`"treatment" | "holdout"`, optional): The arm, when you cannot send visitor_id. - **`lines`** (`OutcomeLineInput[]`, required) - **`id`** (`string`, required): Your order line ID (unique within the order). - **`product`** (`string`, required): Your product ID (the one you pass to the SDK). - **`variant`** (`string`, optional) - **`size`** (`string`, required): The size bought, in your labels. - **`quantity`** (`integer`, required) - **`unit_price_minor`** (`integer`, optional): Price of one unit in minor units (5995 = 59.95). Optional; used for the refund value estimate. - **`tys_shown`** (`boolean`, optional): A TryYourSize element was shown for this purchase. - **`recommended_size`** (`string`, optional): The size TryYourSize recommended (the SDK's recommendation event, or the _tys_size cart line property). - **`attribution`** (`"cart_attribute" | "sdk" | "api"`, optional): Where recommended_size came from. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: What was recorded. - **`id`** (`string`, required) - **`external_id`** (`string`, required) - **`created`** (`boolean`, required): False when the order already existed and was updated. - **`experiment_arm`** (`"treatment" | "holdout"`, optional) - **`lines`** (`integer`, required) ## Example **Node.js** ```ts await tys.orders.create({ id: "1001", // your order ID: re-sending updates it ordered_at: new Date().toISOString(), currency: "EUR", visitor_id, // from tys.experiment() in the browser, saved with the cart lines: [ { id: "1", product: "TEE-001", size: "M", quantity: 1, recommended_size: "M", tys_shown: true }, ], }); ``` **Python** ```python from datetime import datetime, timezone tys.orders.create({ "id": "1001", "ordered_at": datetime.now(timezone.utc).isoformat(), "currency": "EUR", "visitor_id": visitor_id, "lines": [{"id": "1", "product": "TEE-001", "size": "M", "quantity": 1, "recommended_size": "M", "tys_shown": True}], }) ``` **cURL** ```bash curl -X POST https://api.tryyoursize.com/v1/orders \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"id":"1001","ordered_at":"2026-10-26T10:00:00Z","lines":[{"id":"1","product":"TEE-001","size":"M","quantity":1}]}' ``` ## See also - [Orders and returns](https://docs.tryyoursize.com/guides/outcomes.md) - [orders.create (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createoutcomeorder.md) --- # PagePromise > What every list() returns: await it for one page ({ data, has_more, next_cursor }), or iterate it with for await to walk every item of every page. Source: https://docs.tryyoursize.com/reference/node/page-promise/ *Class* · `@tryyoursize/node` What every `list()` returns: await it for one page (`{ data, has_more, next_cursor }`), or iterate it with `for await` to walk every item of every page. ## Methods - **`then / catch / finally`** (`Promise`, required): Awaiting gives the first page. - **`[Symbol.asyncIterator]()`** (`AsyncGenerator`, required): `for await (const item of list)`: every item, following `next_cursor`. - **`pages()`** (`AsyncGenerator`, required): Every page, starting with the first. - **`autoPagingToArray(opts?)`** (`Promise`, required): Collects items across pages, at most `opts.limit` (default 10,000). - **`autoPagingEach(fn)`** (`Promise`, required): Calls `fn` for each item; return `false` to stop. ## Example **Node.js** ```ts const first = await tys.products.list({ limit: 20 }); const all = await tys.products.list().autoPagingToArray({ limit: 500 }); await tys.fitGroups.list().autoPagingEach((g) => { console.log(g.name); }); ``` **Python** ```python page = tys.products.list(limit=20) next_page = page.next_page() for product in page.auto_paging_iter(): ... ``` ## See also - [Pagination](https://docs.tryyoursize.com/guides/pagination.md) --- # tys.products.create() > tys.products.create() Source: https://docs.tryyoursize.com/reference/node/products-create/ *Method* · `@tryyoursize/node` ```ts create(input: ProductInput, options?: RequestOptions): Promise ``` ## Parameters - **`input`** (`ProductInput`, required) - **`external_id`** (`string`, required) - **`name`** (`string`, required) - **`category`** (`GarmentCategory`, required): The garment type; it sets which POMs are needed. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The product. - **`id`** (`string`, required) - **`external_id`** (`string`, required): The brand's SKU or style ID (unique per brand). - **`name`** (`string`, required) - **`category`** (`GarmentCategory`, required): The garment type; it sets which POMs are needed. - **`published_version`** (`integer`, optional): Garment version shoppers are fitted against, if any. - **`draft_version`** (`integer`, optional): Garment version being edited, if any. - **`created_at`** (`string`, required) - **`updated_at`** (`string`, required) - **`fit_group_id`** (`string`, optional): The fit group whose garment this product uses (absent until grouped). - **`brand_id`** (`string`, optional): The brand the product belongs to; every store of the brand sees it. - **`home_store_id`** (`string`, optional): The store the product was created in. - **`retired_at`** (`string`, optional): Set when the product is retired; shoppers no longer get a size for it. - **`available`** (`boolean`, optional): Whether the store it was read through offers it (false in the brand list, see `stores`). ## Example **Node.js** ```ts const product = await tys.products.create({ external_id: "TEE-001", // your SKU / style ID, unique per store name: "Basic tee", category: "tshirt", }); ``` **Python** ```python product = tys.products.create(external_id="TEE-001", name="Basic tee", category="tshirt") ``` **cURL** ```bash curl -X POST https://api.tryyoursize.com/v1/products \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"external_id":"TEE-001","name":"Basic tee","category":"tshirt"}' ``` ## See also - [products.create (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createcatalogproduct.md) --- # tys.products.garments.createDraft() > Starts a new draft version (sizes, POMs in mm, grading, fabric). Source: https://docs.tryyoursize.com/reference/node/products-garments-create-draft/ *Method* · `@tryyoursize/node` Starts a new draft version (sizes, POMs in mm, grading, fabric). 422 errors carry `issues`. ```ts createDraft(idOrSku: string, garment: GarmentInput, options?: RequestOptions): Promise ``` ## Parameters - **`idOrSku`** (`string`, required): The product's TryYourSize ID or your SKU (URL-encoded for you, so `TEE/01` works). - **`garment`** (`GarmentInput`, required) - **`category`** (`GarmentCategory`, required): The garment type; it sets which POMs are needed. - **`fit_intent`** (`FitIntent`, required): The designer's intended silhouette; sets the ease targets the fit judgement compares against. - **`sizes`** (`string[]`, required): Size labels, smallest to largest. - **`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. - **`fabric`** (`Fabric`, required): What the tech pack / mill sheet says. - **`import_id`** (`string`, optional): Pattern import linked to this version (omit to unlink). - **`season`** (`string`, optional): Season tag, e.g. "SS27". - **`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. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The draft garment version, with `issues` that still block publishing. ## Example **Node.js** ```ts const garment: GarmentInput = { category: "tshirt", fit_intent: "regular", sizes: ["S", "M", "L"], poms: { S: { chest_width: 480 }, M: { chest_width: 510 }, L: { chest_width: 540 } }, // mm fabric: { composition: [{ fiber: "cotton", pct: 100 }], weight_gsm: 180 }, }; const draft = await tys.products.garments.createDraft("TEE-001", garment); console.log(draft.version, draft.issues); // what still blocks publishing ``` **Python** ```python garment = { "category": "tshirt", "fit_intent": "regular", "sizes": ["S", "M", "L"], "poms": {"S": {"chest_width": 480}, "M": {"chest_width": 510}, "L": {"chest_width": 540}}, # mm "fabric": {"composition": [{"fiber": "cotton", "pct": 100}], "weight_gsm": 180}, } draft = tys.products.garments.create_draft("TEE-001", garment) print(draft["version"], draft["issues"]) ``` **cURL** ```bash curl -X POST https://api.tryyoursize.com/v1/products/TEE-001/garments \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"category":"tshirt","fit_intent":"regular","sizes":["S","M","L"],"poms":{"S":{"chest_width":480},"M":{"chest_width":510},"L":{"chest_width":540}},"fabric":{"composition":[{"fiber":"cotton","pct":100}],"weight_gsm":180}}' ``` ## See also - [Catalog API](https://docs.tryyoursize.com/products/catalog-api.md) - [products.garments.createDraft (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createcataloggarmentdraft.md) --- # tys.products.garments.list() > Garment versions, newest first (a single page: has_more is always false). Source: https://docs.tryyoursize.com/reference/node/products-garments-list/ *Method* · `@tryyoursize/node` Garment versions, newest first (a single page: has_more is always false). ```ts list(idOrSku: string, options?: RequestOptions): PagePromise ``` ## Parameters - **`idOrSku`** (`string`, required): The product's TryYourSize ID or your SKU (URL-encoded for you, so `TEE/01` works). - **`options`** (`RequestOptions`, optional) ## Returns `PagePromise`: The product's garment versions, newest first (a single page). Await it for one page (`{ data, has_more, next_cursor }`), or `for await` over every item. See [PagePromise](https://docs.tryyoursize.com/reference/node/page-promise.md). ## Example **Node.js** ```ts const { data } = await tys.products.garments.list("TEE-001"); // newest first ``` **Python** ```python versions = tys.products.garments.list("TEE-001") # newest first ``` **cURL** ```bash curl https://api.tryyoursize.com/v1/products/TEE-001/garments \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [products.garments.list (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/listcataloggarments.md) --- # tys.products.list() > Newest first. Source: https://docs.tryyoursize.com/reference/node/products-list/ *Method* · `@tryyoursize/node` Newest first. Await for one page, or `for await` over every product. ```ts list(params: ProductListParams = {}, options?: RequestOptions): PagePromise ``` ## Parameters - **`params`** (`ProductListParams`, optional, default `{}`): `limit`, `cursor`, and `sku` to find one product by SKU. - **`options`** (`RequestOptions`, optional) ## Returns `PagePromise`: Products, newest first. Await it for one page (`{ data, has_more, next_cursor }`), or `for await` over every item. See [PagePromise](https://docs.tryyoursize.com/reference/node/page-promise.md). ## Example **Node.js** ```ts // One page const page = await tys.products.list({ limit: 50 }); // Every product, across pages for await (const p of tys.products.list()) { console.log(p.external_id, p.published_version); } // One product by SKU const { data } = await tys.products.list({ sku: "TEE-001" }); ``` **Python** ```python page = tys.products.list(limit=50) for product in tys.products.list().auto_paging_iter(): print(product["external_id"], product.get("published_version")) match = tys.products.list(sku="TEE-001") ``` **cURL** ```bash curl "https://api.tryyoursize.com/v1/products?limit=50" \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [products.list (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/listcatalogproducts.md) --- # tys.products.retrieve() > tys.products.retrieve() Source: https://docs.tryyoursize.com/reference/node/products-retrieve/ *Method* · `@tryyoursize/node` ```ts retrieve(idOrSku: string, options?: RequestOptions): Promise ``` ## Parameters - **`idOrSku`** (`string`, required): The product's TryYourSize ID or your SKU (URL-encoded for you, so `TEE/01` works). - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The product. - **`id`** (`string`, required) - **`external_id`** (`string`, required): The brand's SKU or style ID (unique per brand). - **`name`** (`string`, required) - **`category`** (`GarmentCategory`, required): The garment type; it sets which POMs are needed. - **`published_version`** (`integer`, optional): Garment version shoppers are fitted against, if any. - **`draft_version`** (`integer`, optional): Garment version being edited, if any. - **`created_at`** (`string`, required) - **`updated_at`** (`string`, required) - **`fit_group_id`** (`string`, optional): The fit group whose garment this product uses (absent until grouped). - **`brand_id`** (`string`, optional): The brand the product belongs to; every store of the brand sees it. - **`home_store_id`** (`string`, optional): The store the product was created in. - **`retired_at`** (`string`, optional): Set when the product is retired; shoppers no longer get a size for it. - **`available`** (`boolean`, optional): Whether the store it was read through offers it (false in the brand list, see `stores`). ## Example **Node.js** ```ts const product = await tys.products.retrieve("TEE-001"); // TryYourSize ID or your SKU ``` **Python** ```python product = tys.products.retrieve("TEE-001") # TryYourSize ID or your SKU ``` **cURL** ```bash curl https://api.tryyoursize.com/v1/products/TEE-001 \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [products.retrieve (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/getcatalogproduct.md) --- # tys.products.sizeMap.retrieve() > tys.products.sizeMap.retrieve() Source: https://docs.tryyoursize.com/reference/node/products-size-map-retrieve/ *Method* · `@tryyoursize/node` ```ts retrieve(idOrSku: string, options?: RequestOptions): Promise ``` ## Parameters - **`idOrSku`** (`string`, required): The product's TryYourSize ID or your SKU (URL-encoded for you, so `TEE/01` works). - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The size map: Studio size → your size label. - **`entries`** (`object[]`, required) - **`unmapped_shop_values`** (`string[]`, optional): Variant size values of the product with no Studio size yet (read only). ## Example **Node.js** ```ts const map = await tys.products.sizeMap.retrieve("TEE-001"); console.log(map.entries, map.unmapped_shop_values); ``` **Python** ```python size_map = tys.products.size_map.retrieve("TEE-001") print(size_map["entries"], size_map.get("unmapped_shop_values")) ``` **cURL** ```bash curl https://api.tryyoursize.com/v1/products/TEE-001/size_map \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [products.sizeMap.retrieve (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/getcatalogsizemap.md) --- # tys.products.sizeMap.save() > Replaces the size map. Source: https://docs.tryyoursize.com/reference/node/products-size-map-save/ *Method* · `@tryyoursize/node` Replaces the size map. ```ts save(idOrSku: string, map: ProductSizeMapInput, options?: RequestOptions): Promise ``` ## Parameters - **`idOrSku`** (`string`, required): The product's TryYourSize ID or your SKU (URL-encoded for you, so `TEE/01` works). - **`map`** (`ProductSizeMapInput`, required): `{ entries: [{ studio_size, shop_value }] }`: replaces the whole map. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The saved size map. ## Example **Node.js** ```ts await tys.products.sizeMap.save("TEE-001", { entries: [ { studio_size: "S", shop_value: "Small" }, { studio_size: "M", shop_value: "Medium" }, ], }); ``` **Python** ```python tys.products.size_map.save("TEE-001", entries=[ {"studio_size": "S", "shop_value": "Small"}, {"studio_size": "M", "shop_value": "Medium"}, ]) ``` **cURL** ```bash curl -X PUT https://api.tryyoursize.com/v1/products/TEE-001/size_map \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"entries":[{"studio_size":"M","shop_value":"Medium"}]}' ``` ## See also - [products.sizeMap.save (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/savecatalogsizemap.md) --- # tys.products.update() > Replaces the SKU, name and category (all three required). Source: https://docs.tryyoursize.com/reference/node/products-update/ *Method* · `@tryyoursize/node` Replaces the SKU, name and category (all three required). ```ts update(idOrSku: string, input: ProductInput, options?: RequestOptions): Promise ``` ## Parameters - **`idOrSku`** (`string`, required): The product's TryYourSize ID or your SKU (URL-encoded for you, so `TEE/01` works). - **`input`** (`ProductInput`, required) - **`external_id`** (`string`, required) - **`name`** (`string`, required) - **`category`** (`GarmentCategory`, required): The garment type; it sets which POMs are needed. - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: The updated product. ## Example **Node.js** ```ts await tys.products.update("TEE-001", { external_id: "TEE-001", name: "Basic tee (organic)", category: "tshirt" }); ``` **Python** ```python tys.products.update("TEE-001", external_id="TEE-001", name="Basic tee (organic)", category="tshirt") ``` **cURL** ```bash curl -X PATCH https://api.tryyoursize.com/v1/products/TEE-001 \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"external_id":"TEE-001","name":"Basic tee (organic)","category":"tshirt"}' ``` ## See also - [products.update (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/updatecatalogproduct.md) --- # tys.recommendations.create() > handle comes from the browser SDK (await tys.recommendationHandle()), products are your SKUs / style IDs. Source: https://docs.tryyoursize.com/reference/node/recommendations-create/ *Method* · `@tryyoursize/node` `handle` comes from the browser SDK (`await tys.recommendationHandle()`), `products` are your SKUs / style IDs. Key scope: `fit_checks:read`. ```ts create(params: RecommendationsRequest, options?: RequestOptions): Promise ``` ## Parameters - **`params`** (`RecommendationsRequest`, required) - **`handle`** (`string`, required): A recommendation handle from the browser SDK (`tys.recommendationHandle()`). - **`products`** (`string[]`, required): Product SKUs / style IDs (what you pass to the element as `product`). - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: `{ data: ServerRecommendation[] }`, one per product, in your size labels. Sizes only, never measurements. - **`product`** (`string`, required) - **`status`** (`"ready" | "computing" | "none" | "unavailable"`, required): `ready`: a size. `computing`: a simulation the shopper started is running (ask again later). `none`: simulated, no size can be worn. `unavailable`: no published garment for this product, not simulated on this body yet, or the store's plan has no fit checks left. A page view or this API never starts a simulation. - **`size`** (`string`, required): The recommended size in the store's label (the product's size map), or null. - **`studio_size`** (`string`, required): The same size as entered in TryYourSize Studio, or null. - **`wearable_sizes`** (`string[]`, required): Sizes that can be worn on this body, in the store's labels. - **`tryon_id`** (`string`, optional): The try-on that produced the size, when there is one. Send it back with orders for attribution. ## Example **Node.js** ```ts // handle: from the browser SDK, `await tys.recommendationHandle()`, sent to your server const { data } = await tys.recommendations.create({ handle, products: ["SKU-123", "SKU-456"], }); for (const r of data) { if (r.status === "ready") console.log(r.product, r.size, r.wearable_sizes); } ``` **Python** ```python answer = tys.recommendations.create(handle=handle, products=["SKU-123", "SKU-456"]) for rec in answer["data"]: if rec["status"] == "ready": print(rec["product"], rec["size"], rec["wearable_sizes"]) ``` **cURL** ```bash curl -X POST https://api.tryyoursize.com/v1/recommendations \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"handle":"tys_rh_…","products":["SKU-123","SKU-456"]}' ``` ## See also - [Server-side recommendations](https://docs.tryyoursize.com/guides/server-side-recommendations.md) - [tys.recommendationHandle() (browser)](https://docs.tryyoursize.com/reference/web/client-recommendation-handle.md) - [recommendations.create (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createrecommendations.md) --- # RequestOptions > Options of one call: the last argument of every method. Source: https://docs.tryyoursize.com/reference/node/request-options/ *Type* · `@tryyoursize/node` Options of one call: the last argument of every method. ```ts interface RequestOptions ``` ## Properties - **`idempotencyKey`** (`string | undefined`, optional): Idempotency-Key for this POST (default: a random UUID, reused across this call's retries). - **`timeoutMs`** (`number | undefined`, optional): Overrides the client's timeout for this call. - **`maxRetries`** (`number | undefined`, optional): Overrides the client's maxRetries for this call. - **`apiVersion`** (`string | undefined`, optional): Overrides the client's TYS-Version for this call. - **`headers`** (`Record | undefined`, optional): Extra request headers. - **`signal`** (`AbortSignal | undefined`, optional): Aborts the call (not retried). ## Example **Node.js** ```ts await tys.orders.create(order, { idempotencyKey: `order-${order.id}`, timeoutMs: 10_000 }); ``` **Python** ```python tys.orders.create(order, idempotency_key=f"order-{order['id']}") ``` ## See also - [Idempotency and retries](https://docs.tryyoursize.com/guides/idempotency.md) --- # tys.returns.create() > tys.returns.create() Source: https://docs.tryyoursize.com/reference/node/returns-create/ *Method* · `@tryyoursize/node` ```ts create(ret: OutcomeReturnInput, options?: RequestOptions): Promise ``` ## Parameters - **`ret`** (`OutcomeReturnInput`, required) - **`id`** (`string`, required): Your return (or RMA) ID. - **`order_id`** (`string`, required) - **`line_id`** (`string`, required) - **`quantity`** (`integer`, required) - **`reason`** (`string`, optional): size_too_small, size_too_large, fit_other, style, quality, damaged_or_wrong, changed_mind, other; Shopify's ReturnReason codes (SIZE_TOO_SMALL…) and common returns-platform words are mapped. Empty: unspecified. - **`exchange`** (`boolean`, optional): The item was exchanged rather than refunded. - **`exchange_size`** (`string`, optional): The size sent in exchange (implies exchange). - **`returned_at`** (`string`, required) - **`options`** (`RequestOptions`, optional) ## Returns `Promise`: What was recorded. ## Example **Node.js** ```ts await tys.returns.create({ id: "RMA-7", order_id: "1001", line_id: "1", quantity: 1, reason: "size_too_small", returned_at: new Date().toISOString(), }); ``` **Python** ```python tys.returns.create({ "id": "RMA-7", "order_id": "1001", "line_id": "1", "quantity": 1, "reason": "size_too_small", "returned_at": datetime.now(timezone.utc).isoformat(), }) ``` **cURL** ```bash curl -X POST https://api.tryyoursize.com/v1/returns \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" \ -H "Content-Type: application/json" \ -d '{"id":"RMA-7","order_id":"1001","line_id":"1","quantity":1,"reason":"size_too_small","returned_at":"2026-11-02T09:00:00Z"}' ``` ## See also - [Orders and returns](https://docs.tryyoursize.com/guides/outcomes.md) - [returns.create (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createoutcomereturn.md) --- # tys.webhooks.constructEvent() > Verifies a delivery's TYS-Signature header against the raw request body and returns the parsed event. Source: https://docs.tryyoursize.com/reference/node/webhooks-construct-event/ *Method* · `@tryyoursize/node` Verifies a delivery's `TYS-Signature` header against the raw request body and returns the parsed event. Also exported as a function: `import { constructEvent } from "@tryyoursize/node"`. ```ts constructEvent( rawBody: RawBody, signatureHeader: string | string[] | null | undefined, secret: string, opts?: ConstructEventOptions, ): WebhookEvent ``` ## Parameters - **`rawBody`** (`RawBody`, required): The raw request body (string or Buffer), not parsed JSON. With Express use `express.raw({ type: "application/json" })`. - **`signatureHeader`** (`string | string[] | null | undefined`, required): The `TYS-Signature` header. - **`secret`** (`string`, required): The endpoint's signing secret (`whsec_…`) from Studio → Developers → Webhooks. - **`opts`** (`ConstructEventOptions`, optional) - **`toleranceSeconds`** (`number | undefined`, optional): Maximum |now − t| in seconds (default 300). 0 or less disables the check. - **`now`** (`number | Date | undefined`, optional): The current time (unix seconds or a Date); for tests. ## Returns `WebhookEvent`: The event. Narrow on `type` to get typed `data`. Payloads never carry shopper identity or measurements. ## Errors `SignatureVerificationError` when no signature matches or the timestamp is outside the tolerance (5 minutes by default). ## Example **Node.js** ```ts app.post("/webhooks/tryyoursize", express.raw({ type: "application/json" }), (req, res) => { let event; try { event = tys.webhooks.constructEvent(req.body, req.headers["tys-signature"], process.env.TYS_WEBHOOK_SECRET!); } catch { return res.sendStatus(400); } if (event.type === "garment.published") console.log(event.data.product_skus); res.sendStatus(200); }); ``` **Python** ```python from flask import Flask, request @app.post("/webhooks/tryyoursize") def webhook(): try: event = tryyoursize.Webhook.construct_event( request.get_data(), request.headers.get("TYS-Signature", ""), os.environ["TYS_WEBHOOK_SECRET"] ) except tryyoursize.SignatureVerificationError: return "", 400 if event["type"] == "garment.published": print(event["data"]["product_skus"]) return "", 200 ``` ## See also - [Webhooks guide](https://docs.tryyoursize.com/guides/webhooks.md) --- # tys.webhooks.generateTestHeader() > Builds a valid TYS-Signature header for a payload, to test your webhook handler. Source: https://docs.tryyoursize.com/reference/node/webhooks-generate-test-header/ *Method* · `@tryyoursize/node` Builds a valid `TYS-Signature` header for a payload, to test your webhook handler. ```ts generateTestHeader(opts: Parameters[0]): string ``` ## Parameters - **`opts`** (`Parameters[0]`, required): `{ payload, secret, timestamp? }`: the body, the secret (or several, as during a rotation) and the unix time (default now). ## Returns `string`: The header value: `t=,v1=`. ## Example **Node.js** ```ts const payload = JSON.stringify({ id: "evt_test", object: "event", type: "webhook.test", data: {} }); const header = tys.webhooks.generateTestHeader({ payload, secret: "whsec_test" }); await fetch("http://localhost:3000/webhooks/tryyoursize", { method: "POST", headers: { "TYS-Signature": header, "Content-Type": "application/json" }, body: payload, }); ``` **Python** ```python payload = json.dumps({"id": "evt_test", "object": "event", "type": "webhook.test", "data": {}}) header = tryyoursize.Webhook.generate_test_header(payload, "whsec_test") ``` --- # tys.webhooks.verifySignature() > Checks the signature only (throws when it does not verify). Source: https://docs.tryyoursize.com/reference/node/webhooks-verify-signature/ *Method* · `@tryyoursize/node` Checks the signature only (throws when it does not verify). Use `constructEvent()` unless you parse the body yourself. ```ts verifySignature( rawBody: RawBody, signatureHeader: string | string[] | null | undefined, secret: string, opts?: ConstructEventOptions, ): void ``` ## Parameters - **`rawBody`** (`RawBody`, required): The raw request body. - **`signatureHeader`** (`string | string[] | null | undefined`, required): The `TYS-Signature` header. - **`secret`** (`string`, required): The signing secret (`whsec_…`). - **`opts`** (`ConstructEventOptions`, optional) - **`toleranceSeconds`** (`number | undefined`, optional): Maximum |now − t| in seconds (default 300). 0 or less disables the check. - **`now`** (`number | Date | undefined`, optional): The current time (unix seconds or a Date); for tests. ## Example **Node.js** ```ts tys.webhooks.verifySignature(rawBody, req.headers["tys-signature"], secret); // throws SignatureVerificationError ``` **Python** ```python tryyoursize.Webhook.verify_signature(payload, sig_header, secret) # True, or raises SignatureVerificationError ```