NexoPOS
Documentación de la API

Conectá tu sistema con NexoPOS

Si el comercio usa un ERP, Odoo o un sistema propio, puede dar de alta sus productos de a miles, leer su catálogo, escribir precios y stock, y leer lo que se vendió en el mostrador — sin que nadie tenga que cargar nada a mano en la pantalla del POS.

Empezar

Tres pasos. El primero lo hace el comerciante; los otros dos, quien programe.

  1. El comerciante genera una clave en NexoPOS → Configuración → Conectar tu sistema. Le pone un nombre para saber cuál es y la copia. Se muestra una sola vez.
  2. Probá que llega. Si esto devuelve tus productos, está todo bien:
curl -s "https://nexopos.app/api/erp/v1/productos" \
  -H "Authorization: Bearer npos_TU_CLAVE"
  1. Escribí un precio y miralo en el POS. Con eso ya sabés que el circuito completo funciona.
curl -s -X PUT "https://nexopos.app/api/erp/v1/precios" \
  -H "Authorization: Bearer npos_TU_CLAVE" \
  -H "Content-Type: application/json" \
  -d '{"precios":[{"ean":"7798042240180","precio_centavos":5200000}]}'

Base de todas las llamadas: https://nexopos.app/api/erp/v1

La clave

Authorization: Bearer npos_xxxxxxxxxxxxxxxxxxxxxxxx

Es de un comercio: abre ese y ninguno más. Si se filtra, el alcance del daño es ese negocio y no la plataforma.

Se muestra una sola vez. De nuestra base sale solo un hash, así que no hay forma de recuperarla — ni nosotros podemos. Si se pierde, el comerciante genera otra y revoca la anterior.

Es incómodo a propósito. Una clave que se puede recuperar es una clave que alguien puede ir a buscar a un backup, a un dump o a una consulta de soporte.

El comerciante ve cuándo se usó cada clave por última vez y puede revocarla cuando quiera. Revocada, la siguiente llamada devuelve 401.

Convenciones

Los importes van en centavos, enteros

$52.000 es 5200000. Nunca decimales: un float arrastrando medio centavo por 3000 productos termina en una diferencia que después nadie encuentra.

Cómo se identifica un producto

Cada línea que escribís lleva una de estas tres:

eanEl código de barras. Es lo normal.
skuEl código de balanza, si el comercio lo usa.
idEl id de NexoPOS, que sale de GET /productos.

Si un EAN aparece en dos productos del mismo comercio, esa línea no se aplica y vuelve en no_encontrados. No adivinamos cuál era.

Nada se cachea

El stock cambia con cada venta del mostrador. Un catálogo de hace cinco minutos vende lo que ya no está.

Leer el catálogo

GET /productos

Todo lo que el comercio tiene, paginado de a 500.

{
  "productos": [{
    "id": "184",
    "ean": "7798042240180",
    "sku": null,
    "nombre": "Silla Plástica Voss 2000 — unidad",
    "unidad": "unidad",
    "precio_centavos": 5200000,
    "costo_centavos": 3000000,
    "stock": 17,
    "stock_minimo": 0,
    "es_insumo": false,
    "publicado_en_tienda": true,
    "actualizado": "2026-09-15T03:28:00.000Z"
  }],
  "page": 1, "pageSize": 500, "total": 3
}

precio_centavos: null es un producto sin precio de venta: no se puede cobrar en el mostrador ni aparece en la tienda online hasta que tenga uno. Es lo que pasa, por ejemplo, con un catálogo recién importado.

Dar de alta productos

POST /productos

Hasta 5000 por llamada. Es lo mismo que subir un CSV desde NexoPOS (Productos → Integración API): los dos usan el mismo motor y terminan igual.

{
  "productos": [
    { "ean": "7790070507341", "precio_centavos": 399900, "costo_centavos": 199950,
      "stock": 12, "stock_minimo": 2 },
    { "nombre": "Tarta de verdura", "precio_centavos": 550000, "stock": 4 }
  ]
}

Cada producto termina en una de estas cosas:

  • Ya lo tenés (mismo EAN; sin EAN, mismo nombre): se le cambian precio, costo y stock.
  • Está en el catálogo de Nexo B2B: entra con su ficha —nombre, foto, rubro—. El nombre que mandes no se usa.
  • No está en ningún lado: se crea como producto propio del comercio con el nombre que mandaste, sin foto.
  • Error: un EAN que no está en Nexo B2B y sin nombre, un número que no se entiende, o el mismo producto dos veces en la misma llamada.

Hace falta ean o nombre; lo demás es opcional, y lo que no mandes no se borra: queda lo que había. El stock reemplaza (es la carga inicial: lo que hay), así que mandar lo mismo dos veces no duplica nada. Para el día a día, usá PUT /stock con ajuste.

precio_centavos es el precio de venta y nunca se calcula: sin él, el producto se carga pero no se vende ni sale en la tienda online.

