pickea

API de Pickea

Si tu tienda no está en Mercado Libre, Tiendanube ni Shopify, la conectás por acá. Consultás cuánto stock tenés, nos mandás las ventas, y te avisamos cuando pasa algo con ellas.

Todo bajo https://app.pickea.com.ar/api/v1. JSON entra y JSON sale.

Autenticación

Una llave por integración, en el header Authorization. La creás desde tu cuenta, en API.

Authorization: Bearer pk_xxxxxxxxxxxxxxxxxxxxxxxx
La llave se muestra una sola vez, cuando la creás. En nuestra base queda su hash, no la llave: no podemos volver a mostrártela ni aunque la pidas. Si la perdés, revocás esa y creás otra — y revocar es inmediato, sirve para cortar el acceso de un sistema que dejaste de usar.

La llave puede crear ventas a tu nombre, así que tratala como una contraseña: en una variable de entorno del servidor, nunca en el código de tu página. Cualquier llamada desde el navegador de un comprador expone la llave a quien abra las herramientas de desarrollo.

Consultar stock

GET/api/v1/stock

Lo que tenés en nuestro galpón, SKU por SKU. Parámetros opcionales: sku (separados por coma) y pagina.

Pedido

curl https://app.pickea.com.ar/api/v1/stock?sku=REM-M,REM-L \
  -H "Authorization: Bearer $PICKEA_API_KEY"

Respuesta

{
  "stock": [
    {
      "sku": "REM-M",
      "nombre": "Remera M",
      "codigoInterno": "2000000001",
      "disponible": 42,
      "reservado": 3,
      "propio": { "PROPIO_VENDEDOR": 10, "MELI_FULL": 5 }
    }
  ],
  "pagina": 1,
  "porPagina": 200,
  "total": 1
}
No devolvemos un total, y es a propósito. Si sumáramos tu stock propio, el que quiere publicar solo lo que está con nosotros publicaría de más. Si no lo sumáramos, el que lo quiere sumado tendría que pedirlo aparte. Con las piezas separadas armás el número que necesitás y, sobre todo, entendés de dónde sale el día que no cierre con lo que ves en tu tienda.
CampoQué es
disponibleLo que se puede vender ya mismo desde nuestro galpón. Es el número que se publica.
reservadoComprometido con una venta que todavía no salió. No se puede vender, pero explica la diferencia con lo que tenés guardado.
propioLo que declaraste que tenés fuera de Pickea, por origen. Vacío si no declaraste nada.

Cargar una venta

POST/api/v1/ordenes

Entra por el mismo camino que una venta cargada a mano: reserva stock al crearse y, si no alcanza, nace frenada en SIN_STOCK y sigue sola cuando entre mercadería. No hay un camino de creación “para la API”.

Pedido

curl -X POST https://app.pickea.com.ar/api/v1/ordenes \
  -H "Authorization: Bearer $PICKEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "claveIdempotencia": "venta-8842",
    "numeroExterno": "#8842",
    "comprador": {
      "nombre": "Ana Gómez",
      "documento": "30111222",
      "email": "ana@ejemplo.com",
      "telefono": "1155667788"
    },
    "envioA": {
      "calle": "Av. Rivadavia",
      "numero": "5400",
      "piso": "3",
      "depto": "B",
      "codigoPostal": "C1424",
      "localidad": "Caballito",
      "provincia": "CABA"
    },
    "lineas": [
      { "sku": "REM-M", "cantidad": 2, "precioUnitarioCentavos": 1899000 }
    ]
  }'

Respuesta · 201

{
  "ordenId": "cm...",
  "numero": "ORD-ACME-000123",
  "estado": "PENDIENTE",
  "diaOperativo": "2026-08-27"
}
claveIdempotencia es obligatoria, y es lo que hace seguro reintentar. Dos POST con la misma clave crean una orden: el segundo devuelve 200 con duplicado: true y la orden que ya existía. Poné el id de la venta en tu sistema. Si no la mandaras, un timeout de red te duplicaría la venta y te reservaría el stock dos veces.
CampoObligatorioDetalle
claveIdempotenciaSíTu id de venta. Hasta 120 caracteres.
lineas[].skuSíEl SKU tal como está en tu catálogo de Pickea.
lineas[].cantidadSíEntero mayor a cero.
lineas[].precioUnitarioCentavosNoCentavos de ARS, entero. Nunca decimales.
numeroExternoNoEl número que ve tu comprador. Aparece en el remito.
compradorNoNombre, documento, email y teléfono.
envioANoOpcional a propósito: una venta ya hecha no se rechaza por un dato que falta. La orden nace sin destino y queda marcada — lo que sí se bloquea es empaquetarla así. Mandalo siempre y el pedido sale solo.
observacionesNoHasta 500 caracteres. Los ve quien prepara el pedido.

