Try-On
Create Try-On
Run a virtual try-on. Reference an existing product or describe one inline; pre-upload the customer image or ship it in the same request.
POST
Creates a virtual try-on generation. Runs asynchronously — poll Generation Status for the result. Each generation consumes 1 credit.
The body has three parts: a
Full catalog at Errors. If a reference call returns
products array describing what to try on, a person image (the shopper photo, either pre-uploaded or shipped inline), and optional externalUserId / output controls.
Products
products is an array. For now it must hold exactly one item (multi-product try-on is on the roadmap). Each item works three ways:
- Reference an existing product — pass
{ "externalId": "..." }only. Cheapest call (~50 bytes on the wire). - Describe a product inline — pass
{ "externalId": "...", "title": ..., "description": ..., "images": [...] }. Creates the product if it’s new; updates it if it’s not. Inline-created products live for 15 days from their last use; the server refreshes the timer on every generation, so an actively-used product never expires. - One-shot — omit
externalId. The server returns a generated ID in the response underproductExternalIdthat you can pass back if you want to reference the same product later. One-shot products live for 7 days from their last use.
Array of product specs to try on. Exactly one item for now — multi-product try-on is on the roadmap.
Person
The shopper photo.person.image.source holds exactly one of id, url, or fileKey.
Optional opaque identifier of your own end user (e.g. your user ID). No PII — it’s used purely as an attribution and GDPR key. When set, the generation — and the person image uploaded as part of this call — can be wiped on demand via
DELETE /customers/:customerId (pass the same value as the path segment).Optional controls over the generated result.
The previous request shape is still accepted but deprecated (this is not a breaking change). The old form used a top-level singular
product object, a customer object (customer: { source: { id | url | fileKey } }), a top-level customerId, and top-level useWatermark / retentionDays. Migrate to products: [...], person.image.source, externalUserId, and output.watermark / output.keepForDays. See the Changelog.Recommended flow
- Upload the person image once via
POST /images/upload— gets you animageIdyou can reuse. - Call
/try-onwith{ products: [{ externalId }], person: { image: { source: { id: imageId } } } }for repeat generations against known products, or with a full inline product when introducing a new SKU.
person.image.source.url and person.image.source.fileKey paths are convenient one-shot conveniences but they re-download/re-upload on every call. Stick to /images/upload once you’re in steady state.
Examples
Response
Poll
GET /generations/:id every 2s until status is COMPLETED or
FAILED.Initial status:
PENDING.The product’s external ID. Echoes back the value you sent for named calls; on one-shot calls it’s a server-generated
ID you can store and re-use to reference the same product later.
Errors
| Code | HTTP | Meaning |
|---|---|---|
PRODUCT_NOT_FOUND | 404 | The referenced externalId doesn’t exist (or has expired). Retry with a full inline payload. |
PRODUCT_IMAGES_REQUIRED | 400 | One-shot call (no externalId) without any image. |
CUSTOMER_IMAGE_REQUIRED | 400 | person is missing. |
CUSTOMER_IMAGE_FETCH_FAILED | 400 | person.image.source.url could not be downloaded — DNS fail, host unreachable, or non-2xx status. |
MULTIPART_FILE_NOT_FOUND | 400 | A fileKey from data doesn’t appear in the multipart payload. |
VALIDATION_FAILED | 400 | Request body failed validation — see details[] for the offending fields. |
INSUFFICIENT_CREDITS | 402 | Account is out of credits. |
RESERVED_EXTERNAL_ID | 409 | product.externalId starts with _anon_, which is reserved for server-generated IDs. |
PRODUCT_NOT_FOUND, the product has fallen out of cache — retry with the full inline payload to recreate it. No sync loop required.
Watermarking
If your account has a logo configured, the result comes back with the logo composited in the bottom-left corner. Passoutput: { watermark: false } to skip it on a single call. See Watermark for configuration.
