API REST v1

Base https://sandbox.minimarket.digital/v1 · respuestas en JSON · multi-tenant por subdominio

Autenticación

Todas las peticiones requieren la cabecera X-SYNCS-API-TOKEN con un token vigente, emitido por el tenant. El tenant se resuelve por el subdominio de la petición.

Verificar un token

curl -H "X-SYNCS-API-TOKEN: TU_TOKEN" https://sandbox.minimarket.digital/v1/acl
{
    "status": "success",
    "code": "200",
    "message": "TOKEN_VALID",
    "data": {
        "emp_id": "tester",
        "rol_id": "api",
        "name": "Token de pruebas",
        "tenant": "demo"
    }
}
SituaciónCódigomessage
Falta la cabecera401UNAUTHORIZED
Token inexistente, anulado o expirado401TOKEN_INVALID
El subdominio no corresponde a un tenant403TENANT_UNKNOWN
El rol del token no puede ejecutar esa operación403FORBIDDEN
El token tiene una lista de IPs y la petición no viene de ninguna de ellas403IP_NOT_ALLOWED

Cuando al token le quedan pocos días de vigencia, cada respuesta trae las cabeceras X-Token-Expires (fecha) y X-Token-Expires-In (días). Es el aviso para pedir el reemplazo antes de que deje de funcionar.

Alcance de los permisos

El rol del token decide qué operaciones puede ejecutar sobre cada recurso, y cada permiso tiene un alcance: Propios (lo que registró o tiene asignado la persona del token), Grupo (lo propio y lo de quienes la tienen como jefatura directa, en cadena) o Todo (toda la empresa). Un registro fuera del alcance no existe para ese token: se responde 404 NO_DATA, igual que si no existiera, y los listados no lo cuentan.

Tampoco existe lo que en el sistema está como borrador, anulado, archivado o eliminado: no se lista, no se lee, no se edita ni se vuelve a eliminar.

Estados con permiso propio

En los recursos con estado, algunos estados exigen su propio permiso (aprobar, rechazar, anular…). Dejar un registro en uno de esos estados, editarlo mientras sigue en él o sacarlo de él pide ese permiso, con su alcance. Si el rol no lo tiene, se responde 403 FORBIDDEN: comando, con el comando que falta (por ejemplo, FORBIDDEN: apv para Aprobar).

Formato de respuesta

Todas las respuestas comparten la misma envoltura. meta aparece solo en los listados.

{
    "status"  : "success" | "error",
    "code"    : "200",
    "message" : "LIST | GET | ADD | UPDATE | DELETED | ...",
    "data"    : { ... } | null,
    "meta"    : { "page": 1, "per_page": 20, "count": 20, "total": 134 }
}

En los listados, data es un objeto indexado por el id de cada registro. El código HTTP de la respuesta coincide siempre con el campo code.

Métodos HTTP

MétodoRutaCuerpoAcción
GET/v1/{x}—Lista paginada
GET/v1/{x}/{id}—Un registro
POST/v1/{x}JSON completoAgrega. Devuelve 201 ADD
PUT/v1/{x}/{id}JSON parcialActualiza los campos enviados
PATCH/v1/{x}/{id}JSON parcialIdéntico a PUT
DELETE/v1/{x}/{id}—Elimina el registro

Sobre POST

Solo se graban las columnas de la lista blanca de cada recurso (los campos grabables que aparecen en cada endpoint); cualquier otra clave del JSON se ignora en silencio. Cada valor es un texto, un número, un booleano (se guarda como 1 o 0) o null; un arreglo o un objeto responde 400 FIELD_INVALID: campo. Los componentes de la clave primaria que no se envíen toman el valor ---. El id puede enviarse (máximo 45 caracteres alfanuméricos, _, - y .); si se omite, la API genera un UUID.

Recursos de sólo lectura

Algunos recursos sólo se consultan, porque su contenido es el resultado de un proceso del sistema y no un dato que se edita (el stock, por ejemplo). Su página lo indica, y POST, PUT, PATCH y DELETE responden 405 READ_ONLY.

Fechas y horas