El dinero va en centavos, siempre entero. 1899000 son $18.990. Nunca mandes decimales: un 18990.00 en punto flotante pierde centavos, y acá los centavos son plata de verdad.

Errores

Siempre JSON con error. El código dice qué hacer.

CódigoQué pasóQué hacer
401Llave inválida o revocada.No reintentes. Revisá la llave.
409Esa clave de idempotencia se está procesando ahora mismo.Reintentá en unos segundos. La orden se está creando.
422El cuerpo no cumple el contrato, o hay SKU que no están en tu catálogo (vienen en `skus`).No reintentes igual: corregí y volvé a mandar.
429Pasaste el tope por minuto.Esperá lo que dice `retry-after` (en segundos) y reintentá.
5xxSe rompió de nuestro lado.Reintentá con la MISMA clave de idempotencia: es seguro.

422 con SKU desconocidos

{
  "error": "Hay SKU que no están en tu catálogo.",
  "skus": ["REM-XXL"]
}

Webhooks: te avisamos a vos

Configurás una URL y te mandamos un POST cuando pasa algo con tus pedidos. Así no tenés que preguntar cada cinco minutos si ya salió.

Lo que te llega

POST https://tu-sistema.com/hook
x-pickea-evento: orden.despachada
x-pickea-fecha: 2026-08-27T14:03:11.000Z
x-pickea-firma: 9f2c...
x-pickea-entrega: cm...
Content-Type: application/json

{ "titulo": "Tu pedido salió", "cuerpo": "...", "ordenId": "cm..." }

Verificá la firma antes de hacerle caso a un aviso. Es un HMAC-SHA256 sobre {fecha}.{cuerpo crudo} con el secreto que te damos al configurar el webhook. La fecha entra en la firma para que una entrega vieja capturada no se pueda reenviar como si fuera de ahora.

Verificarla (Node)

import { createHmac, timingSafeEqual } from "node:crypto";

function firmaValida(fecha, cuerpoCrudo, firmaRecibida, secreto) {
  const esperada = createHmac("sha256", secreto)
    .update(`${fecha}.${cuerpoCrudo}`, "utf8")
    .digest("hex");
  const a = Buffer.from(esperada, "utf8");
  const b = Buffer.from(firmaRecibida.trim(), "utf8");
  // Comparación en tiempo constante: con === se puede adivinar byte a byte.
  return a.length === b.length && timingSafeEqual(a, b);
}
Firmá sobre el cuerpo crudo, tal como llegó. Si parseás el JSON y lo volvés a serializar, el orden de las claves o un espacio cambian los bytes y la firma no da nunca.

Contestá 2xx apenas lo recibas y hacé el trabajo después. Si contestás 4xx no reintentamos —damos por hecho que lo rechazaste—; ante un 5xx o un timeout reintentamos a los 1, 5, 15, 60 y 180 minutos, y después lo dejamos. Usá x-pickea-entrega como clave de idempotencia: un reintento nuestro trae el mismo id.

Eventos

EventoCuándo
asn.recibidoTerminamos de recibir un envío tuyo. Si hubo diferencias, vienen en el detalle.
cuenta.aviso_moraTenés una liquidación vencida. A los 14 días se frenan los despachos.
cuenta.bloqueo_moraSe frenaron los despachos por mora. Se destraba solo al acreditarse lo vencido.
devolucion.recibidaLlegó una devolución. Todavía no vuelve a stock: primero se inspecciona.
liquidacion.emitidaSe cerró la semana y tenés una liquidación nueva, con su vencimiento.
orden.cortadaFaltó mercadería al prepararla y sale incompleta. Avisale al comprador antes que él te reclame.
orden.despachadaSalió del galpón. Trae el transportista y el seguimiento si el envío ya lo tiene.
orden.no_entregadaEl transportista no pudo entregarla.
orden.repuestaEntró stock y una orden frenada consiguió reserva. Ya va a preparación.
orden.sin_stockLa venta entró pero no alcanzó el stock. Queda frenada y sigue sola cuando entre mercadería.
pago.acreditadoVimos tu transferencia y se imputó.
pago.rechazadoNo pudimos conciliar un pago informado. Viene el motivo.
sistema.avisoUn aviso nuestro que no entra en las categorías de arriba.
stock.bajoUn SKU bajó del mínimo que configuraste.

Límites

QuéCuánto
Llamadas por minuto60, por llave
SKU por respuesta de stock200 (paginado con `pagina`)
Líneas por ordenSin tope práctico; un SKU no se puede repetir en la misma venta

El tope es por llave y no por vendedor: una integración desbocada no te frena las otras. Si tenés varios sistemas conectados, dale una llave a cada uno.