Troubleshooting
Organized by what you’re seeing, not by what’s wrong. Each entry says how to confirm the cause before you change anything.
Every request returns 401 unauthorized
Section titled “Every request returns 401 unauthorized”The key is missing, malformed, or revoked.
- The header is
Authorization: Bearer tryon_sk_...— theBearerprefix is required. - Keys are shown once at creation. If you didn’t copy it, you can’t recover it; create a new one in the panel under Settings → API Keys and revoke the old one.
- A revoked key returns
401, not403.
See Authentication for the key format and rotation.
404 not_found on a product you know exists
Section titled “404 not_found on a product you know exists”Two different situations return the same response, deliberately.
- Wrong id type. REST paths take the TryOn
id(a UUID). They do not acceptexternal_id. If all you have is your own SKU, look it up first withGET /v1/products?external_id=SKU-1234— see Using your own IDs. - Another shop’s product. Every request is scoped to the shop that owns the key, and a
product belonging to a different shop returns
404rather than403. That is intentional: it never confirms whether a resource exists elsewhere. See Cross-shop access.
swap_ready never becomes true
Section titled “swap_ready never becomes true”Processing normally finishes in under a minute. After a few minutes, assume failure rather than slowness.
- Check
images_failedfrom thePOST /v1/productsresponse. A URL that timed out, wasn’t publicly reachable, wasn’t a JPEG/PNG/WebP/GIF, or exceeded 15 MB is reported there and is never silently retried. - Check the product’s
imagesarray. If it’s empty, every URL in the batch failed and there is nothing to process. - Confirm the URL is reachable from the public internet. A URL your own servers can fetch
but the public internet can’t — localhost, a private network address, anything behind auth —
fails as
unreachable_url.
Images lists every per-image code and what it means.
400 validation_error when enabling try-on
Section titled “400 validation_error when enabling try-on”Enabling requires a category (set at create time, and it can’t be left unset later) and a
mode.
The common case is mode: realtime, which additionally requires an active 3D asset and returns
400 validation_error with “Active 3D asset required for real-time mode” when none is usable.
3D assets are managed in the panel — this API can’t attach one.
mode: swap is the only mode you can drive end-to-end through the API.
Also note that changing mode on a product that already has try-on enabled turns it off again;
send a fresh tryon_enabled: true afterward. See
Product lifecycle.
Try-on is on, but the button does nothing
Section titled “Try-on is on, but the button does nothing”Work down this list in order:
- Both gates satisfied?
tryon_statusmust be"active"andswap_readymust betrue. A product can be active withswap_ready: false— the button opens an empty experience. See tryon_status vs. swap_ready. - Is the bootstrap script actually on the page? The button is inert on its own; it only binds because the script is present.
- Does the script’s
productIdmatch the button’sdata-tryon-product-id? They have to be the same product. - Is
shop_slugcorrect? Find it in the panel under Settings → Shop.
One thing that catches people: the bootstrap script is served from
/api/v1/tryon/scripts/embed/bootstrap.js, not from the /v1/... public API namespace the rest
of these docs use. Same host, different path — copy the URL from
Storefront integration exactly rather than reconstructing
it from the REST base.
Only one product opens on a page with several
Section titled “Only one product opens on a page with several”Expected, and it’s a hard limit rather than a bug. Every bootstrap script defines the same
window.openTryOn global, so a second script on the same page overwrites the first instead
of adding a product.
For grids, quick-view cards, and bundle pages, link each product to its own product page. See The two snippets.
429 rate_limited during a bulk import
Section titled “429 rate_limited during a bulk import”The limit is 120 requests per minute per API key. The response carries a Retry-After header in
seconds — wait at least that long before retrying, and space out a catalog import rather than
firing it all at once. See Rate limits.
Still stuck?
Section titled “Still stuck?”Open the support chat in the merchant panel — the bubble in the
bottom corner reaches the team directly. Include the product id, the endpoint you called, and
the code from the error envelope; all three make it answerable on the first reply.