Ojito API

Historial diario de precios de Coto (sucursal 200 y excepciones por sucursal). Es la API de la extensión Ojito: el uso automatizado fuera de la extensión, la extracción masiva y la redistribución no están permitidos.

Autenticación

Las rutas de productos, /v1/events y /v1/feedback piden el header X-Install-Token. El token sale de POST /v1/installs (uno por instalación de la extensión).

Cada token y cada IP tienen un tope de productos distintos por día. Al pasarlo, 429 con Retry-After hasta la medianoche (hora argentina).

Recursos

RutaQué devuelve
GET /v1/storesLos súper, con la fecha de la última captura.
GET /v1/products?store=coto&sku=…Hasta 100 productos por SKU (o ean=…), con su último precio. Sin filtro: 400.
GET /v1/products/{id}Un producto. El id es coto- + el SKU de 8 dígitos.
GET /v1/products/{id}/pricesLa serie diaria (por defecto, los últimos 30 días).
GET /v1/products/{id}/prices/{fecha}Un día (YYYY-MM-DD).
POST /v1/installs201 con { installId, token }.
POST /v1/eventsLos contadores del día: { version, counters: { evento: cantidad } }. Uno por día.
POST /v1/feedbackUn comentario: { text, version, site }. Es anónimo.
GET /healthQue la API responde.

Parámetros de precio

Parámetro
branch=078Los precios como se cobran en esa sucursal. Sin él, la 200. Lo que se vende por peso queda con la 200 (priceBranch lo dice).
member=trueeffectivePrice con el precio de socio de la Comunidad Coto si es más barato.
from, toFechas YYYY-MM-DD, como mucho 30 días.
include=pricesEn /products: la serie de cada producto.
fields=sku,pricesSólo esos campos de cada producto.

Un día de la serie

{
  "date": "2026-11-06",
  "listPrice": 4300,
  "price": 2795,
  "promo": null,
  "community": { "price": 2150, "label": "+15%" },
  "effectivePrice": 2150
}

price es llevando una unidad, con los descuentos directos. promo es una promo por cantidad ({ price, minQuantity, label }), con el precio por unidad. effectivePrice es lo que se paga: la promo si hay, el de socio si member=true y es más barato. Los días sin dato no aparecen.

Errores

{ "developerMessage": "…", "userMessage": "…", "errorCode": "product_not_found",
  "moreInfo": "https://api.ojito.com.ar/docs#product_not_found" }
CódigoHTTPQué pasó
invalid_branch400branch no es un número de sucursal.
invalid_member400member no es true ni false.
invalid_date400Una fecha no es YYYY-MM-DD válida.
invalid_range400from es posterior a to.
range_too_long400Más de 30 días.
invalid_include400include sólo acepta prices.
invalid_fields400Un campo de fields no existe.
missing_store400Falta store.
missing_filter400Falta sku o ean (o vinieron los dos).
invalid_sku400sku no es una lista de 1 a 100 SKU.
invalid_ean400ean no es una lista de 1 a 100 EAN.
invalid_body400El cuerpo no es el JSON esperado.
unknown_event400Un evento que no está en la lista.
invalid_count400Una cantidad fuera de rango.
missing_token401Falta X-Install-Token.
invalid_token401El token no es válido o fue revocado.
not_found404La ruta no existe.
store_not_found404El súper no existe.
product_not_found404No tenemos ese producto.
price_not_found404El producto no tiene precio ese día.
method_not_allowed405El método no va en esa ruta (ver Allow).
payload_too_large413El cuerpo pasa de 16 KB.
rate_limited429Tope de productos distintos del día.
too_many_installs429Demasiadas instalaciones nuevas desde la misma IP hoy.
events_already_sent429Los contadores de hoy ya se mandaron.
feedback_limit429Demasiados comentarios hoy.
internal_error500Un error nuestro.

Caché

Las respuestas valen hasta la próxima captura (06:45 o 10:45, hora argentina): Cache-Control y ETag, con 304 para If-None-Match.