# SECOP Contracts Colombia — Entity & Contractor History (`polyglot-data/secop-contracts`) Actor

Colombian public contracts by contractor or entity, SECOP I + II: value, payments and % paid, funding sources such as royalties, standard bidding docs, yearly summaries and new-contract alerts.

- **URL**: https://apify.com/polyglot-data/secop-contracts.md
- **Developed by:** [Polyglot Data](https://apify.com/polyglot-data) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 contract saveds

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

## SECOP Contracts Colombia — Entity & Contractor History

Get the **history of public contracts** in Colombia, from **SECOP II** (the current platform) and the **SECOP I**
archive, in one clean, typed feed. Look up a **contractor** (a company or a person) and see everything it has signed
with the state. Look up a **contracting entity** and see everything it has signed, with payments, funding sources and
execution status. Turn on **alert mode** to receive only the contracts that are new or changed since your last run.

Built for analysts, journalists, compliance and KYC teams, and contractors who research their competitors. It saves you
from reading the portal one contract at a time.

The data comes from the official open data of Colombia's public procurement agency (datos.gov.co). The actor uses
plain HTTP requests, so runs are fast and light.

### 🇪🇸 En español

Este actor saca el **historial de contratos públicos** de Colombia desde SECOP II y SECOP I: qué firmó un contratista o una entidad, por cuánto, cuándo y cuánto se ha pagado. Si buscas **contratos SECOP**, el **historial de contratos de un contratista** o los **contratos de una entidad pública**, lo tienes en un solo JSON, y cada fila lleva el enlace oficial al proceso.

Úsalo para:

- Revisar la experiencia de un contratista antes de firmar un convenio o de invitarlo a un proceso.
- **Consultar contratos por NIT** de una empresa, o de una entidad por nombre o NIT.
- Ver los contratos financiados con **regalías** (`fundingSources: ["royalties"]`) de una zona.
- Seguir los contratos de una entidad y detectar cambios de estado o de pagos.
- Hacer cumplimiento (compliance o KYC) o periodismo con fuentes oficiales.
- Estudiar a tu competencia: cuántos contratos tiene y con qué entidades.

Ejemplo para copiar y pegar (contratos de regalías de una entidad de Bogotá firmados desde 2025):

```json
{
  "entities": ["Bogotá"],
  "fundingSources": ["royalties"],
  "signedFrom": "2025-01-01",
  "maxItems": 200
}
```

Para alertas, pon `onlyNew` en `true`, ve a la pestaña **Schedules**, agrega un horario diario y conecta el resultado a Google Sheets, a un webhook o a un correo. Cada contrato guardado cuesta $0.002 USD; las filas sin cambios en el modo de alertas no se cobran.

***

### ✅ Why this actor

- **Two platforms, one history.** SECOP II and SECOP I are mapped to the same fields, so a contractor's history from
  the old archive and the current platform comes out as one list. You do not have to merge two exports yourself.
- **Profiles, not just searches.** Give a contractor's NIT or name and get every contract it holds. Give an entity's NIT
  or name and get every contract it signed. The history has no date limit when you search by contractor or entity.
- **Money, not only signatures.** For SECOP II contracts you get the value, the amount paid, invoiced and pending, the
  advance payment, the value still to execute, and the percentage already paid.
- **Who pays for what.** Each SECOP II contract has the funding sources in COP (national budget, general participation
  system, royalties, own territorial resources, credit, own resources), so you can see which works are funded by royalties.
- **Summary included.** A `SUMMARY` record in the key-value store totals contracts and values by contractor, by entity and
  by year, so you can see the biggest contractors and entities in one look.
- **Alert mode.** Run it on a daily schedule with `onlyNew` on. You get only contracts that are new, or whose status,
  payments or last update changed, since the previous run with the same filters. Unchanged contracts are skipped and not charged.
- **Clean data.** Values are numbers in COP, dates are `YYYY-MM-DD`, every contract has a direct link to SECOP, and
  missing values are `null`, never empty strings.
- **Open data, allowlist only.** The actor asks the open data API only for an allowlist of contract columns. Bank data,
  contact data, gender and the IDs of legal representatives and officials are never requested. See the Privacy section.
- **Pay per contract.** You pay only for contracts saved to the dataset. Error items and unchanged contracts are free.

***

### 📦 What data you get

Each item is one contract. Fields that exist only for one platform are `null` for the other.

| Field | Example | Notes |
|---|---|---|
| `source` | `SECOP II` | `SECOP II` or `SECOP I` |
| `contractId` | `CO1.PCCNTR.0000001` | Contract id (SECOP I: constancy number and contract number). Unique per contract |
| `contractReference` | `CTR-2026-0001` | Reference number of the contract |
| `processId` | `CO1.BDOS.0000001` | Purchase process the contract came from |
| `entity` | `Entidad Ejemplo Distrital` | Contracting entity |
| `entityNit` | `800000002` | Tax ID (NIT) of the entity. An institution, not a person |
| `entityOrder` | `Territorial` | `Nacional`, `Territorial` or `Corporación Autónoma` |
| `entitySector`, `entityBranch` | `Educación`, `Ejecutiva` | Sector and branch of the entity (SECOP II only) |
| `department` | `Bogotá D.C.` | Canonical department name, same spelling in both platforms |
| `city` | `Bogotá, D.C.` | Municipality of the entity. `null` when not reported |
| `contractor` | `CONSTRUCTORA EJEMPLO SAS` | Contractor name as published in the contract |
| `contractorIdType` | `NIT` | Type of the contractor's identification document, as published |
| `contractorId` | `900000001` | Contractor's identification number as published (NIT or document number) |
| `contractorKind` | `company` | `company` (NIT or foreign company), `person` (personal document) or `null` |
| `contractorIsGroup` | `false` | `true` for a consortium or temporary union (SECOP II only) |
| `contractorIsSme` | `true` | `true` when registered as SME (pyme or mipyme) |
| `legalRepresentative` | `PERSONA EJEMPLO` | Legal representative as published. Companies only, `null` for persons |
| `status` | `Activo` | Contract status as published by SECOP |
| `contractType` | `Obra` | Type of contract: works, services, supplies and so on |
| `modality` | `Licitación pública` | Procurement modality as published (Spanish) |
| `modalityGroup` | `licitacion` | Normalized group (see the modalities input) |
| `modalityJustification` | `null` | Justification of the modality (SECOP II only) |
| `object` | `Obra de mejoramiento de vía ...` | What is being bought or contracted |
| `unspscCode` | `72141100` | UNSPSC category code. `null` when UNSPECIFIED |
| `unspscGroupName`, `unspscFamily`, `unspscFamilyName`, `unspscClassName` | `null`, `7214`, `Servicios de construcción`, ... | UNSPSC hierarchy derived from the code |
| `value` | `2400000000` | Contract value in COP, including additions for SECOP I |
| `additionsValue` | `null` | Value of additions in COP (SECOP I only) |
| `paid`, `invoiced`, `pendingPayment`, `advancePayment`, `pendingExecution` | `1200000000` | Payments and execution in COP (SECOP II only) |
| `paidPct` | `50.0` | Percentage of the value already paid, one decimal (SECOP II only) |
| `daysAdded` | `0` | Days added to the contract term (SECOP II only) |
| `signedAt` | `2026-03-02` | Signing date |
| `startAt`, `endAt` | `2026-03-16`, `2027-03-15` | Execution start and end dates |
| `duration` | `360 Días` | Contract term as published |
| `extendable`, `liquidated` | `true`, `false` | Whether the contract can be extended and whether it has been liquidated (SECOP II only) |
| `fundingOrigin` | `Recursos propios` | Origin of the funds as published (SECOP II only) |
| `spendingDestination` | `Inversión` | Destination of the spending as published |
| `funding` | `{"ownTerritorial": 2400000000}` | Non-zero funding sources in COP: `pgn`, `sgp`, `royalties`, `ownTerritorial`, `credit`, `own`. `null` when none (SECOP II only) |
| `bpinCode` | `null` | BPIN investment project code (SECOP I only) |
| `standardBiddingDocs` | `Ejemplo de pliego tipo` | Standard bidding documents: the type as text when used, `false` when not, `null` when unknown |
| `supervisor` | `SUPERVISOR EJEMPLO` | Contract supervisor, name only (SECOP II only) |
| `spendingOfficer` | `ORDENADOR EJEMPLO` | Spending officer, name only (SECOP II only) |
| `lastUpdatedAt` | `2026-09-30` | Date of the last update on SECOP |
| `url` | `https://community.secop.gov.co/...` | Direct link to the contract page on SECOP |
| `changeType` | `null` | Alert mode only: `new` or `updated`. `null` when alert mode is off |
| `scrapedAt` | `2026-10-10T14:00:00.000Z` | UTC timestamp of the run |

**Missing values are `null`.** SECOP I has no payment, execution or funding columns, so those fields are `null` for
SECOP I contracts. Check `signedAt` and `lastUpdatedAt` for recency.

#### Example item: SECOP II contract with payments and funding

```json
{
  "source": "SECOP II",
  "contractId": "CO1.PCCNTR.0000001",
  "contractReference": "CTR-2026-0001",
  "processId": "CO1.BDOS.0000001",
  "entity": "Entidad Ejemplo Distrital",
  "entityNit": "800000002",
  "entityOrder": "Territorial",
  "entitySector": "Educación",
  "entityBranch": "Ejecutiva",
  "department": "Bogotá D.C.",
  "city": "Bogotá, D.C.",
  "contractor": "CONSTRUCTORA EJEMPLO SAS",
  "contractorIdType": "NIT",
  "contractorId": "900000001",
  "contractorKind": "company",
  "contractorIsGroup": false,
  "contractorIsSme": true,
  "legalRepresentative": "PERSONA EJEMPLO",
  "status": "Activo",
  "contractType": "Obra",
  "modality": "Licitación pública",
  "modalityGroup": "licitacion",
  "modalityJustification": null,
  "object": "Obra de mejoramiento de vía terciaria en el sector de ejemplo. Datos ilustrativos.",
  "unspscCode": "72141100",
  "unspscGroupName": null,
  "unspscFamily": "7214",
  "unspscFamilyName": "Servicios de construcción",
  "unspscClassName": "Servicios de construcción de caminos",
  "value": 2400000000,
  "additionsValue": null,
  "paid": 1200000000,
  "invoiced": 1200000000,
  "pendingPayment": 0,
  "advancePayment": 480000000,
  "pendingExecution": 1200000000,
  "paidPct": 50.0,
  "daysAdded": 0,
  "signedAt": "2026-03-02",
  "startAt": "2026-03-16",
  "endAt": "2027-03-15",
  "duration": "360 Días",
  "extendable": true,
  "liquidated": false,
  "fundingOrigin": "Recursos propios",
  "spendingDestination": "Inversión",
  "funding": { "ownTerritorial": 2400000000 },
  "bpinCode": null,
  "standardBiddingDocs": "Ejemplo de pliego tipo",
  "supervisor": "SUPERVISOR EJEMPLO",
  "spendingOfficer": "ORDENADOR EJEMPLO",
  "lastUpdatedAt": "2026-09-30",
  "url": "https://community.secop.gov.co/Public/Tendering/ContractNoticePhases/View?PPI=CO1.PPI.0000001",
  "changeType": null,
  "scrapedAt": "2026-10-10T14:00:00.000Z"
}
```

#### Example item: SECOP I contract (history)

```json
{
  "source": "SECOP I",
  "contractId": "CONSTANCIA-0000002/CONTRATO-0000002",
  "contractReference": "CONTRATO-0000002",
  "processId": "PROCESO-0000002",
  "entity": "Entidad Ejemplo Departamental",
  "entityNit": "800000003",
  "entityOrder": "Departamental",
  "entitySector": null,
  "entityBranch": null,
  "department": "Antioquia",
  "city": "Ejemplo",
  "contractor": "SUMINISTROS EJEMPLO LTDA",
  "contractorIdType": "NIT",
  "contractorId": "900000003",
  "contractorKind": "company",
  "contractorIsGroup": null,
  "contractorIsSme": false,
  "legalRepresentative": "PERSONA EJEMPLO DOS",
  "status": "Terminado",
  "contractType": "Suministros",
  "modality": "Licitación Pública",
  "modalityGroup": "licitacion",
  "modalityJustification": null,
  "object": "Suministro de equipos de cómputo para colegios.",
  "unspscCode": "43211500",
  "unspscGroupName": null,
  "unspscFamily": "4321",
  "unspscFamilyName": "Equipos de tecnología de la información",
  "unspscClassName": "Computadores",
  "value": 480000000,
  "additionsValue": 0,
  "paid": null,
  "invoiced": null,
  "pendingPayment": null,
  "advancePayment": null,
  "pendingExecution": null,
  "paidPct": null,
  "daysAdded": null,
  "signedAt": "2019-06-10",
  "startAt": "2019-06-20",
  "endAt": "2019-12-19",
  "duration": "6 meses",
  "extendable": null,
  "liquidated": null,
  "fundingOrigin": null,
  "spendingDestination": null,
  "funding": null,
  "bpinCode": null,
  "standardBiddingDocs": null,
  "supervisor": null,
  "spendingOfficer": null,
  "lastUpdatedAt": "2020-01-15",
  "url": "https://www.contratos.gov.co/consultas/detalleProceso.do?numConstancia=0000002",
  "changeType": null,
  "scrapedAt": "2026-10-10T14:00:00.000Z"
}
```

The names, NITs, entities and links above are invented for illustration.

#### Summary record

Unless you turn off **Save summary**, the run saves a `SUMMARY` record in the default key-value store. It is not
charged and it is not in the dataset. It covers the contracts saved in that run:

```json
{
  "generatedAt": "2026-10-10T14:00:00.000Z",
  "totalContracts": 2,
  "totalValue": 2880000000,
  "byContractor": [
    { "contractor": "CONSTRUCTORA EJEMPLO SAS", "contractorId": "900000001", "contracts": 2, "totalValue": 2880000000, "entities": 1, "firstSigned": "2019-06-10", "lastSigned": "2026-03-02" }
  ],
  "byEntity": [
    { "entity": "Entidad Ejemplo Distrital", "entityNit": "800000002", "contracts": 1, "totalValue": 2400000000, "contractors": 1 }
  ],
  "byYear": [
    { "year": 2026, "contracts": 1, "totalValue": 2400000000 }
  ]
}
```

`byContractor` and `byEntity` keep the top 100 each. `contractors` and `entities` count the distinct parties.

#### ⚠️ Error items

If an input produces nothing or cannot run, the actor saves an error item instead of failing silently.
Error items are **never charged**.

```json
{ "error": "NO_RESULTS", "note": "No contracts match these filters. Try a wider date window or fewer keywords.", "input": { "contractors": ["900000009"] } }
```

| error | Meaning | What to do |
|---|---|---|
| `NO_RESULTS` | Nothing matched the filters. The echoed input is in `input` | Check the NIT or name, widen `signedFrom` or remove a filter |
| `SOURCE_ERROR` | One platform could not be read after 3 retries. The source is named in the item | Run again later. The other platform's results are still saved |
| `INVALID_INPUT` | The input cannot be used, e.g. `minValue` greater than `maxValue`, a bad date, or no filter and no date window | Fix the field named in the note |

***

### 🎯 Use cases

- **Contractor profile (due diligence and KYC):** give a company's NIT and get every contract it has signed with public
  entities: entities, values, payments, status and dates. A complete picture before you sign a subcontract or a supplier
  agreement. Check `contractorKind` and `contractorIsGroup` to tell a company from a consortium.
- **Everything an entity signed (journalism and oversight):** give an entity's name or NIT and get its contracts over
  any period, with the contractors it chose, the values and the paid percentage. A city government in Cali or
  Barranquilla, or a department government in Antioquia, works the same way. Use `byContractor` in the summary to
  find the firms that win the most.
- **Who gets royalty-funded works (regional analysis):** set `fundingSources` to `royalties`, with `contractTypes` set to
  `Obra` and the departments you follow. The `funding` object of each contract gives the amount per source in COP.
- **Competitor research for contractors:** give the NITs of your main competitors and see which entities they work for,
  how big their contracts are and how much they have executed.
- **Payment risk for suppliers:** track `paidPct`, `pendingPayment` and `status` for a contractor's open contracts to see
  whether the state is paying on time.
- **Dashboards and BI:** feed the dataset into Google Sheets, Power BI or your own database through the API.

***

### 🚀 How to use

1. Choose what to search: **contractors** (NIT or name), **contracting entities** (name or NIT), **keywords** in the
   contract object, or a combination.
2. Choose the **sources**. Both SECOP II and SECOP I are on by default, so you get the full history.
3. Narrow the results with **contract types**, **departments**, **modalities**, the value range, or **Signed from / to**.
4. Set **Max items**, click **Start**, then download the results as JSON, CSV, Excel or HTML, or connect them to Google Sheets.

**Date window.** When you give no contractor and no entity, the default is the last 365 days, so a run is never an
open-ended scan of the whole archive. When you give a contractor or an entity, there is no date limit unless you set
**Signed from** or **Signed to**. Profiles need the full history.

#### Tips for entity and contractor searches

- **Entity names differ between platforms.** The same institution can be written with its acronym in SECOP II and with
  its full name in SECOP I (for example, `EJEM` in one and `Entidad Ejemplo Departamental` in the other). A name search
  only finds the spelling it matches, so it can miss part of the history.
- **Search entities and contractors by NIT for the complete history.** The NIT is the same on both platforms. Put the
  digits in `entities` or `contractors`, with or without the check digit (`800000003` or `800000003-1`).
- **SECOP II stores the NIT without its check digit.** The actor handles this for you, so paste the NIT as it appears
  in the contract. A 10-digit number that includes the check digit also matches in SECOP II.

#### How to pull the full history of one contractor

```json
{
  "contractors": ["900000001"],
  "sources": ["secop2", "secop1"],
  "maxItems": 500
}
```

A NIT with its check digit also works (`900000001-1`). To search by name, use part of the name. Accents are ignored.

#### How to see everything one entity signed since 2024

```json
{
  "entities": ["Bogotá"],
  "sources": ["secop2", "secop1"],
  "signedFrom": "2024-01-01",
  "maxItems": 1000
}
```

An entity name is matched as part of the name, so `Bogotá` also matches other entities with that word in their name.
The same works for any city, for example `Cali` or `Barranquilla`. To match one institution exactly, use its NIT digits
instead (see the tips above).

#### How to find royalty-funded works in a region

```json
{
  "fundingSources": ["royalties"],
  "departments": ["Antioquia"],
  "contractTypes": ["Obra"]
}
```

A contract is kept when its royalties amount is greater than zero. The run covers SECOP II only, because SECOP I has no
funding columns. Without a contractor or entity, the default window is the last 365 days; add `signedFrom` for more history.

#### How to check a company's history for compliance

```json
{
  "contractors": ["900000001"],
  "contractorKind": "company",
  "sources": ["secop2", "secop1"],
  "maxItems": 500
}
```

#### Default input (daily sample)

```json
{
  "contractTypes": ["Obra"],
  "maxItems": 10
}
```

With no contractor and no entity, this saves the last 365 days of works contracts, up to 10.

#### Input fields

| Field | Type | Default | Description |
|---|---|---|---|
| `contractors` | string\[] | `[]` | NIT or document digits (a NIT with its check digit also works), or part of the name. Accents ignored for names |
| `entities` | string\[] | `[]` | Part of the entity name, or the entity's NIT digits (exact match in SECOP II, prefix match in SECOP I; check digit optional) |
| `keywords` | string\[] | `[]` | Words to find in the contract object or description. Accents ignored. A contract is kept if any keyword matches |
| `sources` | select\[] | `["secop2", "secop1"]` | `secop2` (current platform), `secop1` (historical archive) |
| `contractTypes` | string\[] | `[]` (all) | Contract type as published, e.g. `Obra`, `Servicios`, `Suministros`, `Compraventa`, `Consultoría` |
| `modalities` | select\[] | All eight groups | Procurement method. Unselect groups to narrow the results |
| `departments` | select\[] | `[]` (all) | One or more of the 33 Colombian departments, including Bogotá D.C. |
| `fundingSources` | select\[] | `[]` (no filter) | Keep contracts with a positive amount in at least one of: `pgn`, `sgp`, `royalties`, `ownTerritorial`, `credit`, `own`. SECOP II only: SECOP I is skipped when set |
| `contractorKind` | string | `any` | `any`, `company` (NIT) or `person` (personal document) |
| `onlyStandardBiddingDocs` | boolean | `false` | Keep only contracts whose bidding documents were marked as standard |
| `minValue` / `maxValue` | integer | none | Contract value range in COP |
| `signedFrom` / `signedTo` | date | none | Signing date range (`YYYY-MM-DD`). Empty with no contractor or entity means the last 365 days |
| `maxItems` | integer | `1000` | Maximum number of contracts to save per run |
| `onlyNew` | boolean | `false` | Alert mode: save only new or changed contracts since the last run with the same filters |
| `includeSummary` | boolean | `true` | Save the `SUMMARY` record in the key-value store. Not charged |
| `appToken` | string (secret) | empty | Optional datos.gov.co app token for heavy use |

***

### 🔔 Alert mode and schedules

Alert mode is for watching a contractor or an entity over time. Set `onlyNew` to `true` and add a daily schedule.

```json
{
  "contractors": ["900000001"],
  "onlyNew": true,
  "maxItems": 100
}
```

- The first run with a given set of filters saves every matching contract and marks it as `new`.
- Later runs save only contracts that are new, or whose status, payments or last update changed (the fingerprint is
  `lastUpdatedAt`, `status` and `paid`). Those rows have `changeType` set to `new` or `updated`. Everything else is
  skipped and not charged.
- Each filter set keeps its own history. Changing a filter starts a new history, so the next run saves everything again.
- To receive alerts, turn on the **Schedules** tab and add a daily schedule. Then connect the dataset to Google Sheets,
  a webhook, e-mail or the API.

***

### 🔌 Integrations, API & MCP

- **Schedules:** run it every day from the Schedules tab. Alert mode works best with a daily schedule.
- **Webhooks, Make, Zapier, n8n, Google Sheets:** send results anywhere when a run finishes.
- **API:** start a run and get the items in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/polyglot-data~secop-contracts/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"contractors":["900000001"],"maxItems":50}'
```

- **MCP:** the actor can be used from any MCP-compatible AI assistant through the Apify MCP server. Ask the assistant to
  run `Polyglot-Data/secop-contracts` with your input, and it gets the dataset items back as JSON that it can summarize
  or compare.

***

### 💰 Pricing

**Pay per result:** you pay **$0.002 for each contract** saved to the dataset (see the **Pricing** tab), plus Apify
platform usage. There is no monthly rental. Error items and unchanged contracts in alert mode are never charged. The
`SUMMARY` record is not charged.

**Platform usage (measured Oct 2026):** a 300-contract entity history takes about 2 seconds at 256 MB, and a 10-contract run costs about $0.0001 in platform usage. No proxy is used.

***

### 🔒 Privacy

This actor is built to collect the least personal data needed to describe a public contract.

**Personal fields included.** These are published in the contract itself, and the actor copies them as published:

- **Contractor name and identification number** as published in the contract. For a company, this is its name and NIT.
  For a natural person who has a contract with the state, it is their name and document number.
- **Legal representative name**, for companies only. Persons have `null` in this field.
- **Supervisor and spending officer names**, as published. Names only.

**Personal fields never requested.** The actor's request to the open data API uses an allowlist, and these columns are
not in it:

- **Bank data:** bank name, account type and account number.
- **Contact data:** e-mail addresses, phone numbers and postal addresses of contractors, representatives or officials.
- **Gender** of contractors, legal representatives or officials.
- **Nationality and domicile** of legal representatives.
- **ID numbers of legal representatives, supervisors and spending officers.**

Entity NIT codes are the tax IDs of public institutions. They are not personal data.

You are responsible for how you use the data. If you combine it with other records, or publish profiles of people,
check Colombian data protection rules (Ley 1581 de 2012) and your own compliance policy first.

***

### ❓ FAQ

**Which platforms are covered?**
Both. SECOP II, where Colombian entities register contracts today, and SECOP I, the previous platform that holds the
archive (mostly contracts up to 2021). Both are searched by default. Remove `secop1` from `sources` for current contracts only.

**Why do I get more history with a contractor than with a keyword search?**
A contractor or entity search has no date limit by default, so you get the full history. A keyword-only search uses the
last 365 days unless you set **Signed from**.

**Why is `paid` empty for some contracts?**
SECOP I has no payment columns, so `paid`, `invoiced`, `pendingPayment`, `advancePayment` and `pendingExecution` are
always `null` for SECOP I contracts. For SECOP II, a field is `null` when the entity did not report it.

**Why do I see `contractorKind` as `null`?**
The contractor's identification type is not one the actor recognizes as a company or a person. The raw type is in
`contractorIdType` so you can check it.

**How do I find the royalty-funded works?**
Set `fundingSources` to `royalties`, and combine it with `contractTypes` and `departments`. Only SECOP II has funding
columns, so SECOP I is skipped for that run.

**Can I find the contracts of a company by its NIT?**
Yes. Put the NIT digits in `contractors`. A NIT with its check digit also works. Use the name when you do not have the NIT.

**Why do two entities with the same name appear?**
Entity names are not unique in SECOP. Use `entityNit` to tell them apart, or search by the NIT digits in `entities`.

**What is the difference between `contractorIsGroup` and `contractorKind`?**
`contractorKind` says whether the contractor is a company or a person. `contractorIsGroup` says whether it is a
consortium or temporary union, which is a company or a group of companies. It is only filled for SECOP II.

**What is the difference between `value` and `paid`?**
`value` is the total contract value in COP, including additions for SECOP I. `paid` is the amount paid so far, which
exists for SECOP II only. `paidPct` is `paid` divided by `value`.

**Where does the data come from?**
From the open data published on datos.gov.co by the national public procurement agency, ANCP–Colombia Compra Eficiente.
The data is updated by SECOP as contracts change, so a run shows the state of the platform at that moment.

**Something is wrong or a field is missing?**
Open an issue in the **Issues** tab with the input you used. Issues are answered quickly.

**¿Funciona en español?**
Sí. Los campos de entrada aceptan palabras en español, con o sin tildes (por ejemplo, `obra` o `Bogotá`). Los datos llegan en español tal como los publica SECOP.

***

### ⚖️ Legal

This actor reads public contract data that SECOP publishes as open data on datos.gov.co. Contract information about
public spending is public under Ley 1712 de 2014 (transparency and access to public information). The actor collects
only the contract fields listed above, and it never requests bank, contact or gender data.

**Attribution and license.** The source data is published by the Agencia Nacional de Contratación Pública – Colombia
Compra Eficiente (ANCP–CCE) under CC BY-SA 4.0. If you publish or redistribute the results, credit ANCP–Colombia
Compra Eficiente as the source, and check the ShareAlike terms for any derived dataset.

You are responsible for making sure your use complies with the terms of datos.gov.co and SECOP, with applicable law,
and with Colombian data protection rules (Ley 1581 de 2012) if you combine the data with other records or publish
information about individuals.

# Actor input Schema

## `contractors` (type: `array`):

Contractors to profile: a NIT or document number (digits only; a NIT with its check digit also works) or part of the contractor's name. Accents are ignored for names. Leave empty to search by entity, keyword or other filters.

## `entities` (type: `array`):

Contracting entities to profile: part of the entity name (e.g. "Bogotá") or the entity's NIT digits (exact match in SECOP II, prefix match in SECOP I; with or without the check digit). An entity NIT is the tax ID of a public institution, not a person's ID.

## `keywords` (type: `array`):

Words to find in the contract object or description. Accents are ignored, so "construccion" also matches "construcción". A contract is kept if any keyword matches.

## `sources` (type: `array`):

SECOP II holds the contracts signed on the current platform. SECOP I is the previous platform and holds the history (mostly contracts up to 2021). Keep both for full contractor and entity histories.

## `contractTypes` (type: `array`):

Contract type as published by SECOP, e.g. "Obra" (works), "Servicios", "Suministros", "Compraventa" or "Consultoría". Leave empty for all types.

## `modalities` (type: `array`):

Procurement method used to sign the contract. All eight groups are included by default. Unselect groups to narrow the results.

## `departments` (type: `array`):

Department of the contracting entity. Leave empty for all of Colombia. Municipality-level filters are not available.

## `fundingSources` (type: `array`):

SECOP II only: keep contracts with a positive amount in at least one of these funding sources. When set, SECOP I is skipped because it has no funding columns. Empty means no funding filter.

## `contractorKind` (type: `string`):

Filter by the kind of contractor. "Companies" keeps NIT holders, "Persons" keeps natural persons identified by a personal document. "Any" keeps both.

## `onlyStandardBiddingDocs` (type: `boolean`):

Keep only contracts whose bidding documents were marked as standard (pliegos tipo). Contracts without that information are dropped when this is on.

## `minValue` (type: `integer`):

Keep contracts with a value of at least this amount, in Colombian pesos (COP). Empty means no minimum.

## `maxValue` (type: `integer`):

Keep contracts with a value of at most this amount, in Colombian pesos (COP). Empty means no maximum.

## `signedFrom` (type: `string`):

Only contracts signed on or after this date (YYYY-MM-DD). Empty with no contractor or entity set means the last 365 days. When a contractor or an entity is set, the history has no date limit unless you fill this field or the next one.

## `signedTo` (type: `string`):

Only contracts signed on or before this date (YYYY-MM-DD).

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

Maximum number of contracts to save in one run.

## `onlyNew` (type: `boolean`):

Save only contracts that are new, or whose status, payments or last update changed since the previous run with the same filters. Combine with a daily schedule to get alerts. The first run saves everything. Unchanged contracts are not charged.

## `includeSummary` (type: `boolean`):

Save a SUMMARY record in the key-value store with totals by contractor, by entity and by year. The summary is not charged.

## `appToken` (type: `string`):

Optional datos.gov.co app token. It raises the rate limit for heavy use. Leave empty for normal runs.

## Actor input object example

```json
{
  "contractors": [],
  "entities": [],
  "keywords": [],
  "sources": [
    "secop2",
    "secop1"
  ],
  "contractTypes": [
    "Obra"
  ],
  "modalities": [
    "licitacion",
    "seleccion_abreviada",
    "minima_cuantia",
    "concurso_meritos",
    "con_ofertas",
    "regimen_especial",
    "contratacion_directa",
    "otros"
  ],
  "departments": [],
  "fundingSources": [],
  "contractorKind": "any",
  "onlyStandardBiddingDocs": false,
  "maxItems": 10,
  "onlyNew": false,
  "includeSummary": true
}
```

# Actor output Schema

## `contracts` (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 = {
    "contractTypes": [
        "Obra"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("polyglot-data/secop-contracts").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 = {
    "contractTypes": ["Obra"],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("polyglot-data/secop-contracts").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 '{
  "contractTypes": [
    "Obra"
  ],
  "maxItems": 10
}' |
apify call polyglot-data/secop-contracts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,polyglot-data/secop-contracts"
        }
    }
}
```

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/ZZZ1KZadxUCbCCMwQ/builds/4OsWV8mgD7eBWH0th/openapi.json
