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
| Ruta | Qué devuelve |
|---|---|
GET /v1/stores | Los 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}/prices | La serie diaria (por defecto, los últimos 30 días). |
GET /v1/products/{id}/prices/{fecha} | Un día (YYYY-MM-DD). |
POST /v1/installs | 201 con { installId, token }. |
POST /v1/events | Los contadores del día: { version, counters: { evento: cantidad } }. Uno por día. |
POST /v1/feedback | Un comentario: { text, version, site }. Es anónimo. |
GET /health | Que la API responde. |
Parámetros de precio
| Parámetro | |
|---|---|
branch=078 | Los 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=true | effectivePrice con el precio de socio de la Comunidad Coto si es más barato. |
from, to | Fechas YYYY-MM-DD, como mucho 30 días. |
include=prices | En /products: la serie de cada producto. |
fields=sku,prices | Só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ódigo | HTTP | Qué pasó |
|---|---|---|
invalid_branch | 400 | branch no es un número de sucursal. |
invalid_member | 400 | member no es true ni false. |
invalid_date | 400 | Una fecha no es YYYY-MM-DD válida. |
invalid_range | 400 | from es posterior a to. |
range_too_long | 400 | Más de 30 días. |
invalid_include | 400 | include sólo acepta prices. |
invalid_fields | 400 | Un campo de fields no existe. |
missing_store | 400 | Falta store. |
missing_filter | 400 | Falta sku o ean (o vinieron los dos). |
invalid_sku | 400 | sku no es una lista de 1 a 100 SKU. |
invalid_ean | 400 | ean no es una lista de 1 a 100 EAN. |
invalid_body | 400 | El cuerpo no es el JSON esperado. |
unknown_event | 400 | Un evento que no está en la lista. |
invalid_count | 400 | Una cantidad fuera de rango. |
missing_token | 401 | Falta X-Install-Token. |
invalid_token | 401 | El token no es válido o fue revocado. |
not_found | 404 | La ruta no existe. |
store_not_found | 404 | El súper no existe. |
product_not_found | 404 | No tenemos ese producto. |
price_not_found | 404 | El producto no tiene precio ese día. |
method_not_allowed | 405 | El método no va en esa ruta (ver Allow). |
payload_too_large | 413 | El cuerpo pasa de 16 KB. |
rate_limited | 429 | Tope de productos distintos del día. |
too_many_installs | 429 | Demasiadas instalaciones nuevas desde la misma IP hoy. |
events_already_sent | 429 | Los contadores de hoy ya se mandaron. |
feedback_limit | 429 | Demasiados comentarios hoy. |
internal_error | 500 | Un 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.