# Mercado Público

> Pide una licitación por su ID y recibe sus adjuntos (bases, anexos, resoluciones) en PDF, Word, Excel o imagen, con enlaces de descarga. Sin clave: la conexión sólo pide la empresa.



`mercadopublico` descarga los adjuntos de una licitación de [Mercado Público](https://www.mercadopublico.cl) (bases, anexos, resoluciones, actas) y te los entrega con enlaces de descarga. Das el ID público de la licitación (por ejemplo `803-6-LE26`) y Connect hace el resto: abre la ficha, pasa la verificación del portal, recorre la lista de adjuntos y guarda cada archivo tal como lo publicó el comprador, con su nombre, tipo y descripción.

Se descargan los adjuntos en **PDF**, **Word** (`.docx`, `.doc`), **Excel** (`.xlsx`, `.xls`) e **imagen** (`.png`, `.jpg`, `.jpeg`). Connect revisa el contenido de cada archivo, no sólo su nombre, y entrega el formato real en `formato`: un `.doc` que en realidad es un `.docx` llega como `docx`.

No usa la API de Mercado Público ni clasifica los documentos: descarga todos los adjuntos admitidos de la licitación en el orden del portal, y decidir cuál es la base administrativa queda de tu lado.

Es un sistema **de pago**: se usa con una [conexión](/docs/conceptos/conexiones), que se cobra como cualquier otra de tu plan. Sus dos tools llevan el `conn_…` en cada llamada (en REST, el header `X-Connect-Connection`).

## Qué necesitas para conectar [#qué-necesitas-para-conectar]

Las licitaciones son públicas, así que **no se pide ninguna clave**. La conexión sólo pide el **RUT de la empresa** para la que la usas: la conexión es la empresa, y una misma empresa no se conecta dos veces.

Se crea de dos formas:

* **Desde el panel**: Conexiones → Conectar → Mercado Público, con el RUT de la empresa.
* **Desde un agente**, con `conexiones.conexion.crear`. Si esa empresa ya tiene una conexión activa, devuelve la misma y no crea otra:

```bash
curl -X POST https://connect.emisso.ai/api/v1/tools/conexiones.conexion.crear/execute \
  -H "Authorization: Bearer connect_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"input":{"sistema":"mercadopublico","empresaRut":"76.123.456-0"}}'
```

```json
{
  "data": {
    "id": "conn_...",
    "sistema": "mercadopublico",
    "sistemaNombre": "Mercado Público",
    "nombre": "Mercado Público",
    "empresaRut": "76123456-0",
    "creada": true
  }
}
```

A diferencia de los sistemas con clave, Mercado Público **no se conecta por enlace**: no hay nada que un tercero tenga que entregar. `conexiones.enlace.crear` lo rechaza y te indica `conexiones.conexion.crear`.

## Pedir una licitación: `mercadopublico.adjuntos.solicitar` [#pedir-una-licitación-mercadopublicoadjuntossolicitar]

```bash
curl -X POST https://connect.emisso.ai/api/v1/tools/mercadopublico.adjuntos.solicitar/execute \
  -H "Authorization: Bearer connect_sk_..." \
  -H "X-Connect-Connection: conn_..." \
  -H "Content-Type: application/json" \
  -d '{"input":{"codigoLicitacion":"803-6-LE26"}}'
```

```json
{
  "data": {
    "codigoLicitacion": "803-6-LE26",
    "estado": "pendiente",
    "solicitadoEn": "2026-09-25T22:25:49.625Z",
    "finalizadoEn": null,
    "errorCodigo": null,
    "consultarEnSegundos": 300
  }
}
```

La descarga **no es inmediata**: `solicitar` deja la licitación en cola y responde al instante. Connect la toma en su próxima pasada, que corre cada cinco minutos, y la descarga suele tardar menos de un minuto. `consultarEnSegundos` te dice cuándo volver a preguntar: 300 mientras espera turno, 60 mientras se descarga y `null` cuando terminó.

Pedir otra vez la misma licitación no duplica nada: si hay una descarga en curso, o una terminada en las últimas 24 horas, `solicitar` devuelve esa. El ID se acepta tal como sale en el portal; una URL no se acepta.

## Leer los adjuntos: `mercadopublico.adjuntos.consultar` [#leer-los-adjuntos-mercadopublicoadjuntosconsultar]

```bash
curl -X POST https://connect.emisso.ai/api/v1/tools/mercadopublico.adjuntos.consultar/execute \
  -H "Authorization: Bearer connect_sk_..." \
  -H "X-Connect-Connection: conn_..." \
  -H "Content-Type: application/json" \
  -d '{"input":{"codigoLicitacion":"803-6-LE26"}}'
```

```json
{
  "data": {
    "codigoLicitacion": "803-6-LE26",
    "estado": "disponible",
    "solicitadoEn": "2026-09-25T22:25:49.625Z",
    "finalizadoEn": "2026-09-25T22:27:10.655Z",
    "errorCodigo": null,
    "consultarEnSegundos": null,
    "observadoEn": "2026-09-25T22:27:10.647Z",
    "totalAnexos": 12,
    "completo": true,
    "motivosIncompletitud": [],
    "resultadoAnterior": false,
    "documentos": [
      {
        "id": "5b992ef3ed73b240e17b4c4a6601ce59a148a0e54b33adfa76bf4343abeade6b",
        "nombre": "BASES 803-6-LE26 DIFUSION.pdf",
        "descripcion": "BASES ID 803-6-LE26 DIFUSION",
        "tipo": "Otros Anexos de adquisición",
        "estado": "descargado",
        "formato": "pdf",
        "bytes": 811972,
        "sha256": "5b992ef3ed73b240e17b4c4a6601ce59a148a0e54b33adfa76bf4343abeade6b",
        "archivoUrl": "https://…/mercadopublico-bases/803-6-LE26/5b992ef3….pdf?token=…",
        "urlVenceEn": "2026-09-25T22:32:35.022Z"
      }
    ]
  }
}
```

`consultar` nunca abre el portal: lee lo que Connect ya guardó. Recortado a un documento.

**`estado`** dice en qué va el trabajo: `no_solicitada`, `pendiente`, `procesando`, `disponible` (se descargó todo lo que había), `parcial` (se descargó lo que se pudo; los motivos están en `motivosIncompletitud`) o `fallido` (con la causa en `errorCodigo`). Ninguno de `no_solicitada`, `pendiente` o `fallido` significa que la licitación no tenga adjuntos.

**`completo`** y **`motivosIncompletitud`** cuentan cuánto del listado del portal quedó cubierto. Un anexo en otro formato, por ejemplo un plano `.dwg` o un `.zip`, se inventaría (entra en `totalAnexos`, con `estado: "omitido_formato"`) pero no se descarga, y aparece el motivo `formatos_no_admitidos`. Otros motivos son `limite_archivos`, `limite_paginas`, `limite_total_bytes` y `paginacion_incompleta`.

**Los documentos** conservan el nombre, el tipo y la descripción que les puso el comprador, y su huella SHA-256 (que además es su `id`). El archivo es el original, sin modificar.

## Los enlaces de descarga [#los-enlaces-de-descarga]

Cada `archivoUrl` es un enlace firmado que vence a los **cinco minutos** (`urlVenceEn`). Para bajar el archivo después, vuelve a llamar a `consultar`: firma enlaces nuevos al instante, sin volver al portal. Mientras está vigente, el enlace funciona para quien lo tenga, así que trátalo como el documento mismo, que es público.

Si un enlace no se pudo firmar, ese documento viene con `archivoUrl: null` y el resto sale igual.

## Actualizar una licitación [#actualizar-una-licitación]

Pasadas 24 horas, un nuevo `solicitar` vuelve a descargar la licitación: el comprador puede haber agregado anexos o cambiado alguno. Mientras eso ocurre, y también si esa actualización falla, `consultar` **sigue entregando los documentos de la descarga anterior** con `resultadoAnterior: true`; `observadoEn` dice de cuándo son. Sólo una descarga exitosa los reemplaza. Tras un fallo, puedes volver a pedirla a los 15 minutos.

## Si algo falla [#si-algo-falla]

`errorCodigo` acota la causa, sin datos de la sesión ni URLs del portal:

| Código                                                        | Qué pasó                                                                                  |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `licitacion_no_encontrada`                                    | El portal no tiene una ficha con ese ID. Revisa el código.                                |
| `portal_no_disponible`                                        | Mercado Público no respondió o no dejó abrir la lista de adjuntos. Suele ser transitorio. |
| `descarga_fallida`                                            | La lista se abrió pero la descarga no terminó.                                            |
| `limite_excedido`                                             | Un archivo supera el tope de tamaño.                                                      |
| `almacenamiento_fallido`, `ingesta_fallida`, `lease_expirado` | Un problema de nuestro lado. Vuelve a pedirla; si se repite, escríbenos.                  |

## Límites [#límites]

Por licitación, Connect descarga hasta **30 archivos** en hasta **10 páginas** del listado, con un tope de **16 MiB por archivo** y **128 MiB en total**. Sólo PDF, Word, Excel, PNG y JPEG: otros formatos se inventarían pero no se descargan. Cuando se alcanza un límite, el resultado queda `parcial` y lo dice en `motivosIncompletitud`.

## Por MCP [#por-mcp]

El recorrido de un agente es el mismo de siempre, con una diferencia: si Mercado Público aparece con `conectado: false`, el camino es `conexiones.conexion.crear`, no un enlace.

1. `search_docs` para ver el catálogo.
2. `conexiones.estado.consultar` para obtener el `connectionId` (o `conexiones.conexion.crear` si todavía no hay conexión).
3. `execute_write` con `mercadopublico.adjuntos.solicitar`.
4. `execute` con `mercadopublico.adjuntos.consultar`, esperando lo que diga `consultarEnSegundos`.

La ficha técnica de cada tool está en la [referencia](/docs/referencia/mercadopublico).
