Limits and throughput
Every number you can hit, what happens when you hit it, and how long a large feed really takes.
Limits
| Limit | Value | Past it |
|---|---|---|
| Rows per batch | 1,000 | 400 INVALID_REQUEST |
| Bytes per batch | 5 MiB (5,242,880 bytes) | 413 REQUEST_BODY_TOO_LARGE |
| Inventory request | 1,000 rows, 1 MiB | 413 REQUEST_BODY_TOO_LARGE |
| Batches per job | About 2,000 (roughly 2 million rows) | 409 JOB_FULL |
| Open jobs per caller | 3 | 409 TOO_MANY_OPEN_JOBS |
| Waiting batches per caller | 2,000 received, not yet applied | 429 PUSH_QUEUE_FULL, Retry-After: 60 |
| Job lifetime while open | 24 hours | Expires: JOB_EXPIRED |
| Request rate | 600 per 60 s per key (approximate) | 429 RATE_LIMITED with Retry-After |
| Idempotency-Key | 1 to 200 characters | 400 INVALID_REQUEST |
| Job CSV report | Up to 900 parts | 409 REPORT_TOO_LARGE |
| Report retention | 30 days after the run finishes | 410 REPORT_EXPIRED |
| Refs per archive, restore or assign call | 100 | 400 INVALID_REQUEST |
| GET /products page size | 1 to 100, default 50 | 400 INVALID_REQUEST |
| externalId length | 255 characters | 400 INVALID_REQUEST or a refused row |
| Idempotency-Key memory | 24 hours | After that the same key is treated as new |
| Stock adjust de-duplication (job rows) | 7 days | A repeated adjust row of the same delivery is not applied twice |
| Vendors per store / keys per vendor | 200 / 2 active | Creation is refused |
The rate limiter is approximate: it is not an exact meter, so a burst can slip a little past 600 or be
refused a little early. Treat 600 per minute as a design target, not an exact meter, and always honor
Retry-After. A vendor key is limited on every route; the store key on jobs and products routes only.
Throughput: two measured runs
| Measure | Run 1 (Worker e844ed62) | Run 2 (Worker e2f3c98a, after a read-path fix) |
|---|---|---|
| Upload (open to close) | 321 s | 354 s |
| Close to completed | 2,963 s (49 min) | 3,327 s (55 min) |
| Rows per minute while applying (close to completed) | about 7,538 | about 6,713 |
| Rows per minute end to end | about 6,707 | about 6,045 |
| End to end (open to fully live) | 3,330 s (55 min) | 3,694 s (62 min) |
| Rows refused or failed | 0 | 0 |
- Expect about 1 hour per 120,000 products with images, roughly 6.7k to 7.5k rows per minute on average, and plan on a feed with many new image URLs taking that long or longer.
- The apply rate falls during a run (about 12k to 13k rows per minute at the start, about 3.5k in the middle) and recovers once the image copies drain. The fix between the runs cut database reads by half and made them independent of catalog size, but did not make the run faster.
- Updates to existing products with no image changes run faster: a price update of about 150,000 rows on the same store applied at about 46,000 rows per minute (a single run on 2026-11-01, 195 s, Worker e844ed62).
- The same 120,000-product feed ran in about 4 minutes on a local test stack. Do not read that as a production figure.
What to do about it
- Split very large catalogs across jobs (for example by category or by 20,000 products), and keep at most 3 open at once.
- Poll the job every few seconds, or use the webhook, rather than holding a connection open. Closing returns at once.
- Send updates without images as a separate, small job so they are not queued behind a big image feed (lanes take turns, but a lane applies its own work in order).
Images
Image copies run in two phases. While a job applies, they run alongside it: about 200 to 285 copies per minute at peak in one production run (2026-11-01, Worker e2f3c98a, a single run on one store). Copies still waiting when the job ends are picked up by a sweep that runs every 5 minutes and publishes up to 100 jobs per run, about 20 copies per minute (in the first run, 1,607 leftover copies took about 40 minutes). Until a copy lands, the storefront serves the vendor's own image URL, so keep those URLs public and stable. A catalog also has a budget of 20,000 image resizes per calendar month (roughly 6,700 images), so a feed with more images than that stays partly on vendor URLs for longer. A completion event means rows are written, not that images are copied. See known limits.
How fresh is the storefront?
Rows are visible a few seconds after finishedAt (8.6 s and 39 s were measured on
the two large runs). An archived product can still be served for up to 60 seconds from the edge cache.