Skip to main content
La API pública de Commercy es una API REST en JSON. Todos los ejemplos de esta página usan la versión 2026-10.

Versionado

La versión va en la URL y es una fecha (2026-10). Una versión nueva se publica como otro prefijo, sin romper la anterior, y cada versión se mantiene al menos 12 meses después de que sale la siguiente. Una versión inexistente responde 404 not_found.

Convenciones

  • Los nombres de campo son snake_case.
  • Los ids son strings.
  • Los montos son números en pesos argentinos y los recursos con importes traen "currency": "ARS".
  • Las fechas son ISO 8601 en UTC, por ejemplo 2026-10-09T12:00:00.000Z.
  • Los campos sin valor vienen como null. Los campos de costo sólo aparecen si tu app tiene el scope read_costs.
  • Los parámetros y campos desconocidos se rechazan con 400 invalid_request (no se ignoran en silencio), para que no creas que aplicó un filtro que no existe.
  • Todas las respuestas traen el header X-Request-Id; mandalo a soporte si necesitás ayuda con un request puntual.
  • Un recurso de otro comercio responde 404 not_found, igual que uno que no existe. Nunca confirmamos que existe.

Respuestas

Un recurso:
Una colección:
Los errores tienen su propio formato, descripto en Errores.

Paginación

Las colecciones se paginan con cursor. Parámetros: Mientras next_cursor no sea null, hay más páginas. El cursor es opaco y está atado a los filtros con los que se pidió: si lo usás con otros filtros recibís 400 invalid_request. Las listas de productos, ventas y clientes se ordenan por fecha de modificación ascendente, así que podés sincronizar de forma incremental guardando la última fecha vista y pidiendo updated_since. updated_since y created_since son fechas ISO 8601 e incluyen el instante indicado (>=).

Idempotencia

Mandá un header Idempotency-Key (1 a 255 caracteres ASCII imprimibles, por ejemplo un UUID) para que un reintento no repita la operación.
  • Es obligatorio en POST /stock/adjustments y opcional en el resto de los POST, PUT y PATCH. DELETE no usa idempotencia.
  • La clave vale 24 horas y se guarda por instalación.
  • Repetir la misma clave con el mismo body devuelve la respuesta original, con el header Idempotent-Replayed: true.
  • La misma clave con otro body responde 422 idempotency_conflict.
  • Si el primer request todavía está en curso (hasta 60 segundos) responde 409 conflict: esperá y reintentá.
  • Las respuestas 5xx no se guardan, así que podés reintentar con la misma clave.

Tienda

GET /store

Sin scope. Datos del comercio donde está instalada la app.
plan_tier es professional, enterprise, demo o developer.

Sucursales

Scope read_shops.

GET /shops y GET /shops/:id

La sucursal que no pertenece al comercio responde 404.

Categorías y marcas

Scope read_products. GET /categories y GET /brands aceptan limit y cursor.
Las marcas traen id, name, slug, is_active, image y updated_at.

Productos

Scope read_products.

GET /products

No se listan los productos en borrador. Un category o brand que no es del comercio responde 404.

GET /products/:id

Devuelve un producto con sus variantes.
price es el precio base. Para el precio que realmente paga un cliente en una sucursal y lista de precios usá GET /prices. Con el scope read_costs el producto trae además cost, y cada variante su propio cost.

Precios

Scope read_prices.

GET /prices

Precio resuelto de cada producto y variante en una sucursal, con el mismo motor que usa el punto de venta.
price_list_id solo viene informado si el comercio usa listas de precios. source indica de dónde sale el precio resuelto.

Stock

Scope read_stock.

GET /stock

Una fila por producto o, si tiene variantes, por variante.
on_hand es el stock físico y available lo que se puede vender (descontadas las reservas). Nunca se exponen lotes, costos ni proveedores.

Ventas

Scope read_orders. Sólo se listan las ventas del comercio; las compras a proveedores no aparecen.

GET /orders

GET /orders/:id

El :id acepta el id de la venta o su order_number.
Con el scope read_costs cada línea trae además cogs (costo de la mercadería vendida). customer es null si la venta no tiene un comprador identificable.

Clientes

Scope read_customers. Sólo los clientes del comercio: no incluye al equipo ni a los contactos que todavía no son clientes.

GET /customers y GET /customers/:id

document solo viene informado para un DNI. Los datos fiscales (CUIT, CUIL) nunca se exponen.

Escrituras

Todas requieren el scope write_* correspondiente y devuelven el recurso actualizado en el mismo formato que la lectura. Los POST que crean un recurso responden 201.

Productos (write_products)

  • POST /products crea un producto. No acepta precio ni costo (ni en el producto ni en sus variantes): la API responde 400 si los mandás. El producto nace con precio 0 y visibilidad interna; asignale el precio con PUT /prices/:productId y publicalo después con PATCH.
  • PATCH /products/:id edita los datos del producto. En las variantes sólo se editan las existentes (por id); las variantes nuevas se crean únicamente al crear el producto.
  • DELETE /products/:id da de baja el producto. Si tiene reservas vigentes responde 409 conflict con details[0].reason = "has_reservations".

Precios (write_prices)

PUT /prices/:productId es el único camino para cambiar precios. Body:
Cambia el precio base del producto y/o de sus variantes (mayores a 0). Con expected hacés una escritura condicional: si el precio actual no es el esperado responde 409 conflict. En productos con variantes no se acepta price a nivel producto: el precio base se deriva de las variantes.

Stock (write_stock)

POST /stock/adjustments (con Idempotency-Key obligatorio):
Usá delta (entero distinto de 0, suma o resta) o set (cantidad absoluta), nunca los dos. variant es obligatorio si el producto tiene variantes. Si el ajuste dejaría el stock en negativo responde 409 conflict con details[0].reason = "insufficient_stock". Devuelve la fila de stock actualizada.

Ventas (write_orders)

  • POST /orders/:id/status con { "status": "...", "notes": "..." } cambia el estado. Los estados permitidos son confirmed, preparing, shipped y delivered, y tienen que existir en el flujo de estados de la tienda. Nunca se puede cancelar, rechazar ni devolver una venta desde la API. Si la entrega exige confirmar el cobro (por ejemplo un retiro pagado en efectivo), responde 409 conflict con details[0].reason = "payment_confirmation_required": esa confirmación se hace desde Commercy.
  • POST /orders/:id/fulfillment con { "tracking_number": "...", "tracking_url": "..." } carga los datos de seguimiento. Si la venta no tiene datos de envío responde 409 conflict con details[0].reason = "no_shipping".

Clientes (write_customers)

  • POST /customers con name (obligatorio), email, phone, document ({ "type": "DNI", "number": "..." }) y shipping_addresses.
  • PATCH /customers/:id con los mismos campos, todos opcionales. Solo se admite DNI como documento: los datos fiscales no se gestionan por la API.

DELETE /installation

Sin scope. La app se desinstala a sí misma. Responde { "data": { "uninstalled": true } } y el access token deja de valer en el siguiente request.