API Overview
How to get a key, authenticate, and start using the Market Ninja API — the resolve-then-fetch model, limits, error format.
The Market Ninja API gives programmatic read access to the same crowdsourced dataset you see in the extension's own UI: products, prices (current and historical), sellers, and categories from Wildberries, Ozon, Yandex Market, and Lamoda.
Getting a key
Issued from the extension's options page — API Keys section, available on the
Premium tier. The full key value (mn_live_...) is shown exactly once, at creation
time — save it immediately, it can't be recovered later (only revoked and reissued).
Authentication
Every request needs this header:
Authorization: Bearer mn_live_your_keycurl -H "Authorization: Bearer mn_live_..." \
"https://data.marketninja.ru/v1/products?page_size=3"Core usage model: "resolve, then fetch"
No external integrator knows our internal product id up front — nothing tells you
that in advance. Instead, you always start with whatever you already have:
Find the product via GET /products, passing whatever you have: a product URL
(url), the marketplace's own SKU (external_id + marketplace), or your own internal
SKU (seller_code).
Read the id off the data[].id field in the response — our internal identifier.
If you need to, fetch that product directly by id (GET /products/{id}) or its
price history (GET /products/{id}/price-history) — though note the current price is
already in the response from step 1; the dedicated call is only for trend analysis.
Detailed scenarios with examples: Finding products, Price history, Sellers, Categories, Brands, Bulk export, Scrape sessions (retrieving what you just scraped via the extension), and Webhooks (get notified when a session finishes instead of polling). Full docs on parameters and responses for every endpoint: Reference.
Error format
Every error comes back in one shape:
{ "error": { "code": "invalid_api_key", "message": "Invalid or revoked API key" } }| HTTP status | error.code | Meaning |
|---|---|---|
400 | validation_error | Invalid query parameters. |
401 | invalid_api_key | The key is missing, malformed, unknown, revoked, or expired. |
403 | subscription_lapsed | The key is valid, but Premium isn't currently active. |
404 | not_found | No product with that id exists. |
429 | rate_limited | Per-minute request rate exceeded — see Retry-After. |
429 | quota_exceeded | Daily data-volume quota exhausted — resets at midnight UTC. |
500 | internal_error | An internal server error — safe to retry later. |
403 and 401 are different problems for an integrator: "your key is wrong" (check the value) vs. "go resubscribe" (the key itself works, but access is paused). Don't handle them the same way in your code — the message shown to your user should differ.Limits: two independent mechanisms
- Request rate limit (
rate_limited) — bounds how fast you can call, resets every minute.X-RateLimit-Limit/X-RateLimit-Remaining/Retry-Afterheaders. - Daily data-volume quota (
quota_exceeded) — bounds how many product records you can pull in a day (counts records actually returned, not requests — a singlepage_size=500call costs more quota thanpage_size=10). Resets at midnight UTC.X-Quota-Limit/X-Quota-Usedheaders.
Both header sets only appear on the 429 response itself — not on successful responses.
Worth knowing
- Cache the
idyou resolve. It never changes — if you're polling the same product regularly (e.g. a brand reconciling its catalog daily), save theidfrom the first search and call directly byidfrom then on instead of repeatingGET /products— saves both a request and quota. unverified/flaggeddata is never hidden by default.trust_statusis always present in every product response — whether to trust a not-yet-corroborated record is your call, not something the API decides for you.- Pagination doesn't require knowing the page count up front — read
meta.totalfrom the response and keep going until you have what you need.
Last updated on