# Mercado Público Chile – Licitaciones y Órdenes de Compra (`better-llama/mercado-publico-chile`) Actor

Normalized Chilean public procurement data for AI agents and developers: tenders (licitaciones) and purchase orders from the official Mercado Público API (Compra Ágil in beta), using your own free ChileCompra ticket. Not affiliated with ChileCompra.

- **URL**: https://apify.com/better-llama/mercado-publico-chile.md
- **Developed by:** [Francisco Rubio](https://apify.com/better-llama) (community)
- **Categories:** Developer tools, AI
- **Features:** Limited permissions
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 resultado entregado / delivered results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Mercado Público Chile – Licitaciones y Órdenes de Compra

**ES** · Datos normalizados de compras públicas de Chile para agentes de IA y desarrolladores, obtenidos de la **API oficial de Mercado Público** usando **tu propio ticket**.
**EN** · Normalized Chilean public procurement data for AI agents and developers, from the **official Mercado Público API**, using **your own ticket**.

> ⚠️ **Se requiere ticket propio / Your own ticket is required.** El ticket es gratuito, personal (uno por persona) y se solicita con Clave Única en <https://www.chilecompra.cl/api/>. Este Actor **no incluye, comparte ni revende tickets**: cada ejecución usa el ticket que tú entregas, y consume **tu** cuota (10.000 solicitudes/día por ticket).
>
> ⚠️ **No afiliado / Not affiliated.** Este Actor es un proyecto independiente. **No está afiliado, patrocinado ni aprobado por la Dirección ChileCompra** ni por Mercado Público. "Mercado Público" y "ChileCompra" se mencionan solo para describir la fuente de los datos.
>
> **Fuente de los datos / Data source:** Dirección ChileCompra (API de Mercado Público). Cada registro incluye el campo `dataSource` con esta atribución.

### Qué hace / What it does

| Fuente (`source`) | Endpoint oficial | Filtros |
|---|---|---|
| `licitaciones` | `api.mercadopublico.cl/servicios/v1/publico/licitaciones.json` | fecha (rango ≤ 31 días), estado, código de organismo, código de proveedor, códigos específicos |
| `ordenes_compra` | `api.mercadopublico.cl/servicios/v1/publico/ordenesdecompra.json` | fecha, estado, organismo, proveedor, códigos |
| `compra_agil` **(BETA)** | `api2.mercadopublico.cl/v2/compra-agil` (API v2, beta oficial desde mayo 2026; **aún no validada con datos reales en este Actor**: en pruebas del 09-11-2026 la API respondió 504) | fecha de publicación, estados, regiones, palabras clave, RUT de organismo (filtro local), códigos |

- Los listados por fecha de la API v1 traen solo datos básicos; con `fetchDetails: true` (por defecto) se consulta la ficha de cada resultado (1 solicitud extra de tu cuota por resultado).
- Salida **normalizada y estable** (mismos campos para las tres fuentes), fechas **ISO 8601 UTC**, estados en **español e inglés**, enlace a la **ficha oficial**.
- **Deduplicación** por fuente + código, también si la ejecución se reanuda.
- **Límites y reintentos:** pausa de 2,5 s por defecto entre el fin de una respuesta y la siguiente solicitud (la API rechaza peticiones simultáneas), reintentos con espera exponencial ante errores de red, 5xx y "peticiones simultáneas"; respeta `Retry-After`.
- **Errores claros:** ticket inválido o cuota agotada terminan la ejecución con un mensaje explícito; si la cuota se agota a mitad de camino, se entrega lo ya obtenido.
- **Privacidad:** no se exponen nombres, RUT, correos ni teléfonos de funcionarios o contactos, ni el nombre/RUT de proveedores que sean personas naturales (ni siquiera en `raw`).
- El ticket se marca como **secreto** (cifrado por Apify) y nunca se escribe en logs.

### Precio / Pricing

Pago por resultado (*pay per event*): solo se cobra el evento `result` por cada registro **entregado** en el dataset. No se cobran consultas vacías, duplicados ni errores. Ver la pestaña *Pricing* del Actor. Puedes fijar un gasto máximo por ejecución; el Actor se detiene al alcanzarlo.

### Input

```json
{
  "ticket": "TU-TICKET-PERSONAL",
  "source": "licitaciones",
  "dateFrom": "2026-11-02",
  "dateTo": "2026-11-06",
  "tenderStatus": "publicada",
  "buyerCode": "6945",
  "fetchDetails": true,
  "maxItems": 100
}
```

Compra Ágil (BETA, aún no validada con datos reales):

```json
{
  "ticket": "TU-TICKET-PERSONAL",
  "source": "compra_agil",
  "agileStatuses": ["publicada"],
  "regions": ["13"],
  "keyword": "materiales electricos",
  "maxItems": 50
}
```

Por código / by code: `{ "ticket": "…", "source": "ordenes_compra", "codes": ["1057532-156-AG26"] }`

| Campo | Descripción (ES) | Description (EN) |
|---|---|---|
| `ticket` | Tu ticket (secreto, obligatorio) | Your ticket (secret, required) |
| `source` | `licitaciones` · `ordenes_compra` · `compra_agil` | Data source |
| `codes` | Códigos exactos; ignora los demás filtros | Exact codes; other filters ignored |
| `dateFrom` / `dateTo` | `YYYY-MM-DD`, día de Chile; por defecto hoy; máx. 31 días | Chile calendar day; default today; max 31 days |
| `tenderStatus` | `activas`, `publicada`, `cerrada`, `desierta`, `adjudicada`, `revocada`, `suspendida`, `todos` | Tender status |
| `purchaseOrderStatus` | Valores oficiales (`aceptada`, `cancelada`, `recepcionconforme`, …) | PO status (official values) |
| `buyerCode` / `supplierCode` | `CodigoOrganismo` / `CodigoProveedor` numéricos de Mercado Público | Numeric buyer / supplier codes |
| `agileStatuses`, `regions`, `keyword`, `buyerRut` | Solo Compra Ágil | Compra Ágil only |
| `fetchDetails` | Consultar ficha completa (por defecto `true`) | Fetch full record |
| `includeRaw` | Agregar registro original sin datos personales | Add raw record (personal data removed) |
| `maxItems` | Máximo de resultados entregados/cobrados (por defecto 50) | Max delivered/charged results |
| `requestIntervalMs`, `maxRetries` | Ritmo y reintentos | Pacing and retries |

### Output (diccionario / data dictionary)

| Campo | ES | EN |
|---|---|---|
| `source` | `licitacion`, `orden_compra`, `compra_agil` | Record type |
| `code` | Código oficial | Official code |
| `name`, `description` | Nombre, descripción | Name, description |
| `statusCode`, `statusEs`, `statusEn` | Código de estado de la API y su glosa | API status code and label |
| `type` | Tipo (L1, LE, LP, SE, CM… o `COMPRA_AGIL`) | Procurement type |
| `buyerName`, `buyerCode`, `buyerRut`, `buyerUnit`, `buyerRegion` | Organismo comprador | Buyer |
| `supplierName`, `supplierCode`, `supplierRut` | Proveedor (OC). **`null` si es persona natural** | Supplier (POs); `null` for natural persons |
| `supplierType` | `persona_juridica`, `persona_natural` o `null` | Supplier type |
| `publishedAt`, `closesAt`, `awardedAt`, `createdAt`, `updatedAt` | Fechas ISO 8601 UTC | ISO 8601 UTC dates |
| `estimatedAmount` | Monto estimado / disponible | Estimated / available budget |
| `totalAmount` | Total de la OC | PO total |
| `currency` | CLP, CLF (UF), USD, UTM, EUR | Currency |
| `relatedTenderCode` | Licitación asociada a la OC | Related tender |
| `itemsCount` | Cantidad de ítems/productos | Line items |
| `officialUrl` | Ficha oficial en mercadopublico.cl | Official page |
| `detailLevel` | `full` (ficha) o `basic` (listado) | Detail level |
| `dataSource`, `retrievedAt` | Atribución y fecha de obtención | Attribution, retrieval time |

Ejemplo / example:

```json
{
  "source": "licitacion",
  "code": "1509-5-L126",
  "name": "Servicio de aseo dependencias municipales",
  "statusCode": "5", "statusEs": "Publicada", "statusEn": "Published",
  "type": "L1",
  "buyerName": "I MUNICIPALIDAD DE EJEMPLO", "buyerCode": "6945",
  "publishedAt": "2026-11-09T13:00:00.000Z", "closesAt": "2026-11-20T18:00:00.000Z",
  "estimatedAmount": 3500000, "currency": "CLP",
  "officialUrl": "https://www.mercadopublico.cl/Procurement/Modules/RFB/DetailsAcquisition.aspx?idlicitacion=1509-5-L126",
  "detailLevel": "full",
  "dataSource": "Fuente: Dirección ChileCompra (API de Mercado Público). Registro normalizado por este Actor."
}
```

*(Ejemplo ilustrativo con datos ficticios / illustrative, fictitious data.)*

### Uso vía API / API usage

```bash
curl -X POST "https://api.apify.com/v2/acts/better-llama~mercado-publico-chile/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
  -d '{"ticket":"'"$MP_TICKET"'","source":"compra_agil","agileStatuses":["publicada"],"regions":["13"],"maxItems":20}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('better-llama/mercado-publico-chile').call({
  ticket: process.env.MP_TICKET, source: 'licitaciones', tenderStatus: 'activas', maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

### Uso vía MCP (agentes de IA) / MCP usage (AI agents)

Agrega el servidor MCP de Apify con este Actor como herramienta / add Apify's MCP server with this Actor as a tool:

```json
{
  "mcpServers": {
    "mercadopublico": {
      "url": "https://mcp.apify.com/?tools=better-llama/mercado-publico-chile",
      "headers": { "Authorization": "Bearer <APIFY_TOKEN>" }
    }
  }
}
```

Prompt de ejemplo: *"Busca licitaciones activas de la Región de Valparaíso sobre aseo y dame código, organismo, monto estimado y fecha de cierre."* El agente debe pasar tu ticket en el campo `ticket`; guárdalo como secreto en tu cliente y no lo incluyas en prompts compartidos.

El Actor usa permisos limitados (*limited permissions*), por lo que también es compatible con los pagos de agentes de Apify.

### Condiciones de uso de la API / API terms

Al usar este Actor aceptas cumplir las [Políticas y Condiciones de Uso de la API de Mercado Público](https://www.chilecompra.cl/api/), entre ellas:

- el ticket es **personal**: usa solo el tuyo, con tus datos reales;
- límite de **10.000 solicitudes diarias por ticket**, que no debes exceder ni eludir (este Actor espacia las solicitudes y corta en `maxItems`);
- para descargas masivas se recomienda el horario **22:00–07:00**;
- si publicas datos obtenidos sin modificarlos, debes indicar que la fuente es la **Dirección ChileCompra**.

ChileCompra puede modificar o suspender la API; la API de Compra Ágil está en versión beta. Revisa también la [Ley 19.628 / 21.719](https://www.bcn.cl/leychile/) si cruzas estos datos con datos personales.

### Limitaciones conocidas / Known limitations

- La API de Compra Ágil **no filtra por organismo**; `buyerRut` se aplica localmente (combínalo con `regions`).
- En Compra Ágil, `orden_compra.codigo_orden_compra` suele venir `null` aunque exista OC (documentado por ChileCompra).
- La API rechaza peticiones simultáneas (código 10500, HTTP 429) incluso con ~1 s entre inicios de solicitudes; el Actor mide el intervalo desde el **fin** de la respuesta anterior (2,5 s por defecto, porque con 1,5 s aún hubo rechazos en la nube) y reintenta. No bajes `requestIntervalMs` sin necesidad.
- Consulta por fecha (v1): la API devuelve los registros asociados a ese día según su propio criterio (en pruebas reales: publicadas, cerradas y adjudicadas ese día), no solo los publicados.
- `Fechas.FechaAdjudicacion` de la API trae la fecha *estimada* en licitaciones no adjudicadas; `awardedAt` solo se informa si la licitación está adjudicada.
- Estados no documentados observados: licitación `15` = Revocada; OC `5` = En proceso. Otros códigos se entregan con la glosa de la ficha (`statusEs`) o `null` en modo básico.
- La API de Compra Ágil (beta) puede responder `504 Endpoint request timed out` tras ~30 s; el Actor reintenta y, si persiste, termina con un error claro.
- **Proveedores persona natural:** la API no indica si el proveedor es persona natural o jurídica. Se usa la heurística habitual del RUT chileno (número < 50.000.000 = persona natural). Para personas naturales —o si el RUT no es interpretable— se ocultan nombre, RUT y código del proveedor, también en `raw` y en las adjudicaciones por línea de las licitaciones. Puede haber falsos positivos/negativos en casos excepcionales.
- Datos de pruebas: los tests usan fixtures construidos desde la documentación oficial (ver `test/fixtures/README.md`).

### Changelog

Ver / see [CHANGELOG.md](CHANGELOG.md).

# Changelog

This Actor's version history is a separate document: https://apify.com/better-llama/mercado-publico-chile/changelog.md

# Actor input Schema

## `ticket` (type: `string`):

Tu ticket personal de ChileCompra. Se guarda cifrado y solo se usa para tus consultas; nunca se registra en logs. Solicítalo en https://www.chilecompra.cl/api/ (Clave Única). / Your personal ChileCompra ticket, stored encrypted, never logged.

## `source` (type: `string`):

licitaciones = tenders (API v1); ordenes_compra = purchase orders (API v1); compra_agil = Compra Ágil (API v2, BETA — la API oficial está en beta y aún no se ha validado con datos reales en este Actor; puede fallar con 504).

## `codes` (type: `array`):

Opcional. Si se indican, se consulta la ficha de cada código e ignoran los demás filtros. Ej.: 1509-5-L114 (licitación), 1057532-156-AG26 (OC), 1057539-228-COT26 (Compra Ágil). / Optional: fetch these codes only.

## `dateFrom` (type: `string`):

YYYY-MM-DD, día calendario de Chile. Por defecto: hoy. Licitaciones/OC: una consulta por día; la API devuelve los registros asociados a esa fecha según su propio criterio (en pruebas reales incluye licitaciones publicadas, cerradas y adjudicadas ese día, no solo las publicadas). Compra Ágil: fecha de publicación. Máx. 31 días por ejecución.

## `dateTo` (type: `string`):

YYYY-MM-DD, inclusive. Por defecto igual a 'Desde' (o hoy).

## `tenderStatus` (type: `string`):

Solo para 'licitaciones'. 'activas' = todas las publicadas hoy (ignora fechas si no indicas fechas).

## `purchaseOrderStatus` (type: `string`):

Solo para 'ordenes_compra'. Valores tal como los publica la documentación oficial.

## `buyerCode` (type: `string`):

Licitaciones/OC: CodigoOrganismo numérico (ej. 6945). Se combina con la fecha.

## `supplierCode` (type: `string`):

Licitaciones/OC: CodigoProveedor numérico de Mercado Público (ej. 17793). No es el RUT.

## `agileStatuses` (type: `array`):

\[BETA] Solo para 'compra_agil'. Vacío = todos.

## `regions` (type: `array`):

\[BETA] Solo para 'compra_agil'. Región del organismo comprador. Vacío = todo Chile.

## `keyword` (type: `string`):

\[BETA] Solo para 'compra_agil': búsqueda en nombre/descripción (parámetro q de la API).

## `buyerRut` (type: `string`):

\[BETA] Solo para 'compra_agil'. La API v2 no filtra por organismo; este filtro se aplica localmente. Combínalo con una región para ahorrar cuota.

## `fetchDetails` (type: `boolean`):

Los listados por fecha solo traen datos básicos (código, nombre, estado, cierre). Activado: se consulta la ficha de cada resultado (organismo, montos, fechas). Usa 1 solicitud extra de tu cuota por resultado.

## `includeRaw` (type: `boolean`):

Agrega el campo 'raw' con el registro original de la API (sin datos personales de funcionarios/contactos).

## `maxItems` (type: `integer`):

Tope de resultados entregados (y cobrados) en esta ejecución.

## `requestIntervalMs` (type: `integer`):

Pausa mínima entre el fin de una respuesta y la siguiente solicitud. La API rechaza 'peticiones simultáneas' (10500) incluso con 1–1,5 s; 2500 ms es el valor por defecto tras pruebas reales.

## `maxRetries` (type: `integer`):

Reintentos con espera exponencial ante errores transitorios (red, 5xx, peticiones simultáneas).

## Actor input object example

```json
{
  "source": "licitaciones",
  "codes": [],
  "fetchDetails": true,
  "includeRaw": false,
  "maxItems": 50,
  "requestIntervalMs": 2500,
  "maxRetries": 4
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "codes": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("better-llama/mercado-publico-chile").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "codes": [] }

# Run the Actor and wait for it to finish
run = client.actor("better-llama/mercado-publico-chile").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "codes": []
}' |
apify call better-llama/mercado-publico-chile --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,better-llama/mercado-publico-chile"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/7IHrJcKyteYiNaJjK/builds/Jgxop3RXuVfqQVTKl/openapi.json