Las horas se devuelven y se reciben en la zona horaria de la empresa, no en la de quien consulta: si la operación se realiza en Chile, la hora es la de Chile aunque el sistema que llame esté en otro país. El formato es YYYY-MM-DD HH:MM:SS. Los parámetros since y until se interpretan también en esa zona.

Las fechas sin hora (YYYY-MM-DD), como la de una factura o un vencimiento, no se convierten nunca: no son un instante, son el día que decidió la empresa.

Reintentos seguros (idempotencia)

Un POST que se reintenta crea el registro dos veces: pasa con un tiempo de espera agotado en el que la petición sí llegó, con un doble clic o con una cola que reenvía lo que cree fallido. Para evitarlo, envía la cabecera Idempotency-Key con un valor único por operación (un UUID, por ejemplo). La primera petición se ejecuta y su respuesta queda guardada; las siguientes con la misma clave devuelven esa misma respuesta, con la cabecera Idempotent-Replay: true, sin crear nada nuevo.

curl -X POST "https://sandbox.minimarket.digital/v1/customer" \
     -H "X-SYNCS-API-TOKEN: TU_TOKEN" \
     -H "Idempotency-Key: 7f3c1e40-9b2a-4c11-8e77-0a1b2c3d4e5f" \
     -H "Content-Type: application/json" \
     -d '{"name":"ACME"}'

La clave es de una operación: el token, el método, el recurso, la ruta y el cuerpo. Se recuerda 24 horas. Si se reutiliza en otra operación (otro recurso, otra ruta, otro método o un cuerpo distinto) se responde 409 IDEMPOTENCY_KEY_REUSED, nunca la respuesta de la otra; si la primera petición todavía está en curso, 409 IDEMPOTENCY_IN_PROGRESS. Quien no envíe la cabecera no nota ningún cambio.

Sobre PUT y PATCH

Ambos hacen exactamente lo mismo: actualización parcial. Solo se modifican las columnas presentes en el JSON, el resto queda intacto — no hace falta reenviar el registro completo. Se usa PATCH por corrección semántica y PUT por compatibilidad con clientes que no lo soportan. La API graba modified y modified_by automáticamente.

Los componentes de la clave identifican el registro y no se cambian: enviarlos responde 400 FIELD_READONLY: campo, con todos los que llegaron. En los recursos por idioma, lng_id indica qué traducción se edita y no se escribe.

Si el id no existe, ya se eliminó o queda fuera del alcance del permiso, responden 404 NO_DATA; si el JSON no trae ninguna columna válida, 400 NO_VALID_FIELDS.

Contenido con formato y enlaces

Los campos con formato (el cuerpo de un artículo, la descripción de un cliente, un producto, un almacén o una lista de precios, y los que la empresa marque con editor de contenido en el sistema) se sanean al guardar: se conservan párrafos, títulos, listas, tablas, enlaces e imágenes, y se quitan los scripts, los atributos de evento (onclick…), los estilos no permitidos, los enlaces con un esquema distinto de http, https, mailto y tel, y las imágenes que no son http, https o PNG, JPEG, GIF o WebP embebidas. No se rechaza: se guarda limpio, así que lo que se lee después puede diferir de lo enviado. Los campos de enlace aceptan una URL http o https completa, o vacío; cualquier otra cosa responde 400 FIELD_INVALID: campo.

Quien muestre ese contenido en una página debe sanearlo también, con su propia lista blanca: la API no presupone quién escribió cada registro, y lo guardado antes de esta regla no se volvió a sanear.

Enviar el cuerpo

Se acepta el body crudo con Content-Type: application/json (recomendado) o el parámetro d con el JSON codificado en la URL.

Uso desde el navegador (CORS)

Las llamadas desde servidor (curl, un backend, una app móvil) no tienen restricción de origen. Desde JavaScript, en cambio, solo se permite llamar a la API desde los dominios que el propio tenant tenga registrados: su sitio público, su portal, su aplicación, su extranet y su plataforma de formación. Otros orígenes se piden al administrador. El preflight OPTIONS se responde sin token.

Parámetros de listado

