NinjaBuy Business API
Базовый URL
Все маршруты на этом сайте находятся под одним базовым URL. Приложение Shopify и всё, что вы разрабатываете, вызывает одни и те же маршруты, поэтому всё, что делает приложение, может сделать и ваш код.
https://www.ninjabuy.com/api/v1
Предпочитаете спросить ИИ-ассистента? Тот же аккаунт работает через MCP по адресу https://www.ninjabuy.com/mcp: ИИ-ассистенты (MCP).
- ИмпортНа входе ссылка, на выходе полная стоимость продажи.
- ТоварыЧто вы продаёте и где это выставлено.
- ВариантыКаждый вариант, привязанный к SKU продавца.
- Уровни запасовЧто можно продать прямо сейчас.
- Правила синхронизацииЧто происходит, когда продавец меняет цену.
- ЗаказыПродажа, которую мы выкупаем, проверяем и отправляем.
- Заказы на выполнениеПозиции, которые уходят одной посылкой.
- ОтправленияПосылки в пути, с трекингом.
- БалансДеньги, с которых оплачиваются заказы.
- Эндпоинты вебхуковКуда мы отправляем события.
curl "https://www.ninjabuy.com/api/v1/balance" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"Аутентификация
Передавайте API-ключ как bearer-токен в каждом запросе. Ключи начинаются с nb_. В период предварительной версии их выдаёт наша команда: когда аккаунт Business настроен, мы один раз отправляем каждый ключ по выбранному вами каналу с запрошенными областями доступа. Попросите нас отозвать ключ, и он перестанет работать со следующего запроса.
Храните ключи на сервере. Ключ в браузере, приложении или публичном репозитории может прочитать кто угодно, и им можно потратить ваш баланс.
Приложение, действующее от имени других продавцов NinjaBuy, использует OAuth 2.1: динамическую регистрацию клиента, поток authorization code с PKCE (S256) и собственный экран подтверждения продавца. Его токен доступа передаётся в том же заголовке и работает на тех же маршрутах. Токены доступа действуют час; токены обновления продлевают их на семь дней. ИИ-ассистенты подключаются так же (MCP).
products:readscope- Чтение импортов, товаров, вариантов и правил синхронизации.
products:writescope- Импорт, редактирование, отправка и удаление товаров; изменение правил синхронизации.
inventory:readscope- Чтение уровней запасов.
orders:readscope- Чтение заказов, заказов на выполнение и отправлений.
orders:writescope- Создание, удержание, освобождение и отмена заказов. Расходует ваш баланс.
balance:readscope- Чтение баланса и его транзакций.
webhooks:writescope- Управление эндпоинтами вебхуков.
Запрос вне областей доступа ключа получает ответ 403 insufficient-scope с названием нужной области.
Authorization: Bearer nb_7Qk2...vX9eHTTP/2 401
{
"type": "https://www.ninjabuy.com/api/v1/problems/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "The API key is missing, wrong, expired or revoked.",
"request_id": "req_7Hq2Lw9c"
}Версионирование
Путь содержит основную версию, /v1. Внутри неё версии с датами меняют поля и поведение. Закрепите ту, под которую вы разрабатывали, заголовком NinjaBuy-Version; каждый ответ называет использованную версию в том же заголовке.
2026-11 — текущая версия, и это предварительная версия: названия и поля ещё могут измениться, пока она не помечена как стабильная. Все изменения — в журнале изменений, а перед изменением, которое может что-то сломать, мы пишем на почту каждому владельцу ключа.
Внутри версии мы только добавляем: новые маршруты, новые необязательные параметры, новые поля в ответах и новые типы событий. Стройте клиент так, чтобы он игнорировал незнакомые поля.
GET /api/v1/orders
NinjaBuy-Version: 2026-11
HTTP/2 200
NinjaBuy-Version: 2026-11Запросы и ответы
- Отправляйте JSON с
Content-Type: application/json; ответы — JSON в UTF-8. Ошибки —application/problem+json. - Деньги — это объект с десятичной строкой и валютой:
{ "amount": "264.20", "currency": "CNY" }. Суммы NinjaBuy указаны в CN¥; ваши цены продажи — в валюте вашего магазина. - ID — это строки с префиксом, обозначающим их тип (
prd_,ord_,shp_). Считайте их непрозрачными. - Время — ISO 8601 в UTC. Страны — двухбуквенные коды ISO.
- Каждый ответ содержит заголовок
X-Request-Id, а каждая ошибка — тот же id вrequest_id. Указывайте его, когда пишете нам.
{
"id": "ord_3n7q",
"created_at": "2026-11-01T09:14:02Z",
"total": { "amount": "264.20", "currency": "CNY" },
"suggested_price": { "amount": "49.99", "currency": "USD" }
}Пагинация
Списки возвращаются от новых к старым как data, has_more и cursor. Отправляйте этот cursor обратно за следующей страницей, пока has_more равно true. Cursor работает только с теми фильтрами, с которыми получен.
limitinteger- От 1 до 100. По умолчанию 25.
cursorstring- cursor предыдущей страницы. Для первой страницы не указывайте.
curl "https://www.ninjabuy.com/api/v1/orders?limit=25&cursor=c_2v9kq" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"HTTP/2 200 OK
{
"data": [
{ "id": "ord_3n7q", "status": "checked" },
{ "id": "ord_3n6z", "status": "shipped" }
],
"has_more": true,
"cursor": "c_1q4ea"
}Лимиты запросов
Лимиты действуют на аккаунт и общие для всех его ключей, OAuth-токенов и MCP-подключения. Каждый ответ сообщает ваше положение в заголовках IETF RateLimit-Policy и RateLimit; отказ — это 429 rate-limited с Retry-After в секундах.
| Период | Что учитывается |
|---|---|
| "create-links";q=30;w=60 | Запросы, читающие карточку с маркетплейса: создание или обновление импорта, отправка товара. 30 в минуту, общий лимит с API ссылок и MCP. |
| "default";q=120;w=60 | Все остальные запросы. 120 в минуту. |
HTTP/2 429
Content-Type: application/problem+json
Retry-After: 12
RateLimit-Policy: "create-links";q=30;w=60
RateLimit: "create-links";r=0;t=12
{
"type": "https://www.ninjabuy.com/api/v1/problems/rate-limited",
"title": "Too many requests",
"status": 429,
"detail": "Try again in 12 seconds.",
"request_id": "req_7Hq2Lw9c"
}Идемпотентность
Передавайте Idempotency-Key (от 1 до 255 печатных символов ASCII; идеально — UUID) в любом POST, и повтор после тайм-аута не создаст второй заказ. В течение 24 часов тот же ключ на том же маршруте с тем же телом возвращает первый ответ байт в байт, с Idempotent-Replayed: true, без повторного выполнения и без учёта в лимите.
- Тот же ключ с другим телом или маршрутом:
422 idempotency-key-reused. - Первый запрос ещё выполняется:
409 idempotency-key-in-progressсRetry-After. - Отказ из-за лимита запросов — не ответ: ключ остаётся свободным, поэтому повтор после
Retry-Afterвыполнит запрос.
Заказы также несут ваш собственный external_id: второй заказ с тем же значением отклоняется с 409 duplicate-order, каким бы ключом он ни был отправлен.
POST /api/v1/orders
Idempotency-Key: 4f0c2b4e-9d1a-4e0f-b0a8-5d1d3c7e2f61
HTTP/2 201
Idempotent-Replayed: true
X-Request-Id: req_7Hq2Lw9cОшибки
Ошибки возвращаются в формате problem JSON (RFC 9457): type — стабильный URL для ветвления, title называет ошибку, detail объясняет этот случай словами, которые можно показать, а request_id позволяет найти его в наших логах. Тело, не прошедшее валидацию, добавляет errors, каждый с JSON-pointer на поле.
| Статус | Тип | Когда |
|---|---|---|
| 400 | bad-json | Тело не является JSON. |
| 400 | bad-body | Поле отсутствует или заполнено неверно; errors[] указывает на него. |
| 400 | bad-idempotency-key | Idempotency-Key пустой, слишком длинный или содержит непечатаемые символы ASCII. |
| 401 | unauthorized | Ключ или токен отсутствует, неверен, истёк или отозван. |
| 403 | insufficient-scope | У ключа нет области доступа, нужной маршруту. |
| 404 | not-found | В этом аккаунте нет такого объекта. ID другого аккаунта дают тот же ответ. |
| 405 | method-not-allowed | Маршрут существует, но не с этим методом; Allow перечисляет допустимые. |
| 409 | duplicate-order | Заказ с этим external_id уже существует; order указывает на него. |
| 409 | idempotency-key-in-progress | Первый запрос с этим ключом ещё выполняется. |
| 409 | invalid-state | Объект не может сделать это сейчас, например отменить отправленный заказ. |
| 415 | unsupported-media-type | Тело не в формате application/json. |
| 422 | idempotency-key-reused | Ключ использовался для другого запроса. |
| 422 | unprocessable | Корректный JSON, с которым мы не можем ничего сделать: непрочитанная ссылка, распроданный вариант. detail указывает, что именно. |
| 429 | rate-limited | Слишком много запросов за период. Подождите Retry-After секунд. |
| 500 | internal-error | Ошибка на нашей стороне. Повторите с тем же Idempotency-Key. |
| 503 | service-unavailable | Сейчас мы не смогли проверить ключ или связаться с магазином. Повторите после Retry-After. |
HTTP/2 400
{
"type": "https://www.ninjabuy.com/api/v1/problems/bad-body",
"title": "Invalid request body",
"status": 400,
"detail": "1 field is invalid.",
"request_id": "req_7Hq2Lw9c",
"errors": [
{
"pointer": "/ship_to/country",
"detail": "Must be a two-letter country code."
}
]
}