# TryYourSize Python SDK reference --- # Python reference (tryyoursize) > The server SDK for Python 3.9+, standard library only: recommendations, catalog, orders and returns, audit log, webhooks. Source: https://docs.tryyoursize.com/reference/python/ *SDK* · `tryyoursize` · v0.1.0 The official Python SDK for the TryYourSize server API: no third-party dependencies (standard library only), Python 3.9+, fully typed (`py.typed`). Use it **on your server** with a secret key (`sk_test_…` / `sk_live_…`) or a restricted key (`rk_…`); publishable keys (`pk_…`) are refused. Responses are plain dicts typed with `TypedDict`s generated from our OpenAPI spec. ## Install **pip** ```bash pip install tryyoursize ``` **npm** ```bash npm install @tryyoursize/node ``` ## Initialize **Python** ```python tys = tryyoursize.TryYourSize(os.environ["TRYYOURSIZE_SECRET_KEY"], max_retries=2, timeout=30.0) ``` **Node.js** ```ts const tys = new TryYourSize(process.env.TRYYOURSIZE_SECRET_KEY!, { maxRetries: 2, // network errors, timeouts, 429, 5xx timeoutMs: 30_000, }); ``` 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/python/errors.md) and the [API error codes](https://docs.tryyoursize.com/api/errors.md). ## Client | | | |---|---| | [`TryYourSize()`](https://docs.tryyoursize.com/reference/python/client.md) | Creates a client for one secret or restricted key. | | [`mode`](https://docs.tryyoursize.com/reference/python/mode.md) | "test" or "live", from the key prefix ("unknown" for other formats). | ## Recommendations | | | |---|---| | [`recommendations.create()`](https://docs.tryyoursize.com/reference/python/recommendations-create.md) | The shopper's size for up to 25 products (SKUs), from a browser SDK handle. | ## Products | | | |---|---| | [`products.list()`](https://docs.tryyoursize.com/reference/python/products-list.md) | The store's products, newest first. | | [`products.create()`](https://docs.tryyoursize.com/reference/python/products-create.md) | Create a product. | | [`products.retrieve()`](https://docs.tryyoursize.com/reference/python/products-retrieve.md) | A product by its TryYourSize ID or its SKU. | | [`products.update()`](https://docs.tryyoursize.com/reference/python/products-update.md) | Replace the SKU, name and category (all three required). | | [`products.size_map.retrieve()`](https://docs.tryyoursize.com/reference/python/products-size-map-retrieve.md) | A product's size map (Studio size → your size label). | | [`products.size_map.save()`](https://docs.tryyoursize.com/reference/python/products-size-map-save.md) | Replace the size map, e.g. | | [`products.garments.list()`](https://docs.tryyoursize.com/reference/python/products-garments-list.md) | Garment versions of a product, newest first (has_more is always false). | | [`products.garments.create_draft()`](https://docs.tryyoursize.com/reference/python/products-garments-create-draft.md) | Start a draft version: sizes, points of measure (mm) per size, grading, fabric. | ## Garments | | | |---|---| | [`garments.retrieve()`](https://docs.tryyoursize.com/reference/python/garments-retrieve.md) | A garment version. | | [`garments.update_draft()`](https://docs.tryyoursize.com/reference/python/garments-update-draft.md) | Replace a draft's content. | | [`garments.publish()`](https://docs.tryyoursize.com/reference/python/garments-publish.md) | Publish a complete draft (same checks as Studio; 422 lists what is missing). | ## Fit groups | | | |---|---| | [`fit_groups.list()`](https://docs.tryyoursize.com/reference/python/fit-groups-list.md) | Fit groups, cursor-paginated. | | [`fit_groups.create()`](https://docs.tryyoursize.com/reference/python/fit-groups-create.md) | Create a fit group: one garment shared by several products (colourways, prints). | | [`fit_groups.retrieve()`](https://docs.tryyoursize.com/reference/python/fit-groups-retrieve.md) | A fit group. | | [`fit_groups.link_products()`](https://docs.tryyoursize.com/reference/python/fit-groups-link-products.md) | Move products into the fit group; they then use its garment. | ## Outcomes | | | |---|---| | [`orders.create()`](https://docs.tryyoursize.com/reference/python/orders-create.md) | Record an order (idempotent by order id; re-sending updates it). | | [`returns.create()`](https://docs.tryyoursize.com/reference/python/returns-create.md) | Record a return of an order line (idempotent by return id and line). | ## Audit log | | | |---|---| | [`audit_events.list()`](https://docs.tryyoursize.com/reference/python/audit-events-list.md) | The audit log of the key's organization, newest first. | ## Webhooks | | | |---|---| | [`Webhook.construct_event()`](https://docs.tryyoursize.com/reference/python/webhook-construct-event.md) | Verify the signature, then return the parsed event envelope. | | [`Webhook.verify_signature()`](https://docs.tryyoursize.com/reference/python/webhook-verify-signature.md) | Return True or raise SignatureVerificationError. | | [`Webhook.generate_test_header()`](https://docs.tryyoursize.com/reference/python/webhook-generate-test-header.md) | A valid TYS-Signature value, for your own tests. | ## Pagination and errors | | | |---|---| | [`ListPage`](https://docs.tryyoursize.com/reference/python/list-page.md) | One page of a list. | | [`Errors`](https://docs.tryyoursize.com/reference/python/errors.md) | Every exception is a TryYourSizeError. | --- # tys.audit_events.list() > The audit log of the key's organization, newest first. Source: https://docs.tryyoursize.com/reference/python/audit-events-list/ *Method* · `tryyoursize` The audit log of the key's organization, newest first. Scope `audit:read`. Filters: `action` (a trailing `.` matches a prefix), `actor` (`actor_type:actor_id`), `store_id`, `target`, `from_` (or `**{"from": ...}`), `to` (`datetime` or RFC 3339 string), `limit` (≤ 200), `cursor`. ```python def list(**filters: Any) -> ListPage ``` ## Parameters - **`**filters`** (`Any`, required): `action` (a trailing `.` matches a prefix), `actor` (`actor_type:actor_id`), `store_id`, `target`, `from_` and `to` (datetime or RFC 3339), `limit` (≤ 200), `cursor`. Unknown filters raise `TypeError`. ## Returns `ListPage`: Audit events, newest first. A dict with `data`, `has_more`, `next_cursor`; `next_page()` and `auto_paging_iter()` walk the rest. See [ListPage](https://docs.tryyoursize.com/reference/python/list-page.md). ## Example **Python** ```python for event in tys.audit_events.list(action="api_key.").auto_paging_iter(): print(event["created_at"], event["actor_type"], event["action"]) ``` **Node.js** ```ts for await (const e of tys.auditEvents.list({ action: "api_key." })) { console.log(e.created_at, e.actor_type, e.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 - [audit_events.list (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/listauditeventswithkey.md) --- # TryYourSize() > Creates a client for one secret or restricted key. Source: https://docs.tryyoursize.com/reference/python/client/ *Constructor* · `tryyoursize` Creates a client for one secret or restricted key. Create it once and reuse it. ```python def __init__(api_key: str, *, api_version: Optional[str] = None, base_url: str = DEFAULT_BASE_URL, max_retries: int = 2, timeout: float = 30.0, transport: Optional[Transport] = None, sleep: Optional[Callable[[float], None]] = None) -> None ``` ## Parameters - **`api_key`** (`str`, required): A secret key (`sk_test_…` / `sk_live_…`) or a restricted key (`rk_…`). - **`api_version`** (`Optional[str]`, optional, default `None`): The `TYS-Version` to send (default: the version this release is built against, `API_VERSION`). - **`base_url`** (`str`, optional, default `DEFAULT_BASE_URL`): API origin; change only for local development. - **`max_retries`** (`int`, optional, default `2`): Retries of network errors, timeouts, 429, 5xx and `409 idempotency_key_in_use`. - **`timeout`** (`float`, optional, default `30.0`): Per-attempt timeout in seconds. - **`transport`** (`Optional[Transport]`, optional, default `None`): Replaces the HTTP call (tests). - **`sleep`** (`Optional[Callable[[float], None]]`, optional, default `None`): Replaces the wait between retries (tests). ## Errors `TryYourSizeError` for a missing key or a publishable key. ## Example **Python** ```python tys = tryyoursize.TryYourSize(os.environ["TRYYOURSIZE_SECRET_KEY"], max_retries=2, timeout=30.0) ``` **Node.js** ```ts const tys = new TryYourSize(process.env.TRYYOURSIZE_SECRET_KEY!, { maxRetries: 2, // network errors, timeouts, 429, 5xx timeoutMs: 30_000, }); ``` --- # Errors > Every exception is a TryYourSizeError. Source: https://docs.tryyoursize.com/reference/python/errors/ *Class* · `tryyoursize` Every exception is a `TryYourSizeError`. API answers raise an `APIError` subclass by status: `InvalidRequestError` (400, 422; `issues` for garments), `AuthenticationError` (401), `PermissionDeniedError` (403), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429, `retry_after`), `ServerError` (5xx). `APIConnectionError` when no answer came; `SignatureVerificationError` for webhooks. ```python class APIError(TryYourSizeError) ``` ## Attributes of APIError - **`status`** (`int`, required): The HTTP status. - **`code`** (`Optional[str]`, required): The stable error code ([API error codes](https://docs.tryyoursize.com/api/errors.md)). - **`doc_url`** (`Optional[str]`, required): Link to the code's explanation. - **`request_id`** (`Optional[str]`, required): Quote it to support. - **`body`** (`Dict[str, Any]`, required): The parsed error body. - **`issues`** (`list`, required): Garment issues of a 422; empty otherwise. ## Example **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) ``` **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); } ``` --- # tys.fit_groups.create() > Create a fit group: one garment shared by several products (colourways, prints). Source: https://docs.tryyoursize.com/reference/python/fit-groups-create/ *Method* · `tryyoursize` Create a fit group: one garment shared by several products (colourways, prints). ```python def create(*, name: str, product_ids: Optional[Iterable[str]] = None, source_product_id: Optional[str] = None, idempotency_key: Optional[str] = None) -> FitGroup ``` ## Parameters - **`name`** (`str`, required): The group's name. - **`product_ids`** (`Optional[Iterable[str]]`, optional, default `None`): Products to put in the new group. - **`source_product_id`** (`Optional[str]`, optional, default `None`): The new group takes over this product's garment versions. - **`idempotency_key`** (`Optional[str]`, optional, default `None`) ## Returns `FitGroup`: The fit group. ## Example **Python** ```python group = tys.fit_groups.create(name="Basic tee", product_ids=[navy["id"], black["id"]]) ``` **Node.js** ```ts const group = await tys.fitGroups.create({ name: "Basic tee", product_ids: [navy.id, black.id], // colourways that share one garment }); ``` **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 - [fit_groups.create (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createcatalogfitgroup.md) --- # tys.fit_groups.link_products() > Move products into the fit group; they then use its garment. Source: https://docs.tryyoursize.com/reference/python/fit-groups-link-products/ *Method* · `tryyoursize` Move products into the fit group; they then use its garment. ```python def link_products(fit_group_id: str, *, product_ids: Iterable[str], idempotency_key: Optional[str] = None) -> FitGroup ``` ## Parameters - **`fit_group_id`** (`str`, required): The fit group ID. - **`product_ids`** (`Iterable[str]`, required): Products to move into the group. - **`idempotency_key`** (`Optional[str]`, optional, default `None`) ## Returns `FitGroup`: The fit group. ## Example **Python** ```python tys.fit_groups.link_products(group["id"], product_ids=[white["id"]]) ``` **Node.js** ```ts await tys.fitGroups.linkProducts(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 - [fit_groups.link_products (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/linkcatalogfitgroupproducts.md) --- # tys.fit_groups.list() > Fit groups, cursor-paginated. Source: https://docs.tryyoursize.com/reference/python/fit-groups-list/ *Method* · `tryyoursize` Fit groups, cursor-paginated. ```python def list(*, limit: Optional[int] = None, cursor: Optional[str] = None) -> ListPage ``` ## Parameters - **`limit`** (`Optional[int]`, optional, default `None`): Page size. - **`cursor`** (`Optional[str]`, optional, default `None`): `next_cursor` of the previous page. ## Returns `ListPage`: Fit groups. A dict with `data`, `has_more`, `next_cursor`; `next_page()` and `auto_paging_iter()` walk the rest. See [ListPage](https://docs.tryyoursize.com/reference/python/list-page.md). ## Example **Python** ```python for group in tys.fit_groups.list().auto_paging_iter(): print(group["id"], group["name"]) ``` **Node.js** ```ts for await (const g of tys.fitGroups.list()) console.log(g.id, g.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 - [fit_groups.list (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/listcatalogfitgroups.md) --- # tys.fit_groups.retrieve() > A fit group. Source: https://docs.tryyoursize.com/reference/python/fit-groups-retrieve/ *Method* · `tryyoursize` A fit group. ```python def retrieve(fit_group_id: str) -> FitGroup ``` ## Parameters - **`fit_group_id`** (`str`, required): The fit group ID. ## Returns `FitGroup`: The fit group. ## Example **Python** ```python group = tys.fit_groups.retrieve(group_id) ``` **Node.js** ```ts const group = await tys.fitGroups.retrieve(groupId); ``` **cURL** ```bash curl https://api.tryyoursize.com/v1/fit_groups/ \ -H "Authorization: Bearer $TRYYOURSIZE_SECRET_KEY" \ -H "TYS-Version: 2026-10-25" ``` ## See also - [fit_groups.retrieve (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/getcatalogfitgroup.md) --- # tys.garments.publish() > Publish a complete draft (same checks as Studio; 422 lists what is missing). Source: https://docs.tryyoursize.com/reference/python/garments-publish/ *Method* · `tryyoursize` Publish a complete draft (same checks as Studio; 422 lists what is missing). ```python def publish(garment_id: str, *, idempotency_key: Optional[str] = None) -> GarmentVersion ``` ## Parameters - **`garment_id`** (`str`, required): The draft's ID. - **`idempotency_key`** (`Optional[str]`, optional, default `None`) ## Returns `GarmentVersion`: The published version. ## Errors `InvalidRequestError` (422); `err.issues` lists what is missing. ## Example **Python** ```python try: tys.garments.publish(draft["id"]) except tryyoursize.InvalidRequestError as err: print(err.issues) # what is missing ``` **Node.js** ```ts try { await tys.garments.publish(draft.id); } catch (err) { if (err instanceof InvalidRequestError) console.log(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() > A garment version. Source: https://docs.tryyoursize.com/reference/python/garments-retrieve/ *Method* · `tryyoursize` A garment version. ```python def retrieve(garment_id: str) -> GarmentVersion ``` ## Parameters - **`garment_id`** (`str`, required): The garment version ID. ## Returns `GarmentVersion`: The garment version. ## Example **Python** ```python version = tys.garments.retrieve(garment_id) ``` **Node.js** ```ts const version = await tys.garments.retrieve(garmentId); ``` **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.update_draft() > Replace a draft's content. Source: https://docs.tryyoursize.com/reference/python/garments-update-draft/ *Method* · `tryyoursize` Replace a draft's content. Published versions never change (409). ```python def update_draft(garment_id: str, garment: GarmentInput) -> GarmentVersion ``` ## Parameters - **`garment_id`** (`str`, 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. ## Returns `GarmentVersion`: The updated draft. Published versions never change (409). ## Example **Python** ```python tys.garments.update_draft(draft["id"], {**garment, "season": "SS27"}) # replaces the draft ``` **Node.js** ```ts await tys.garments.updateDraft(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.update_draft (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/updatecataloggarmentdraft.md) --- # ListPage > One page of a list. Source: https://docs.tryyoursize.com/reference/python/list-page/ *Class* · `tryyoursize` One page of a list. A `dict` with `data`, `has_more` and `next_cursor` (also as attributes). `auto_paging_iter()` yields every item, fetching the following pages lazily. ```python class ListPage(Dict[str, Any]) ``` ## Members - **`data`** (`list`, required): The items of this page. - **`has_more`** (`bool`, required): Whether another page follows. - **`next_cursor`** (`Optional[str]`, required): Cursor of the next page. - **`next_page()`** (`Optional[ListPage]`, required): The following page, or `None` at the end. - **`auto_paging_iter()`** (`Iterator[Any]`, required): Every item of this page and all following pages. ## Example **Python** ```python page = tys.products.list(limit=20) while page is not None: for product in page.data: print(product["external_id"]) page = page.next_page() ``` **Node.js** ```ts for await (const page of tys.products.list({ limit: 20 }).pages()) { for (const p of page.data) console.log(p.external_id); } ``` ## See also - [Pagination](https://docs.tryyoursize.com/guides/pagination.md) --- # tys.mode > "test" or "live", from the key prefix ("unknown" for other formats). Source: https://docs.tryyoursize.com/reference/python/mode/ *Property* · `tryyoursize` `"test"` or `"live"`, from the key prefix (`"unknown"` for other formats). ```python @property def mode() -> str ``` ## Example **Python** ```python if tys.mode == "live": enable_order_sync() ``` **Node.js** ```ts if (tys.mode === "live") enableOrderSync(); ``` --- # tys.orders.create() > Record an order (idempotent by order id; re-sending updates it). Source: https://docs.tryyoursize.com/reference/python/orders-create/ *Method* · `tryyoursize` Record an order (idempotent by order `id`; re-sending updates it). No customer data. ```python def create(order: OutcomeOrderInput, *, idempotency_key: Optional[str] = None) -> OutcomeOrderResult ``` ## 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. - **`idempotency_key`** (`Optional[str]`, optional, default `None`) ## Returns `OutcomeOrderResult`: 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 **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}], }) ``` **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 }, ], }); ``` **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) --- # tys.products.create() > Create a product. Source: https://docs.tryyoursize.com/reference/python/products-create/ *Method* · `tryyoursize` Create a product. `external_id` (SKU / style ID) is unique per store (409). ```python def create(*, external_id: str, name: str, category: str, idempotency_key: Optional[str] = None) -> Product ``` ## Parameters - **`external_id`** (`str`, required): Your SKU / style ID, unique per store (409 otherwise). - **`name`** (`str`, required): The product name. - **`category`** (`str`, required): The garment category, e.g. `tshirt`, `jeans`. - **`idempotency_key`** (`Optional[str]`, optional, default `None`) ## Returns `Product`: 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 **Python** ```python product = tys.products.create(external_id="TEE-001", name="Basic tee", category="tshirt") ``` **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", }); ``` **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.create_draft() > Start a draft version: sizes, points of measure (mm) per size, grading, fabric. Source: https://docs.tryyoursize.com/reference/python/products-garments-create-draft/ *Method* · `tryyoursize` Start a draft version: sizes, points of measure (mm) per size, grading, fabric. A 422 raises `InvalidRequestError` with the issues in `err.body["issues"]`. ```python def create_draft(product: str, garment: GarmentInput, *, idempotency_key: Optional[str] = None) -> GarmentVersion ``` ## Parameters - **`product`** (`str`, required): The product's TryYourSize ID or your SKU (URL-encoded for you). - **`garment`** (`GarmentInput`, required): The garment: category, fit intent, sizes, points of measure per size (mm), grading and fabric. - **`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. - **`idempotency_key`** (`Optional[str]`, optional, default `None`) ## Returns `GarmentVersion`: The draft garment version, with `issues` that still block publishing. ## Example **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"]) ``` **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 ``` **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 - [products.garments.create_draft (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createcataloggarmentdraft.md) --- # tys.products.garments.list() > Garment versions of a product, newest first (has_more is always false). Source: https://docs.tryyoursize.com/reference/python/products-garments-list/ *Method* · `tryyoursize` Garment versions of a product, newest first (`has_more` is always false). ```python def list(product: str) -> ListPage ``` ## Parameters - **`product`** (`str`, required): The product's TryYourSize ID or your SKU (URL-encoded for you). ## Returns `ListPage`: Garment versions, newest first (a single page). A dict with `data`, `has_more`, `next_cursor`; `next_page()` and `auto_paging_iter()` walk the rest. See [ListPage](https://docs.tryyoursize.com/reference/python/list-page.md). ## Example **Python** ```python versions = tys.products.garments.list("TEE-001") # newest first ``` **Node.js** ```ts const { data } = await 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() > The store's products, newest first. Source: https://docs.tryyoursize.com/reference/python/products-list/ *Method* · `tryyoursize` The store's products, newest first. `sku` finds one product by SKU / style ID. ```python def list(*, sku: Optional[str] = None, limit: Optional[int] = None, cursor: Optional[str] = None) -> ListPage ``` ## Parameters - **`sku`** (`Optional[str]`, optional, default `None`): Find one product by SKU / style ID. - **`limit`** (`Optional[int]`, optional, default `None`): Page size. - **`cursor`** (`Optional[str]`, optional, default `None`): `next_cursor` of the previous page. ## Returns `ListPage`: Products, newest first. A dict with `data`, `has_more`, `next_cursor`; `next_page()` and `auto_paging_iter()` walk the rest. See [ListPage](https://docs.tryyoursize.com/reference/python/list-page.md). ## Example **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") ``` **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" }); ``` **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() > A product by its TryYourSize ID or its SKU. Source: https://docs.tryyoursize.com/reference/python/products-retrieve/ *Method* · `tryyoursize` A product by its TryYourSize ID or its SKU. ```python def retrieve(product: str) -> Product ``` ## Parameters - **`product`** (`str`, required): The product's TryYourSize ID or your SKU (URL-encoded for you). ## Returns `Product`: 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 **Python** ```python product = tys.products.retrieve("TEE-001") # TryYourSize ID or your SKU ``` **Node.js** ```ts const product = await 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.size_map.retrieve() > A product's size map (Studio size → your size label). Source: https://docs.tryyoursize.com/reference/python/products-size-map-retrieve/ *Method* · `tryyoursize` A product's size map (Studio size → your size label). Product by ID or SKU. ```python def retrieve(product: str) -> ProductSizeMap ``` ## Parameters - **`product`** (`str`, required): The product's TryYourSize ID or your SKU (URL-encoded for you). ## Returns `ProductSizeMap`: The size map. - **`entries`** (`object[]`, required) - **`unmapped_shop_values`** (`string[]`, optional): Variant size values of the product with no Studio size yet (read only). ## Example **Python** ```python size_map = tys.products.size_map.retrieve("TEE-001") print(size_map["entries"], size_map.get("unmapped_shop_values")) ``` **Node.js** ```ts const map = await tys.products.sizeMap.retrieve("TEE-001"); console.log(map.entries, map.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.size_map.retrieve (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/getcatalogsizemap.md) --- # tys.products.size_map.save() > Replace the size map, e.g. Source: https://docs.tryyoursize.com/reference/python/products-size-map-save/ *Method* · `tryyoursize` Replace the size map, e.g. `entries=[{"studio_size": "M", "shop_value": "Medium"}]`. ```python def save(product: str, *, entries: List[ProductSizeMapEntriesItem]) -> ProductSizeMap ``` ## Parameters - **`product`** (`str`, required): The product's TryYourSize ID or your SKU (URL-encoded for you). - **`entries`** (`List[ProductSizeMapEntriesItem]`, required): `[{"studio_size": "M", "shop_value": "Medium"}, …]`: replaces the whole map. ## Returns `ProductSizeMap`: The saved size map. ## Example **Python** ```python tys.products.size_map.save("TEE-001", entries=[ {"studio_size": "S", "shop_value": "Small"}, {"studio_size": "M", "shop_value": "Medium"}, ]) ``` **Node.js** ```ts await tys.products.sizeMap.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.size_map.save (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/savecatalogsizemap.md) --- # tys.products.update() > Replace the SKU, name and category (all three required). Source: https://docs.tryyoursize.com/reference/python/products-update/ *Method* · `tryyoursize` Replace the SKU, name and category (all three required). ```python def update(product: str, *, external_id: str, name: str, category: str) -> Product ``` ## Parameters - **`product`** (`str`, required): The product's TryYourSize ID or your SKU (URL-encoded for you). - **`external_id`** (`str`, required): The SKU (all three fields are required). - **`name`** (`str`, required): The name. - **`category`** (`str`, required): The category. ## Returns `Product`: The updated product. ## Example **Python** ```python tys.products.update("TEE-001", external_id="TEE-001", name="Basic tee (organic)", category="tshirt") ``` **Node.js** ```ts await 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() > The shopper's size for up to 25 products (SKUs), from a browser SDK handle. Source: https://docs.tryyoursize.com/reference/python/recommendations-create/ *Method* · `tryyoursize` The shopper's size for up to 25 products (SKUs), from a browser SDK handle. Sizes only, in your labels: ``data`i`` has `product`, `status`` (`ready`/`computing`/`none`/`unavailable`), `size`, `studio_size` and `wearable_sizes`. Never starts a simulation. Scope `fit_checks:read`. ```python def create(*, handle: str, products: Iterable[str], idempotency_key: Optional[str] = None) -> RecommendationList ``` ## Parameters - **`handle`** (`str`, required): The handle from the browser SDK (`await tys.recommendationHandle()`), sent to your server. - **`products`** (`Iterable[str]`, required): Up to 25 of your SKUs / style IDs. - **`idempotency_key`** (`Optional[str]`, optional, default `None`) ## Returns `RecommendationList`: `{"data": [...]}`, one recommendation per product, in your size labels. Sizes only. - **`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 **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"]) ``` **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); } ``` **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) - [recommendations.create (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createrecommendations.md) --- # tys.returns.create() > Record a return of an order line (idempotent by return id and line). Source: https://docs.tryyoursize.com/reference/python/returns-create/ *Method* · `tryyoursize` Record a return of an order line (idempotent by return `id` and line). ```python def create(ret: OutcomeReturnInput, *, idempotency_key: Optional[str] = None) -> OutcomeReturnResult ``` ## 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) - **`idempotency_key`** (`Optional[str]`, optional, default `None`) ## Returns `OutcomeReturnResult`: What was recorded. ## Example **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(), }) ``` **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(), }); ``` **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 - [returns.create (HTTP API)](https://docs.tryyoursize.com/api/reference/operations/createoutcomereturn.md) --- # Webhook.construct_event() > Verify the signature, then return the parsed event envelope. Source: https://docs.tryyoursize.com/reference/python/webhook-construct-event/ *Method* · `tryyoursize` Verify the signature, then return the parsed event envelope. ```python @staticmethod def construct_event(payload: Union[bytes, str], sig_header: str, secret: str, tolerance: int = DEFAULT_TOLERANCE, now: Optional[int] = None) -> WebhookEvent ``` ## Parameters - **`payload`** (`Union[bytes, str]`, required): The raw request body (bytes or str), never re-serialized JSON. - **`sig_header`** (`str`, required): The `TYS-Signature` header. - **`secret`** (`str`, required): The endpoint's signing secret (`whsec_…`). - **`tolerance`** (`int`, optional, default `DEFAULT_TOLERANCE`): Accepted age in seconds (either direction); 0 disables the check. - **`now`** (`Optional[int]`, optional, default `None`): Overrides the clock (unix seconds), for tests. ## Returns `WebhookEvent`: The event envelope (`id`, `type`, `api_version`, `created`, `mode`, `store_id`, `data`). ## Errors `SignatureVerificationError`. ## Example **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 ``` **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); }); ``` ## See also - [Webhooks guide](https://docs.tryyoursize.com/guides/webhooks.md) --- # Webhook.generate_test_header() > A valid TYS-Signature value, for your own tests. Source: https://docs.tryyoursize.com/reference/python/webhook-generate-test-header/ *Method* · `tryyoursize` A valid `TYS-Signature` value, for your own tests. ```python @staticmethod def generate_test_header(payload: Union[bytes, str], secret: str, timestamp: Optional[int] = None) -> str ``` ## Parameters - **`payload`** (`Union[bytes, str]`, required): The body you will send. - **`secret`** (`str`, required): The signing secret. - **`timestamp`** (`Optional[int]`, optional, default `None`): Unix seconds (default now). ## Returns `str`: A valid `TYS-Signature` value. ## Example **Python** ```python payload = json.dumps({"id": "evt_test", "object": "event", "type": "webhook.test", "data": {}}) header = tryyoursize.Webhook.generate_test_header(payload, "whsec_test") ``` **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, }); ``` --- # Webhook.verify_signature() > Return True or raise SignatureVerificationError. Source: https://docs.tryyoursize.com/reference/python/webhook-verify-signature/ *Method* · `tryyoursize` Return `True` or raise `SignatureVerificationError`. `tolerance` is the accepted age in seconds (either direction); `0` or less disables the check. `now` overrides the clock (unix seconds), for tests. ```python @staticmethod def verify_signature(payload: Union[bytes, str], sig_header: str, secret: str, tolerance: int = DEFAULT_TOLERANCE, now: Optional[int] = None) -> bool ``` ## Parameters - **`payload`** (`Union[bytes, str]`, required): The raw request body. - **`sig_header`** (`str`, required): The `TYS-Signature` header. - **`secret`** (`str`, required): The signing secret. - **`tolerance`** (`int`, optional, default `DEFAULT_TOLERANCE`): Accepted age in seconds. - **`now`** (`Optional[int]`, optional, default `None`): Clock override, for tests. ## Returns `bool`: `True`, or raises `SignatureVerificationError`. ## Example **Python** ```python tryyoursize.Webhook.verify_signature(payload, sig_header, secret) # True, or raises SignatureVerificationError ``` **Node.js** ```ts tys.webhooks.verifySignature(rawBody, req.headers["tys-signature"], secret); // throws SignatureVerificationError ```