API de NinjaBuy Business
URL base
Todas las rutas de este sitio están bajo una URL base. La app de Shopify y todo lo que desarrolles llaman a las mismas rutas, así que lo que hace la app, tu código también puede hacerlo.
https://www.ninjabuy.com/api/v1
¿Prefieres preguntarle a un asistente de IA? La misma cuenta funciona por MCP en https://www.ninjabuy.com/mcp: Asistentes de IA (MCP).
- ImportacionesEntra un enlace, sale el costo total de venderlo.
- ProductosLo que vendes, y dónde está publicado.
- VariantesCada opción, ligada al SKU del vendedor.
- Niveles de inventarioLo que puedes vender ahora mismo.
- Reglas de sincronizaciónQué pasa cuando un vendedor cambia un precio.
- PedidosUna venta que compramos, revisamos y enviamos.
- Órdenes de preparaciónLas líneas que salen en un paquete.
- EnvíosPaquetes en camino, con seguimiento.
- SaldoEl dinero con el que se pagan los pedidos.
- Endpoints de webhookAdónde enviamos los eventos.
curl "https://www.ninjabuy.com/api/v1/balance" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"Autenticación
Envía una clave de API como token bearer en cada solicitud. Las claves empiezan por nb_. Durante la vista previa las emite nuestro equipo: una vez configurada tu cuenta Business, te enviamos cada clave una sola vez, por el canal que elijas, con los alcances que pediste. Pídenos revocar una y deja de funcionar en la siguiente solicitud.
Guarda las claves en tu servidor. Una clave en un navegador, una app o un repositorio público la puede leer cualquiera, y puede gastar tu saldo.
Una app que actúa en nombre de otros vendedores de NinjaBuy usa OAuth 2.1: registro dinámico de clientes, el flujo de código de autorización con PKCE (S256) y la propia pantalla de aprobación del vendedor. Su token de acceso va en el mismo encabezado y funciona en las mismas rutas. Los tokens de acceso duran una hora; los tokens de actualización los renuevan durante siete días. Los asistentes de IA se conectan igual (MCP).
products:readalcance- Leer importaciones, productos, variantes y reglas de sincronización.
products:writealcance- Importa, edita, envía y elimina productos; cambia las reglas de sincronización.
inventory:readalcance- Leer niveles de inventario.
orders:readalcance- Leer pedidos, órdenes de preparación y envíos.
orders:writealcance- Crea, retén, libera y cancela pedidos. Usa tu saldo.
balance:readalcance- Leer el saldo y sus transacciones.
webhooks:writealcance- Gestiona endpoints de webhook.
Una llamada fuera de los alcances de una clave responde 403 insufficient-scope e indica el alcance que necesita.
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"
}Versiones
La ruta lleva la versión principal, /v1. Dentro de ella, las versiones con fecha cambian campos y comportamiento. Fija aquella con la que desarrollaste mediante el encabezado NinjaBuy-Version; cada respuesta indica la versión que usó en el mismo encabezado.
2026-11 es la versión actual y está en vista previa: los nombres y campos aún pueden cambiar antes de marcarse como estable. Cada cambio está en el registro de cambios, y avisamos por correo a cada titular de una clave antes de un cambio que pueda afectarle.
Dentro de una versión solo agregamos: nuevas rutas, nuevos parámetros opcionales, nuevos campos en las respuestas y nuevos tipos de evento. Construye tu cliente para que ignore los campos que no conoce.
GET /api/v1/orders
NinjaBuy-Version: 2026-11
HTTP/2 200
NinjaBuy-Version: 2026-11Solicitudes y respuestas
- Envía JSON con
Content-Type: application/json; las respuestas son JSON en UTF-8. Los errores sonapplication/problem+json. - El dinero es un objeto con una cadena decimal y una moneda:
{ "amount": "264.20", "currency": "CNY" }. Lo que cobra NinjaBuy está en CN¥; tus precios de venta están en la moneda de tu tienda. - Los ids son cadenas con un prefijo que indica su tipo (
prd_,ord_,shp_). Trátalos como opacos. - Las horas son ISO 8601 en UTC. Los países son códigos ISO de dos letras.
- Cada respuesta lleva un encabezado
X-Request-Id, y cada error lleva el mismo id comorequest_id. Cítalo cuando nos escribas.
{
"id": "ord_3n7q",
"created_at": "2026-11-01T09:14:02Z",
"total": { "amount": "264.20", "currency": "CNY" },
"suggested_price": { "amount": "49.99", "currency": "USD" }
}Paginación
Las listas responden de lo más reciente a lo más antiguo, como data, has_more y cursor. Devuelve ese cursor para obtener la página siguiente mientras has_more sea true. Un cursor solo funciona con los filtros de los que salió.
limitinteger- De 1 a 100. 25 si se omite.
cursorstring- El cursor de la página anterior. Omítelo en la primera 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"
}Límites de tasa
Los límites son por cuenta, compartidos por todas sus claves, tokens OAuth y su conexión MCP. Cada respuesta indica en qué punto estás con los encabezados IETF RateLimit-Policy y RateLimit; un rechazo es 429 rate-limited con Retry-After en segundos.
| Ventana | Qué cuenta |
|---|---|
| "create-links";q=30;w=60 | Llamadas que leen una publicación del marketplace: crear o actualizar una importación, enviar un producto. 30 por minuto, compartidas con la API de enlaces y MCP. |
| "default";q=120;w=60 | Todas las demás llamadas. 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"
}Idempotencia
Envía una Idempotency-Key (de 1 a 255 caracteres ASCII imprimibles; un UUID es ideal) en cualquier POST, y un reintento tras un tiempo de espera agotado no puede crear un segundo pedido. Durante 24 horas, la misma clave, en la misma ruta y con el mismo cuerpo, devuelve la primera respuesta otra vez byte a byte, con Idempotent-Replayed: true, sin volver a ejecutarse ni contar para ningún límite.
- La misma clave con otro cuerpo u otra ruta:
422 idempotency-key-reused. - La primera solicitud sigue en ejecución:
409 idempotency-key-in-progress, conRetry-After. - Un rechazo por límite de tasa no es una respuesta: la clave sigue libre, así que reintentar tras
Retry-Afterejecuta la solicitud.
Los pedidos también llevan tu propio external_id: un segundo pedido con el mismo se rechaza con 409 duplicate-order, sea cual sea la clave con la que se envió.
POST /api/v1/orders
Idempotency-Key: 4f0c2b4e-9d1a-4e0f-b0a8-5d1d3c7e2f61
HTTP/2 201
Idempotent-Replayed: true
X-Request-Id: req_7Hq2Lw9cErrores
Los errores son problem JSON (RFC 9457): type es una URL estable para ramificar, title lo nombra, detail explica este caso con palabras que puedes mostrar, y request_id lo encuentra en nuestros registros. Un cuerpo que no pasa la validación agrega errors, cada uno con un pointer JSON al campo.
| Estado | Tipo | Cuándo |
|---|---|---|
| 400 | bad-json | El cuerpo no es JSON. |
| 400 | bad-body | Falta un campo o es incorrecto; errors[] lo señala. |
| 400 | bad-idempotency-key | La Idempotency-Key está vacía, es demasiado larga o no es ASCII imprimible. |
| 401 | unauthorized | La clave o el token falta, es incorrecto, caducó o fue revocado. |
| 403 | insufficient-scope | A la clave le falta el alcance que necesita la ruta. |
| 404 | not-found | No existe ese objeto en esta cuenta. Los ids de otra cuenta responden lo mismo. |
| 405 | method-not-allowed | La ruta existe, pero no con este método; Allow indica los que acepta. |
| 409 | duplicate-order | Ya existe un pedido con este external_id; order lo indica. |
| 409 | idempotency-key-in-progress | La primera solicitud con esta clave sigue en ejecución. |
| 409 | invalid-state | El objeto no puede hacer eso ahora, por ejemplo cancelar un pedido enviado. |
| 415 | unsupported-media-type | El cuerpo no es application/json. |
| 422 | idempotency-key-reused | La clave se usó para otra solicitud. |
| 422 | unprocessable | JSON válido sobre el que no podemos actuar: un enlace no leído, una variante agotada. detail indica cuál. |
| 429 | rate-limited | Demasiadas llamadas en la ventana. Espera Retry-After segundos. |
| 500 | internal-error | Error nuestro. Reintenta con la misma Idempotency-Key. |
| 503 | service-unavailable | No pudimos comprobar la clave ni conectar con una tienda en este momento. Reintenta tras 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."
}
]
}