English
English
Appearance
English
English
Appearance
Both APIs use the same error shape at the request level:
{ "error": "invalid_key", "message": "Unknown or malformed public key." }error is a stable code meant for branching in code. message is English text for humans; its wording may change, so do not tie application logic to it.
| code | HTTP | what it means |
|---|---|---|
missing_key | 401 | the key query parameter is missing (Search API) |
invalid_key | 403 | unknown or malformed public key |
invalid_credentials | 401 | missing or invalid Authorization header (Catalog API) |
insecure_transport | 400 | the request arrived over HTTP with a secret key (Catalog API); use HTTPS |
invalid_parameter | 422 | unsupported parameter value (sort, include, per_page, limit, image_size, price), an unknown parameter or a malformed filter on /search, or a page beyond the 200 result window |
invalid_payload | 400 | the body is not valid JSON, not a list of products, or does not contain ids |
batch_too_large | 400 | the batch holds more than 100 products |
catalog_mode_conflict | 409 | the e-shop is in feed mode, writes are rejected |
generation_incomplete, generation_committed | 409 | a sync commit did not pass a safeguard; generation_committed also for a write with ?sync= into a sync that is already committed |
not_found | 404 | unknown sync identifier, also for a write with ?sync= |
index_busy | 503 | the search index of the e-shop is busy; nothing was written, repeat after Retry-After |
rate_limited | 429 | rate limit exceeded; follow the Retry-After header |
These codes are not returned by the request as a whole but by an individual item in results for PUT, PATCH and DELETE:
| code | cause |
|---|---|
invalid_id | id is missing, empty, or longer than 255 characters |
missing_name, missing_url | a required field is missing on PUT |
invalid_name, invalid_brand, invalid_description | the field is not a non-empty string |
invalid_url, invalid_image | the field is not an https URL of at most 2048 characters (for example http://, a relative path, javascript:) |
invalid_price, invalid_list_price | the price is not a JSON number, for example it arrived as a string |
invalid_in_stock | in_stock is not a boolean |
invalid_params | params is not a map of name to scalar value, or a name is empty or too long |
invalid_category | empty category path |
not_found | PATCH or DELETE targeted a product that does not exist |
| endpoint | limit |
|---|---|
GET /suggest | 1800 / min |
GET /search | 600 / min |
/catalog/* | 120 / min |
The /search and /suggest limits are counted per caller IP address: the public key is visible to every visitor of the e-shop, so it does not identify the caller. When you call the Search API from your own server, all requests from that server share one limit. The widget counts toward the /search limit of the visitor's IP as well, so a browser that runs the widget and also calls GET /search directly shares one 600 / min. The /catalog/* limit is counted per secret key, so one integrator cannot affect the others. A larger batch consumes more: one extra token is added for every 256 KB of the request body.
When the limit is exceeded we return 429 with the Retry-After, X-RateLimit-Limit and X-RateLimit-Remaining headers.
429 — wait according to the Retry-After header and repeat the request.5xx — repeat with exponential backoff.4xx — repeating will not help, the request has to be fixed.Repeating a write batch is safe because writes are keyed by id.