Parám.DescripciónDefectoEjemplo
pageNúmero de página1?page=2
per_pageRegistros por página (máx. 1000)20?per_page=50
sinceInicio del rango de creación (columna entered). Solo fecha = desde las 00:00:00—?since=2026-07-01
untilFin del rango de creación. Solo fecha = hasta las 23:59:59—?until=2026-07-31
qBúsqueda de texto en los campos indicados en cada recurso—?q=abc
sCampo de ordenamientosegún recurso?s=entered
oSentido: asc o descasc?o=desc
fFiltros exactos en JSON—?f={"cat_id":"X"}
iId del registro (equivale a /{recurso}/{id}). Con el id en la ruta, manda el de la ruta: un i distinto, vacío o en arreglo responde 400 PARAM_INVALID: i—?i=ABC123

Los formatos aceptados en since / until son YYYY-MM-DD y YYYY-MM-DD HH:MM:SS; cualquier otro devuelve 400 PARAM_INVALID. Un campo de ordenamiento o un filtro que no pertenezca al recurso devuelve 400 en vez de ignorarse, y el valor de un filtro tiene que ser texto, número o booleano: un arreglo, un objeto o null responde 400 FILTER_INVALID: campo.

Códigos de error

CódigomessageCuándo
400NO_DATA_SENT, NO_DATA_ID, NO_VALID_FIELDS, FIELD_REQUIRED: x, FIELD_INVALID: x, FIELD_READONLY: x, y, FILTER_INVALID: x, PARAM_INVALID: xPetición incompleta o con campos fuera de la lista blanca; un valor que no es texto, número, booleano ni null, o una URL que no es http(s) (FIELD_INVALID); una columna de la clave o un campo calculado en un PUT/PATCH (FIELD_READONLY); un filtro con un valor que no es escalar (FILTER_INVALID); con el id en la ruta, un i distinto en la query o en el formulario (PARAM_INVALID: i)
401UNAUTHORIZED, TOKEN_INVALIDFalta el token o no es válido
403FORBIDDEN, FORBIDDEN: x, TENANT_UNKNOWN, IP_NOT_ALLOWEDEl rol del token no tiene permiso sobre ese recurso (FORBIDDEN), o no tiene el que exige un estado o una exportación (FORBIDDEN: comando, con el comando que falta), o el subdominio no corresponde a ningún tenant (TENANT_UNKNOWN)
404NO_DATA, NOT_FOUNDSin resultados, ruta inexistente, o un registro que no existe, se eliminó o queda fuera del alcance del permiso
405METHOD_NOT_ALLOWED, READ_ONLYMétodo HTTP no soportado (METHOD_NOT_ALLOWED), o una escritura en un recurso de sólo lectura (READ_ONLY)
409DUPLICATE, IDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_IN_PROGRESSViola una clave única (nombre, código de barras, slug…), o reutiliza una Idempotency-Key en otra operación (IDEMPOTENCY_KEY_REUSED) o mientras la primera sigue en curso (IDEMPOTENCY_IN_PROGRESS)
429RATE_LIMIT_EXCEEDED, TOO_MANY_ATTEMPTS, TOO_MANY_REQUESTSSe superó el ritmo permitido. La respuesta trae Retry-After con los segundos que hay que esperar. Hay dos límites: peticiones por minuto de un mismo token, e intentos fallidos de autenticación desde una misma IP.
500 / 503DB_ERROR, INTERNAL_ERROR, SANITIZER_UNAVAILABLE, SERVICE_UNAVAILABLEError interno o base de datos no disponible. SANITIZER_UNAVAILABLE: el servidor no puede sanear un campo con formato y no lo guarda sin sanear

Colección de Postman

Toda la API lista para importar en Postman: una carpeta por módulo, las seis operaciones de cada recurso con sus parámetros y ejemplos, y pruebas que comprueban la envoltura de cada respuesta. Se genera en el momento a partir de esta misma documentación, así que nunca va por detrás de lo publicado.

Descargar la colección Descargar el entorno

Con la colección basta: el baseUrl ya apunta a esta API. Pega tu token en la variable token y envía cualquier petición. El entorno es opcional — sirve para apuntar la misma colección a otro servidor sin tocarla.

Recursos

Cada recurso tiene su propia página con el detalle de sus operaciones, campos y ejemplos.

Almacenes

Clientes y terceros

Planificación del transporte

Productos y servicios

Catálogo

Publicaciones internas

Archivos y conocimiento

Clasificación del catálogo

Precios y condiciones