API da NinjaBuy Business
URL base
Todas as rotas deste site ficam sob uma URL base. O app da Shopify e tudo o que você desenvolve chamam as mesmas rotas, então o que o app faz, o seu código também pode fazer.
https://www.ninjabuy.com/api/v1
Prefere perguntar a um assistente de IA? A mesma conta funciona via MCP em https://www.ninjabuy.com/mcp: Assistentes de IA (MCP).
- ImportaçõesEntra um link, sai o custo total de vendê-lo.
- ProdutosO que você vende, e onde está anunciado.
- VariantesCada opção, ligada ao SKU do vendedor.
- Níveis de estoqueO que você pode vender agora.
- Regras de sincronizaçãoO que acontece quando um vendedor muda um preço.
- PedidosUma venda que compramos, verificamos e enviamos.
- Ordens de processamentoAs linhas que saem em um pacote.
- RemessasPacotes a caminho, com rastreio.
- SaldoO dinheiro com que os pedidos são pagos.
- Endpoints de webhookPara onde enviamos os eventos.
curl "https://www.ninjabuy.com/api/v1/balance" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"Autenticação
Envie uma chave de API como bearer token em toda requisição. As chaves começam com nb_. Durante a prévia, a nossa equipe as emite: depois que a sua conta Business é configurada, enviamos cada chave uma única vez, pelo canal que você escolher, com os escopos que você pediu. Peça para revogarmos uma e ela para de funcionar na próxima requisição.
Guarde as chaves no seu servidor. Uma chave em um navegador, um app ou um repositório público pode ser lida por qualquer pessoa, e pode gastar o seu saldo.
Um app que age em nome de outros vendedores da NinjaBuy usa OAuth 2.1: registro dinâmico de clientes, o fluxo de código de autorização com PKCE (S256) e a própria tela de aprovação do vendedor. O token de acesso vai no mesmo cabeçalho e funciona nas mesmas rotas. Tokens de acesso duram uma hora; tokens de atualização os renovam por sete dias. Assistentes de IA se conectam do mesmo jeito (MCP).
products:readescopo- Ler importações, produtos, variantes e regras de sincronização.
products:writeescopo- Importe, edite, envie e exclua produtos; altere regras de sincronização.
inventory:readescopo- Ler níveis de estoque.
orders:readescopo- Ler pedidos, ordens de processamento e envios.
orders:writeescopo- Crie, retenha, libere e cancele pedidos. Usa o seu saldo.
balance:readescopo- Ler o saldo e as transações.
webhooks:writeescopo- Gerencie endpoints de webhook.
Uma chamada fora dos escopos de uma chave responde 403 insufficient-scope e informa o escopo necessário.
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"
}Versionamento
O caminho traz a versão principal, /v1. Dentro dela, versões com data mudam campos e comportamento. Fixe aquela com que você desenvolveu usando o cabeçalho NinjaBuy-Version; toda resposta informa no mesmo cabeçalho a versão usada.
2026-11 é a versão atual e está em prévia: nomes e campos ainda podem mudar antes de ela ser marcada como estável. Toda mudança está no changelog, e avisamos por e-mail cada titular de chave antes de uma mudança que possa quebrar a integração.
Dentro de uma versão, só adicionamos: novas rotas, novos parâmetros opcionais, novos campos nas respostas e novos tipos de evento. Construa o seu cliente para ignorar campos que ele não conhece.
GET /api/v1/orders
NinjaBuy-Version: 2026-11
HTTP/2 200
NinjaBuy-Version: 2026-11Requisições e respostas
- Envie JSON com
Content-Type: application/json; as respostas são JSON em UTF-8. Os erros sãoapplication/problem+json. - Dinheiro é um objeto com uma string decimal e uma moeda:
{ "amount": "264.20", "currency": "CNY" }. O que a NinjaBuy cobra está em CN¥; os seus preços de venda estão na moeda da sua loja. - Os ids são strings com um prefixo que indica o tipo (
prd_,ord_,shp_). Trate-os como opacos. - Os horários são ISO 8601 em UTC. Os países são códigos ISO de duas letras.
- Toda resposta traz um cabeçalho
X-Request-Id, e todo erro traz o mesmo id comorequest_id. Informe-o quando nos escrever.
{
"id": "ord_3n7q",
"created_at": "2026-11-01T09:14:02Z",
"total": { "amount": "264.20", "currency": "CNY" },
"suggested_price": { "amount": "49.99", "currency": "USD" }
}Paginação
As listas respondem da mais recente para a mais antiga, como data, has_more e cursor. Envie esse cursor de volta para a próxima página enquanto has_more for true. Um cursor só funciona com os filtros de onde veio.
limitinteger- De 1 a 100. 25 se omitido.
cursorstring- O cursor da página anterior. Omita na primeira página.
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"
}Limites de requisições
Os limites são por conta, compartilhados por todas as chaves, tokens OAuth e a conexão MCP. Toda resposta diz onde você está pelos cabeçalhos IETF RateLimit-Policy e RateLimit; uma recusa é 429 rate-limited com Retry-After em segundos.
| Janela | O que conta |
|---|---|
| "create-links";q=30;w=60 | Chamadas que leem um anúncio do marketplace: criar ou atualizar uma importação, enviar um produto. 30 por minuto, compartilhadas com a API de links e o MCP. |
| "default";q=120;w=60 | Todas as outras chamadas. 120 por minuto. |
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"
}Idempotência
Envie uma Idempotency-Key (de 1 a 255 caracteres ASCII imprimíveis; um UUID é o ideal) em qualquer POST, e uma nova tentativa depois de um timeout não consegue criar um segundo pedido. Por 24 horas, a mesma chave, na mesma rota e com o mesmo corpo, devolve a primeira resposta de novo byte a byte, com Idempotent-Replayed: true, sem executar de novo nem contar para um limite.
- A mesma chave com outro corpo ou outra rota:
422 idempotency-key-reused. - A primeira requisição ainda em execução:
409 idempotency-key-in-progress, comRetry-After. - Uma recusa por limite de requisições não é uma resposta: a chave continua livre, então tentar de novo após
Retry-Afterexecuta a requisição.
Os pedidos também levam o seu próprio external_id: um segundo pedido com o mesmo é recusado com 409 duplicate-order, seja qual for a chave usada.
POST /api/v1/orders
Idempotency-Key: 4f0c2b4e-9d1a-4e0f-b0a8-5d1d3c7e2f61
HTTP/2 201
Idempotent-Replayed: true
X-Request-Id: req_7Hq2Lw9cErros
Os erros são problem JSON (RFC 9457): type é uma URL estável para usar em condicionais, title o nomeia, detail explica este caso com palavras que você pode mostrar, e request_id o encontra nos nossos logs. Um corpo que falha na validação adiciona errors, cada um com um pointer JSON para o campo.
| Status | Tipo | Quando |
|---|---|---|
| 400 | bad-json | O corpo não é JSON. |
| 400 | bad-body | Um campo está faltando ou errado; errors[] aponta para ele. |
| 400 | bad-idempotency-key | A Idempotency-Key está vazia, é longa demais ou não é ASCII imprimível. |
| 401 | unauthorized | A chave ou o token está faltando, errado, expirado ou revogado. |
| 403 | insufficient-scope | Falta à chave o escopo que a rota exige. |
| 404 | not-found | Esse objeto não existe nesta conta. Ids de outra conta respondem igual. |
| 405 | method-not-allowed | A rota existe, mas não com este método; Allow lista os que ela aceita. |
| 409 | duplicate-order | Já existe um pedido com este external_id; order o identifica. |
| 409 | idempotency-key-in-progress | A primeira requisição com esta chave ainda está em execução. |
| 409 | invalid-state | O objeto não pode fazer isso agora, por exemplo cancelar um pedido enviado. |
| 415 | unsupported-media-type | O corpo não é application/json. |
| 422 | idempotency-key-reused | A chave foi usada para uma requisição diferente. |
| 422 | unprocessable | JSON válido sobre o qual não conseguimos agir: um link não lido, uma variante esgotada. detail diz qual. |
| 429 | rate-limited | Chamadas demais na janela. Espere Retry-After segundos. |
| 500 | internal-error | Erro nosso. Tente de novo com a mesma Idempotency-Key. |
| 503 | service-unavailable | Não conseguimos verificar a chave ou alcançar uma loja agora. Tente de novo após 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."
}
]
}