
API para desarrolladores
Con esta API, el sistema de gestión del comercio (su ERP) mantiene al día en Precio de Góndola los artículos, sus códigos de barras y sus precios. Lo que llega por la API aparece en el portal y en las terminales de mano, igual que si se hubiera cargado a mano.
Está incluida en el plan Clásica.
1. Para empezar
Todo se habla en JSON, por HTTPS, contra https://preciodegondola.com/api/v1. Probá que la llave anda con:
curl https://preciodegondola.com/api/v1/yo \ -H "Authorization: Bearer pdg_api_TU_LLAVE"
2. La llave
La crea alguien del comercio en el portal, en Configuración › Conexión con tu sistema (API). Empieza con pdg_api_ y se ve una sola vez: guardala como un secreto (en una variable de entorno, nunca en el código ni en un repositorio). Viaja en cada pedido en la cabecera:
Authorization: Bearer pdg_api_TU_LLAVE
La API cambia cosas en nombre de la persona que creó la llave. Si a esa persona le sacan el permiso de cargar artículos, o el comercio la revoca desde el portal, la llave deja de andar en el acto (vas a recibir un 401 o un 403).
3. Reglas generales
- Cada artículo se identifica por su código interno (
sku), el mismo de tu sistema, como texto. Sin importar mayúsculas. - Lo que no mandás no se toca. Mandar
{ "sku": "123", "marca": "X" }cambia sólo la marca. - Un dato vacío (
""onull) es lo mismo que no mandarlo: no borra nada. - Cada dato va en su tipo: textos como texto, números como número, sí/no como
true/falsey fechas como"AAAA-MM-DD". Un dato en otro tipo hace que se rechace ese artículo. - Nada se da de baja solo: un artículo que no viene en un envío sigue como estaba. Para darlo de baja, pedilo explícitamente.
- Los precios son el precio final al público, con IVA. Se aplican tal cual llegan.
- Precios y contenido van como número JSON (
1234.5), nunca como texto ("1.234,50"se rechaza). - Hasta 5.000 artículos o precios por pedido (y hasta 4 MB por pedido) y 120 pedidos por minuto por llave. Mandá en tandas grandes.
- Mandá los pedidos de a uno, esperando la respuesta del anterior. Dos pedidos a la vez que tocan los mismos artículos pueden chocar (
409 conflicto). - Un pedido es parcial: lo que está bien entra y lo que está mal vuelve en
rechazadoscon el motivo. Reintentar el mismo pedido es seguro: deja todo igual. - Si la suscripción del comercio está vencida, la API sólo lee (los pedidos que escriben devuelven
403 cuenta_limitada).
4. Quién soy: listas y campos
GET/api/v1/yo
De qué comercio es la llave, si puede escribir, sus listas de precios y los campos que usa. Llamalo al conectar para saber qué listas y campos existen.
{
"comercio": "Supermercado Demo",
"llave": "Mi ERP",
"puede_escribir": true,
"motivo_sin_escritura": null,
"listas": [
{ "id": "4f6a…", "nombre": "Minorista" },
{ "id": "9b21…", "nombre": "Mayorista" }
],
"campos": [
{ "clave": "sku", "nombre": "Código interno", "tipo": "texto", "opciones": [], "del_sistema": true },
{ "clave": "pasillo", "nombre": "Pasillo", "tipo": "lista", "opciones": ["1", "2", "3"], "del_sistema": false }
],
"limites": { "por_pedido": 5000, "pedidos_por_minuto": 120, "por_pagina": 1000 }
}5. Leer artículos
GET/api/v1/articulos
Los artículos, ordenados por código interno, de a páginas.
| Parámetro | Qué es |
|---|---|
despues_de | Para la página siguiente: el valor de siguiente que vino en la respuesta anterior. En la primera, no se manda. |
por_pagina | Cuántos por página (hasta 1000; si no se dice, 500). |
modificados_desde | Sólo los que cambiaron (datos, precios o códigos) después de esa fecha y hora, en ISO 8601. Ej.: 2026-10-03T08:00:00-03:00. |
incluir_bajas | Con true trae también los dados de baja. |
curl "https://preciodegondola.com/api/v1/articulos?por_pagina=500" \ -H "Authorization: Bearer pdg_api_TU_LLAVE"
{
"por_pagina": 500,
"hay_mas": true,
"siguiente": "1500",
"articulos": [
{
"sku": "1001",
"descripcion": "Yerba Playadito 1 kg",
"descripcion_corta": "Yerba Playadito",
"marca": "Playadito",
"rubro": "Almacén",
"unidad_venta": "UN",
"contenido": 1,
"unidad_contenido": "KG",
"campos": { "pasillo": "3" },
"codigos_de_barras": ["7790001000012"],
"precios": [
{ "lista_id": "4f6a…", "lista": "Minorista", "precio": 4500 },
{ "lista_id": "9b21…", "lista": "Mayorista", "precio": 3900 }
],
"activo": true,
"actualizado_en": "2026-10-03T11:20:00.000Z"
}
]
}Mientras hay_mas sea true, pedí la siguiente con despues_de=<valor de siguiente>.
GET/api/v1/articulos/{sku}
Un artículo por su código interno (con el mismo formato). Si no existe: 404 articulo_inexistente.
6. Crear y modificar artículos
POST/api/v1/articulos
Si el código interno existe, se actualiza; si no, se crea (para crearlo hace falta descripcion). Se pueden mandar los datos, los códigos de barras y los precios juntos.
curl -X POST https://preciodegondola.com/api/v1/articulos \
-H "Authorization: Bearer pdg_api_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{
"articulos": [
{
"sku": "1001",
"descripcion": "Yerba Playadito 1 kg",
"marca": "Playadito",
"rubro": "Almacén",
"unidad_venta": "UN",
"contenido": 1,
"unidad_contenido": "KG",
"codigos_de_barras": ["7790001000012"],
"precios": { "Minorista": 4500, "Mayorista": 3900 }
},
{ "sku": "1002", "marca": "Cocinero" }
]
}'| Dato | Tipo | Qué es |
|---|---|---|
sku | texto | Obligatorio. El código interno del artículo en tu sistema. |
descripcion | texto | El nombre. Obligatorio para crear. |
descripcion_corta | texto | El nombre para la etiqueta chica. |
marca | texto | |
rubro | texto | Si no existe, se crea. |
unidad_venta | texto | Cómo se vende: UN, KG o LT. |
contenido | número | Cuánto trae el envase (1.5 para 1,5 litros). Va con su unidad. |
unidad_contenido | texto | KG, GR, LT, ML o UN. |
campos | objeto | Los campos propios del comercio, por su clave: { "pasillo": "3" }. Las claves salen de /yo (los que tienen del_sistema: false). Cada valor según su tipo: texto y lista como texto (en una lista, una de sus opciones), numero como número, si_no como true/false, fecha como "AAAA-MM-DD". |
codigos_de_barras | lista de textos | El artículo queda con exactamente estos códigos: se agregan los nuevos y se quitan los que no están. Una lista vacía no quita nada. Van como texto (un número pierde los ceros de adelante) y sin comas, punto y coma ni barras. |
precios | objeto | Precio final por lista: la clave es el nombre o el id de la lista. { "Minorista": 4500 }. |
activo | true / false | false lo da de baja y true lo reactiva. Si no viene, no cambia. |
Un dato que no está en esta tabla hace que se rechace ese artículo (así un error de tipeo no pasa en silencio). También se rechaza uno que el comercio no usa: si apagó la marca en su ficha, mandar marca rechaza el artículo. Los datos que usa están en /yo.
7. Cambiar precios
POST/api/v1/precios
Para cuando sólo cambian precios: más liviano que mandar el artículo entero. La lista va por su nombre o id. Un código interno que no existe se rechaza (los artículos se crean por /articulos).
curl -X POST https://preciodegondola.com/api/v1/precios \
-H "Authorization: Bearer pdg_api_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{
"precios": [
{ "sku": "1001", "lista": "Minorista", "precio": 4650 },
{ "sku": "1001", "lista": "Mayorista", "precio": 3990.5 },
{ "sku": "1002", "lista": "Minorista", "precio": 2100 }
]
}'8. Dar de baja
POST/api/v1/bajas
Da de baja artículos por su código interno. No se borra nada: el artículo, su historial de precios y lo que se imprimió quedan, y se reactiva mandándolo con "activo": true. También se puede dar de baja con "activo": false en /articulos.
curl -X POST https://preciodegondola.com/api/v1/bajas \
-H "Authorization: Bearer pdg_api_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{ "skus": ["1005", "1006"] }'9. Respuestas y rechazos
Los pedidos que escriben contestan 200 con lo que se hizo, aunque algo se haya rechazado:
{
"recibidos": 3,
"creados": 1,
"actualizados": 1,
"precios_cambiados": 2,
"codigos_agregados": 1,
"codigos_quitados": 0,
"dados_de_baja": 0,
"reactivados": 0,
"rechazados": [
{ "posicion": 3, "sku": "1003", "motivo": "El precio de «Minorista» tiene que ser un número JSON mayor o igual a 0 (1234.5), no un texto." }
],
"opciones_creadas": []
}posicion es el lugar del elemento en la lista que mandaste, contando desde 1. Revisá siempre rechazados: lo que está ahí no entró. Corregilo y volvé a mandar sólo eso. precios_cambiados cuenta los precios que se escribieron, aunque alguno haya quedado igual que antes.
10. Errores
Cuando el pedido entero no se puede atender, la respuesta trae un código HTTP de error y siempre la misma forma:
{ "error": { "codigo": "llave_invalida", "mensaje": "La llave no existe o fue revocada." } }| HTTP | Código | Qué pasó |
|---|---|---|
| 400 | pedido_invalido · json_invalido · fecha_invalida | Falta la lista (articulos, precios o skus), el cuerpo no es un JSON válido o «modificados_desde» no es una fecha. |
| 401 | sin_llave · llave_invalida | Falta la llave, o no existe, o fue revocada. |
| 403 | usuario_sin_permiso · plan_sin_api · comercio_suspendido · cuenta_limitada | La llave existe pero no puede hacer eso. |
| 404 | articulo_inexistente | No hay un artículo con ese código interno. |
| 409 | conflicto | Otro pedido estaba cambiando los mismos artículos al mismo tiempo. Reintentá. |
| 413 | pedido_grande | Más de 5.000 elementos: partilo en tandas. (Un cuerpo de más de 4 MB lo corta el servidor antes, con un 413 que no es JSON.) |
| 429 | demasiados_pedidos | Más de 120 pedidos en un minuto: esperá y mandá en tandas más grandes. |
| 500 | error_interno | Falló algo de nuestro lado. Reintentá en unos minutos. |
Ante un 409, un 429 o un 500, reintentá con espera creciente (por ejemplo 1, 2, 4 y 8 minutos). Reintentar es seguro.
11. Cómo sincronizar
La primera vez
Llamá a /yo para conocer las listas. Mandá todo el catálogo por /articulos, en tandas de hasta 5.000.
Después
Mandá sólo lo que cambió en tu sistema: precios por /precios, artículos nuevos o modificados por /articulos, y bajas por /bajas. Lo habitual es cada pocos minutos, o cuando se guarda un cambio.
Si querés traer lo que se cambió en el portal
Guardá el actualizado_en más nuevo que recibiste y la próxima vez pedí /articulos?modificados_desde=ESA_HORA_MENOS_5_MINUTOS&incluir_bajas=true. Restale 5 minutos: una carga grande que estaba en curso mientras leías puede quedar con una hora un poco anterior, y así no se pierde. Volver a recibir un artículo no hace daño. Con incluir_bajas=true te enterás también de los que se dieron de baja desde el portal ("activo": false).
Ojo: si reenviás todo el catálogo, todos los artículos quedan como modificados y la próxima lectura los trae a todos.
12. Especificación OpenAPI
Para generar un cliente o probar desde Postman o Insomnia: /api/v1/openapi.json (OpenAPI 3.1).
¿Dudas con la integración? Escribinos a hola@preciodegondola.com.