Desarrolladores2026-11Vista previa

API de NinjaBuy Business

Importa productos de Taobao, Weidian y 1688, mantén sincronizados su precio y stock, y sigue cada pedido desde el vendedor en China, pasando por la revisión en nuestro almacén, hasta la puerta de tu cliente. JSON sobre HTTPS, una cuenta, un saldo.

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).

Catálogo
Pedidos
Cuenta
Tu primera llamada
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.

Encabezado
Authorization: Bearer nb_7Qk2...vX9e
Response 401
HTTP/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.

Fijar una versión
GET /api/v1/orders
NinjaBuy-Version: 2026-11

HTTP/2 200
NinjaBuy-Version: 2026-11

Solicitudes y respuestas

  • Envía JSON con Content-Type: application/json; las respuestas son JSON en UTF-8. Los errores son application/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 como request_id. Cítalo cuando nos escribas.
Dinero, ids y fechas
{
  "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"
Response 200
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.

VentanaQué cuenta
"create-links";q=30;w=60Llamadas 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=60Todas las demás llamadas. 120 por minuto.
Respuesta 429
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, con Retry-After.
  • Un rechazo por límite de tasa no es una respuesta: la clave sigue libre, así que reintentar tras Retry-After ejecuta 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ó.

Una solicitud reintentada
POST /api/v1/orders
Idempotency-Key: 4f0c2b4e-9d1a-4e0f-b0a8-5d1d3c7e2f61

HTTP/2 201
Idempotent-Replayed: true
X-Request-Id: req_7Hq2Lw9c

Errores

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.

EstadoTipoCuándo
400bad-jsonEl cuerpo no es JSON.
400bad-bodyFalta un campo o es incorrecto; errors[] lo señala.
400bad-idempotency-keyLa Idempotency-Key está vacía, es demasiado larga o no es ASCII imprimible.
401unauthorizedLa clave o el token falta, es incorrecto, caducó o fue revocado.
403insufficient-scopeA la clave le falta el alcance que necesita la ruta.
404not-foundNo existe ese objeto en esta cuenta. Los ids de otra cuenta responden lo mismo.
405method-not-allowedLa ruta existe, pero no con este método; Allow indica los que acepta.
409duplicate-orderYa existe un pedido con este external_id; order lo indica.
409idempotency-key-in-progressLa primera solicitud con esta clave sigue en ejecución.
409invalid-stateEl objeto no puede hacer eso ahora, por ejemplo cancelar un pedido enviado.
415unsupported-media-typeEl cuerpo no es application/json.
422idempotency-key-reusedLa clave se usó para otra solicitud.
422unprocessableJSON válido sobre el que no podemos actuar: un enlace no leído, una variante agotada. detail indica cuál.
429rate-limitedDemasiadas llamadas en la ventana. Espera Retry-After segundos.
500internal-errorError nuestro. Reintenta con la misma Idempotency-Key.
503service-unavailableNo pudimos comprobar la clave ni conectar con una tienda en este momento. Reintenta tras Retry-After.
Response 400
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."
    }
  ]
}