Skip to content

Errors and limits ​

Error shape ​

Both APIs use the same error shape at the request level:

json
{ "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.

codeHTTPwhat it means
missing_key401the key query parameter is missing (Search API)
invalid_key403unknown or malformed public key
invalid_credentials401missing or invalid Authorization header (Catalog API)
insecure_transport400the request arrived over HTTP with a secret key (Catalog API); use HTTPS
invalid_parameter422unsupported 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_payload400the body is not valid JSON, not a list of products, or does not contain ids
batch_too_large400the batch holds more than 100 products
catalog_mode_conflict409the e-shop is in feed mode, writes are rejected
generation_incomplete, generation_committed409a sync commit did not pass a safeguard; generation_committed also for a write with ?sync= into a sync that is already committed
not_found404unknown sync identifier, also for a write with ?sync=
index_busy503the search index of the e-shop is busy; nothing was written, repeat after Retry-After
rate_limited429rate limit exceeded; follow the Retry-After header

Per-product errors ​

These codes are not returned by the request as a whole but by an individual item in results for PUT, PATCH and DELETE:

codecause
invalid_idid is missing, empty, or longer than 255 characters
missing_name, missing_urla required field is missing on PUT
invalid_name, invalid_brand, invalid_descriptionthe field is not a non-empty string
invalid_url, invalid_imagethe field is not an https URL of at most 2048 characters (for example http://, a relative path, javascript:)
invalid_price, invalid_list_pricethe price is not a JSON number, for example it arrived as a string
invalid_in_stockin_stock is not a boolean
invalid_paramsparams is not a map of name to scalar value, or a name is empty or too long
invalid_categoryempty category path
not_foundPATCH or DELETE targeted a product that does not exist

Rate limits ​

endpointlimit
GET /suggest1800 / min
GET /search600 / 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.
  • other 4xx — repeating will not help, the request has to be fixed.

Repeating a write batch is safe because writes are keyed by id.

Metty documentation