Contesta enseguida y sigue en segundo plano

Buscar miles de fichas en Nexo B2B tarda unos minutos, más de lo que una conexión aguanta abierta. Por eso la respuesta es un 202 con un número:

{ "importacion_id": "41", "estado": "analizando" }

GET /importaciones/:id

{
  "importacion_id": "41",
  "estado": "aplicada",
  "total": 2000, "procesadas": 2000,
  "resumen": { "actualizar": 3, "vincular": 0, "crear_b2b": 1850,
               "crear_propio": 120, "error": 27, "sinPrecio": 0 },
  "error": null,
  "errores": [ { "fila": 14, "ean": "7799999999998", "nombre": "",
                 "motivo": "El EAN 7799999999998 no está en el catálogo de NexoB2B y la fila no tiene nombre para darlo de alta como propio." } ]
}

Preguntá cada unos segundos hasta que estado sea aplicada o error. Antes de eso no se escribió nada, y se aplica todo junto: no hay importaciones a medias. Las filas con error se saltean y vienen en errores, con el número de fila (la posición en tu lista, empezando en 1).

Escribir precios

PUT /precios

Hasta 1000 por llamada.

{
  "precios": [
    { "ean": "7798042240180", "precio_centavos": 5200000, "costo_centavos": 3000000 }
  ]
}
{ "aplicados": 1, "no_encontrados": [] }

El costo es opcional: si no va, queda el que estaba. El precio de venta es el único número que tu sistema puede pisar sin pensarlo, porque no hay nadie más escribiéndolo. Con el stock no pasa lo mismo.

Escribir stock

PUT /stock

{
  "modo": "ajuste",
  "stock": [ { "ean": "7798042240180", "cantidad": 5 } ]
}
modoQué hace
ajuste defaultSuma o resta. -2 saca dos.
absolutoDeja el stock en ese número.

Elegir mal acá cuesta plata. Mirá el ejemplo.

Tu sistema sincroniza a las 14:00 y ve 12 unidades. A las 14:30 el cajero vende 3 y quedan 9. A las 15:00 volvés a sincronizar con el número que vos tenés:

absoluto → «dejalo en 12»el stock vuelve a 12
ajuste → «sumá 0»el stock queda en 9

Con absoluto reaparecieron tres unidades que ya no están. El mostrador las va a vender de nuevo y no van a estar en el depósito. Con ajuste eso no puede pasar, porque no reescribe: acumula sobre lo que haya.

Cuándo usar cada uno

  • ajuste para el día a día. Entró mercadería, sumás lo que entró. Es el único seguro cuando el mostrador también vende.
  • absoluto solo cuando tu número es la verdad completa: justo después de un inventario físico, o si el POS no vende nada de ese producto.

Y si tu sistema quiere llevar el stock él mismo, tiene que leer las ventas del mostrador. La venta del cajero no pasa por tu ERP: pasa por acá.

Cada escritura deja un movimiento de tipo erp con lo que cambió, no con lo que quedó, así la suma de los movimientos sigue dando el stock.

Leer las ventas

GET /ventas?desde=

curl -s "https://nexopos.app/api/erp/v1/ventas?desde=2026-09-15T00:00:00Z" \
  -H "Authorization: Bearer npos_TU_CLAVE"
{
  "ventas": [{
    "id": "1", "ticket": 1,
    "fecha": "2026-09-15T03:28:32.005Z",
    "total_centavos": 10400000,
    "medio_pago": "cash",
    "es_reembolso": false,
    "lineas": [{
      "producto_id": 184, "ean": "7798042240180", "sku": null,
      "nombre": "Silla Plástica Voss 2000 — unidad",
      "cantidad": "2.000", "precio_centavos": 5200000
    }]
  }],
  "hasta": "2026-09-15T03:28:32.005Z",
  "hay_mas": false
}

Cómo paginar

Guardá el hasta y mandalo como desde en la próxima llamada. Mientras hay_mas sea true, seguí pidiendo.

Incluye los pedidos de la tienda online entregados, porque terminan como nota de venta igual que una venta del mostrador. Un reembolso viene con es_reembolso: true y cantidades negativas: es una venta al revés, no un registro aparte que haya que interpretar.

Errores

401Clave ausente, inválida o revocada.
400Faltan datos, o el cuerpo no tiene la forma esperada.
409La operación choca con el estado actual.

El cuerpo trae { "error": "…" } con un mensaje escrito para leerse: dice qué falta. Si lo vas a mostrar en tu sistema, mostralo tal cual — está pensado para que lo entienda quien tiene que arreglarlo.

Lo que todavía no hay

Lo decimos para que no lo busques: no está, no es que lo estés haciendo mal.

  • Webhooks hacia tu sistema. Hoy tenés que preguntar por /ventas.

Si lo necesitás, escribinos: es el paso siguiente natural y saber que hace falta cambia el orden.