# SECOP II Colombia Tenders Scraper (`automatic/secop-tenders-scraper`) Actor

Colombian public tenders from SECOP II: open tenders by default, with buyer, department, city, method, UNSPSC codes, estimated value, deadlines, days left and document links. Filter by keyword, buyer, region, method and date for daily tender alerts.

- **URL**: https://apify.com/automatic/secop-tenders-scraper.md
- **Developed by:** [Philip Kirkbride](https://apify.com/automatic) (community)
- **Categories:** Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 tenders

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 II Colombia Tenders Scraper

Find Colombian public tenders on SECOP II, the national e-procurement system run by Colombia Compra Eficiente, and get one clean row per tender: title, buying entity and its tax id, department and city, procurement method, contract type, status, UNSPSC category codes, estimated value in pesos, publication date, deadline for offers, days left and the link to the official notice. Turn on details to add the tender documents (specifications, studies, annexes) with download links and a description excerpt.

By default you get only tenders that are still open: published on SECOP II, with offers accepted until today or later. Drafts that are not public yet are left out. Schedule a daily run with "published or changed since 2 days" and your keywords, buyer or department to get alerts for new tenders in email, Slack or a spreadsheet.

For contracts that have already been awarded and the companies that won them, see our Colombia SECOP Contracts + Supplier Company Profiles actor.

### Quick start

Open tenders, newest first:

```json
{"maxItems": 20}
```

Open security-services tenders in Antioquia, closing soonest first:

```json
{"keywords": ["vigilancia"], "department": "Antioquia", "sort": "deadlineSoonest"}
```

New construction tenders above 1,000 million pesos, with documents:

```json
{"categoryCodes": ["72"], "minEstimatedValue": 1000000000, "publishedSince": "2 days", "includeDetails": true}
```

### Input

| Field | Type | Default | What it does |
|---|---|---:|---|
| `keywords` | list | `[]` | Words searched in the tender title, description and buyer, accents optional (`energia` finds `energía`). Several keywords return tenders that match any of them. |
| `status` | string | `open` | `open` (published, deadline for offers today or later), `closed`, `awarded`, `cancelled` or `all`. |
| `publishedSince` | date | none | Only tenders published or updated on or after this date, e.g. `2026-11-01`, or within a period such as `2 days`. |
| `buyer` | string | `""` | Buying entity: part of its name, case and accents ignored (`policia`), or its tax id (NIT, digits only). |
| `department` | string | `""` | Department of the buyer, e.g. `Antioquia`, `Valle del Cauca`, `Bogotá`. Accents optional. |
| `city` | string | `""` | City of the buyer, the whole name, e.g. `Medellín` or `Pasto`. Accents optional. |
| `procurementMethods` | list | all competitive | Public tender, abbreviated selection, reverse auction, merit contest, minimum value, special regime with offers, direct contracting with offers, request for information or sale of state assets. Direct contracting and special-regime awards without competition are only included when you select them. |
| `categoryCodes` | list | `[]` | UNSPSC code prefixes, 2 to 8 digits, e.g. `72` (building and construction) or `81112000`. |
| `minEstimatedValue` | integer | none | Only tenders with a published estimated value of at least this many pesos. |
| `sort` | string | `newest` | `newest` or `deadlineSoonest`. |
| `maxItems` | integer | `50` | Maximum tenders returned, up to 10,000. |
| `includeDetails` | boolean | `false` | Add the tender documents and a description excerpt. |

### What it returns

Every row has `tenderId`, `reference`, `noticeId`, `portfolioId`, `title`, `buyer` (`name`, `taxId`, `entityCode`, `level`, `unit`), `country`, `region`, `city`, `procurementMethod`, `contractType`, `status` (`open`, `closed`, `awarded` or `cancelled`), `sourceStatus`, `phase`, `categoryScheme`, `categoryCodes`, `estimatedValue`, `awardedValue`, `currency`, `publishedDate`, `lastPublishedDate`, `deadlineDate`, `daysUntilDeadline`, `offersOpeningDate`, `datesTimezone`, `duration`, `durationUnit`, `lots`, `url`, `source` and `scrapedAt`.

With `includeDetails` on, rows also fill `descriptionExcerpt` (up to 600 characters) and `documents` (each with `documentId`, `name`, `fileType`, `sizeBytes` and `url`). If documents cannot be read for a row, the row is still delivered and `detailsError` says why.

Dates are calendar dates in Bogotá (`YYYY-MM-DD`, UTC-5): SECOP II publishes the day of the deadline, not the hour, so check the official notice for the closing time. `daysUntilDeadline` is 0 when offers close today. Values are numbers in Colombian pesos (COP).

### What can be empty, and why

- `estimatedValue` is empty when the buyer did not publish a budget, for example on requests for information.
- `categoryCodes` is empty when the buyer did not classify the tender; many open tenders carry no code, so a category filter returns fewer tenders than a keyword search.
- `city` and `region` are empty when SECOP II does not say where the buyer is.
- `publishedDate` is empty for a small share of tenders that SECOP II lists without one.
- `title` is empty when the source has no title.
- `documents` is empty for tenders whose files SECOP II has not listed yet; newly published tenders can take a day or two.

### Limits

- The official open-data copy of SECOP II is updated daily and usually runs one or two days behind the portal. A tender published this morning may appear tomorrow.
- Runs are quick: 500 tenders took about 3 seconds in our tests, and 300 tenders with documents about 15 seconds.
- Up to 10,000 tenders per run. For more, split the search by department, method or date.

### Published information

Titles, references, descriptions and document names retain the public text published by the buyer, including contact information where present.

### FAQ

**How do I get only new tenders each day?** Schedule a daily run with `publishedSince: "2 days"` and your filters, and deduplicate on `tenderId`. Each run is independent, so overlapping windows deliver (and charge for) the same tenders again.

**What happens when nothing matches?** The run succeeds with an empty dataset and a status message saying no tenders matched.

### Pricing

See the Pricing tab for the current price. The start charge is per GB of memory, rounded up; the default 512 MB run is one start.

### Output example

```json
{"tenderId": "CO1.REQ.11296787", "reference": "MC-RDC-CGA-009-2026", "noticeId": "CO1.NTC.11160203", "portfolioId": "CO1.BDOS.11107663", "title": "Contratar la compra de insumos de tóner originales; necesarios para el adecuado funcionamiento de las dependencias del Centro de Gestión Administrativa.", "buyer": {"name": "SENA-GRUPO DE APOYO ADMINITRATIVO INTERCENTROS CGA Y CFAFC", "taxId": "899999034", "entityCode": "724589023", "level": "Nacional", "unit": "CENTRO DE GESTIÓN ADMINISTRATIVA"}, "country": "CO", "region": "Distrito Capital de Bogotá", "city": "Bogotá", "procurementMethod": "Mínima cuantía", "contractType": "Suministros", "status": "open", "sourceStatus": "Aprobado", "phase": "Presentación de oferta", "categoryScheme": null, "categoryCodes": [], "estimatedValue": 8487000.0, "awardedValue": null, "currency": "COP", "publishedDate": "2026-11-01", "lastPublishedDate": "2026-11-01", "deadlineDate": "2026-11-09", "daysUntilDeadline": 6, "offersOpeningDate": "2026-11-09", "datesTimezone": "America/Bogota", "duration": 30, "durationUnit": "days", "lots": null, "url": "https://community.secop.gov.co/Public/Tendering/OpportunityDetail/Index?noticeUID=CO1.NTC.11160203", "descriptionExcerpt": "Contratar la compra de insumos de tóner originales, necesarios para el adecuado funcionamiento de las dependencias del Centro de Gestión Administrativa.", "documents": [{"documentId": "884186459", "name": "1. DESIGNACION COMUNICACION FUNCIONARIOS Y CONTRATISTAS TONNER (1) (1).pdf", "fileType": "pdf", "sizeBytes": 179651, "url": "https://community.secop.gov.co/Public/Archive/RetrieveFile/Index?DocumentId=884186459&InCommunity=False&InPaymentGateway=False&DocUniqueIdentifier="}, {"documentId": "884186460", "name": "2. SOLCIITUD INICIO PROCESO CONTRATCTUAL.pdf", "fileType": "pdf", "sizeBytes": 190189, "url": "https://community.secop.gov.co/Public/Archive/RetrieveFile/Index?DocumentId=884186460&InCommunity=False&InPaymentGateway=False&DocUniqueIdentifier="}], "detailsError": null, "source": "SECOP II (Colombia Compra Eficiente)", "scrapedAt": "2026-11-03T17:13:59.812155+00:00"}
```

### Support

For questions or issues, contact us from the Actor page.

# Actor input Schema

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

Words searched in the tender (title, description, buyer), accents optional, e.g. 'mantenimiento' or 'vigilancia'. Several keywords return tenders matching any of them. Up to 10.

## `status` (type: `string`):

open: still accepting offers (deadline today or later in Bogotá). closed, awarded, cancelled or all.

## `publishedSince` (type: `string`):

Only tenders published or updated on or after this date (YYYY-MM-DD), or within a period such as 2 days. Use it for daily monitoring.

## `buyer` (type: `string`):

Buying entity: part of its name (case and accents ignored, e.g. 'policia') or its tax id (NIT, digits only).

## `department` (type: `string`):

Department (region) of the buyer, e.g. Antioquia, Valle del Cauca, Bogotá. Accents optional.

## `city` (type: `string`):

City of the buyer, e.g. Medellín or Cali. Accents optional; the whole city name.

## `procurementMethods` (type: `array`):

Leave empty for every competitive method. Direct contracting and special-regime awards without offers are only returned when selected here.

## `categoryCodes` (type: `array`):

UNSPSC code prefixes, 2 to 8 digits, e.g. 72 (construction) or 81112000. Only tenders whose buyer published a matching code are returned.

## `minEstimatedValue` (type: `integer`):

Only tenders with a published estimated value of at least this many pesos.

## `sort` (type: `string`):

Order of the results.

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

Maximum tenders to return.

## `includeDetails` (type: `boolean`):

Add the tender documents (download links) and a description excerpt to each row. Slightly slower.

## Actor input object example

```json
{
  "keywords": [],
  "status": "open",
  "buyer": "",
  "department": "",
  "city": "",
  "procurementMethods": [],
  "categoryCodes": [],
  "sort": "newest",
  "maxItems": 20,
  "includeDetails": false
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": [],
    "buyer": "",
    "department": "",
    "city": "",
    "categoryCodes": [],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automatic/secop-tenders-scraper").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 = {
    "keywords": [],
    "buyer": "",
    "department": "",
    "city": "",
    "categoryCodes": [],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automatic/secop-tenders-scraper").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 '{
  "keywords": [],
  "buyer": "",
  "department": "",
  "city": "",
  "categoryCodes": [],
  "maxItems": 20
}' |
apify call automatic/secop-tenders-scraper --silent --output-dataset

```

## MCP server setup

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

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/tJgLgZlufvoedkBA6/builds/BN0pKXkm6pLNEy7Su/openapi.json
