Limits¶
Every limit of the Ziex Try-On API that you can run into, with the value, what you get when you cross it, and how to react. For the shape of the answers and the retry rules, see Errors.
Three rules cover most of this page:
- Every
429,409and503that the API produces carriesRetry-After(whole seconds). Wait that long. - A request refused by a limit before a job exists takes nothing from your plan, so repeating it with the same
Idempotency-Keyafter the wait is safe. - A server that sends all its shoppers' requests from one address shares one budget for every per-address limit
below. If you submit from your server for many shoppers, you are one address to the API: slow down and queue, or
expect
429 RATE_LIMITED.
Request size and images¶
| Limit | Value | When exceeded | What to do |
|---|---|---|---|
| Request body | 12 MB in total | 413 PAYLOAD_TOO_LARGE, produced before the request reaches the API |
Send smaller photos. Do not retry unchanged. |
| One decoded image | 10 MB | 422 VALIDATION_ERROR |
Compress the photo. |
| Image dimensions | up to 16 megapixels (4096 x 4096 pixels), at least 256 x 256 pixels | 422 VALIDATION_ERROR |
Resize before upload. |
| Image formats | JPEG, PNG, WebP, HEIC, AVIF | 422 VALIDATION_ERROR |
Convert the photo. |
| Image sent as a URL | up to 2048 characters, http or https only |
422 VALIDATION_ERROR |
Use a shorter URL, or send the image as an upload. |
Images larger than needed are shrunk by the service (the long side to 1500 pixels) before they are processed, so
there is no benefit in sending more than about 1500 pixels on the long side. A publishable key must send the shopper's photo as an upload
(a data: URI), never as a URL; the garment may be a URL.
Request rates¶
These limits count requests per client address, except where a key is named. The edge enforces its limits first;
a request over them gets 429 RATE_LIMITED with Retry-After: 1 and never reaches the API.
| Limit | Value | When exceeded | What to do |
|---|---|---|---|
POST /api/v1/tryon, per address, at the edge |
2 requests per second (2 r/s), a burst of 5 | 429 RATE_LIMITED, Retry-After: 1 |
Space submits at least half a second apart. |
| Submits per address, in the API | 30 per minute, in a fixed window that the first submit opens (live and test keys by the same rule, each with its own counter) | 429 RATE_LIMITED, Retry-After = what is left of the window (at least 1 s) |
Wait. A refused submit does not count and does not move the window. |
GET /api/v1/tryon/status/{job_id} and GET /api/v1/tryon/attempts/{idempotency_key}, per address |
20 requests per second (20 r/s), a burst of 30 | 429 RATE_LIMITED, Retry-After: 1 |
Poll every 1 to 2 seconds per job, not in a tight loop. |
GET /api/v1/tryon/result/{job_id}, per address |
1 request per second (1 r/s), a burst of 10 | 429 RATE_LIMITED, Retry-After: 1 |
Fetch results one at a time and keep them; do not poll this endpoint. |
All other API requests (capabilities, domain-check, integration, jobs), per address |
10 requests per second (10 r/s), a burst of 20 | 429 RATE_LIMITED, Retry-After: 1 |
Cache GET /api/v1/tryon/capabilities (it is public and cacheable for 5 minutes). |
GET /api/v1/tryon/jobs, per key |
60 requests per minute | 429 RATE_LIMITED, Retry-After = what is left of the window |
Poll the list once a minute, not faster. |
| Publishable key, per (key, address) | 10 per 10 minutes, counting created jobs (a test publishable key: 60) | 429 RATE_LIMITED, Retry-After = what is left of the window |
A public key can be copied from the page, so this bounds what a copy can spend. Normal shoppers do not reach it. |
Hourly limit of a key (rate_limit) |
Set per key, 100 per hour by default. Only created jobs from POST /api/v1/tryon count; refused submits do not |
429 RATE_LIMITED, Retry-After = what is left of the hour |
Wait. For a higher rate_limit on the key, contact us (see Contact). |
Plan and daily caps¶
| Limit | Value | When exceeded | What to do |
|---|---|---|---|
| Plan quota | The generations of your plan per billing period, enforced with a 10 % tolerance (a soft cap). A failed or interrupted job gives its generation back | 429 LIMIT_EXCEEDED, Retry-After = time to the reset (at least 60 s; one day when no reset date is set) |
Retrying before the reset does not help. Raise the plan, or wait. |
| Platform-wide daily cap | A ceiling on all generations of the platform per UTC day | 429 DAILY_CAP_REACHED, Retry-After = time to the next UTC midnight |
Do not loop. Try again after midnight UTC. |
| One key's share of the daily cap | A single key may use at most 50 % of the platform-wide daily cap, secret and publishable keys alike | 429 DAILY_CAP_REACHED, Retry-After = time to the next UTC midnight |
As above. If you need more, contact us (see Contact). |
The daily cap protects every account from a leaked key. The exact figure of the platform-wide daily cap is not part of the contract.
Fields of the request¶
| Field or header | Limit | When exceeded | What to do |
|---|---|---|---|
Idempotency-Key |
22-64 characters from A-Z a-z 0-9 _ - (^[A-Za-z0-9_-]{22,64}$). A repeat with the same key finds its job for as long as the job exists (at least 24 hours) |
422 VALIDATION_ERROR for a malformed key |
Use a UUID without dashes (32 characters). One key per attempt. |
product_title |
At most 1000 characters in the request; stored cut to 200 characters | 422 VALIDATION_ERROR above 1000 (nothing is charged) |
Send a short title. A longer title up to 1000 is accepted and shortened. |
product_url |
At most 4096 characters in the request; stored only if it is a plain http or https link of at most 2048 characters |
422 VALIDATION_ERROR above 4096; between 2048 and 4096 the link is dropped (null), not refused |
Send the canonical product link. |
integration |
At most 64 characters, in the form name/version (for example woocommerce/1.4.0) |
Never refused: a bad value is dropped | Send it as documented, or leave it out. |
category |
A category id from GET /api/v1/tryon/capabilities |
422 CATEGORY_UNSUPPORTED for one that is unknown or unavailable |
Read the list; do not hard-code it. |
Processing and time¶
| Limit | Value | When exceeded | What to do |
|---|---|---|---|
| Wait for a free image-processing slot | Up to 10 seconds, when every slot is busy with other submits | 503 OVERLOADED, Retry-After: 5, no X-Job-Id. No job exists |
Repeat with the same Idempotency-Key after Retry-After. |
| Time to a final state | Every job is completed, failed or interrupted within 45 minutes (a pending job is ended after 30 minutes, a processing job after 15) |
The job is ended as failed by the platform | Stop waiting at 45 minutes and read the status; a webhook may not be sent for such a job. |
| Webhooks | Best effort, not a limit of time | A late or lost webhook | Reconcile by polling GET /api/v1/tryon/status/{job_id} or GET /api/v1/tryon/jobs?since=.... |
| Webhook endpoints per account | 10 (live and test together) | 409 WEBHOOK_LIMIT (no Retry-After) |
Delete an unused endpoint, then create the new one. |
Test keys and retention¶
| Limit | Value | When exceeded | What to do |
|---|---|---|---|
| Test keys per account | Up to 3 | 409 TEST_KEY_LIMIT (no Retry-After) |
Delete one, then create the new one. |
| Test submits per address | 30 per minute for a test key (its own counter, the same fixed window as a live key) and 60 per 10 minutes for a test publishable key | 429 RATE_LIMITED |
Wait Retry-After. |
| Photos and results of live try-ons | Kept for 180 days, then deleted | The file is gone: its result_url no longer works |
Keep your own copy of anything you need longer. |
| Files of test try-ons | Kept for 72 hours, then deleted | As above | Test results are placeholders; nothing needs to be kept. |
What Retry-After means¶
| Answer | Retry-After |
|---|---|
429 RATE_LIMITED from the edge |
1 second |
429 RATE_LIMITED from the API |
What is left of the window that was exceeded (a minute, 10 minutes, an hour), at least 1 second |
429 LIMIT_EXCEEDED |
Seconds to the reset of your plan period, at least 60; one day when no reset date is set |
429 DAILY_CAP_REACHED |
Seconds to the next UTC midnight |
409 IDEMPOTENT_IN_PROGRESS |
2 seconds |
503 SUBMIT_UNCONFIRMED |
2 seconds (with X-Job-Id) |
503 ATTEMPT_LOOKUP_UNAVAILABLE |
2 seconds |
503 OVERLOADED |
5 seconds (without X-Job-Id) |
A browser page can read Retry-After, X-Job-Id, Location and X-Request-ID on these answers.
Changing a limit¶
Loosening a documented limit is an additive change and may happen at any time. Tightening a documented limit counts as a breaking change and is announced at least 90 days before it takes effect.