# LatAm Public Tenders: Colombia SECOP II and Brazil PNCP (`ceibadata/latam-public-tenders`) Actor

Get new government tenders from Colombia (SECOP II) and Brazil (PNCP) in one clean schema: buyer, object, method, estimated value, deadlines and link. Keyword, state and value filters, plus an "only new since last run" mode for daily alerts.

- **URL**: https://apify.com/ceibadata/latam-public-tenders.md
- **Developed by:** [Ceiba Data](https://apify.com/ceibadata) (community)
- **Categories:** Lead generation, Agents
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 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

## LatAm Public Tenders: Colombia SECOP II and Brazil PNCP

Get new government tenders from **Colombia (SECOP II)** and **Brazil (PNCP, Portal Nacional de Contratações Públicas)** in one clean, OCDS-like schema. Filter by keyword, state or department and estimated value, keep only tenders still open for bids, and turn on **Only new since my last run** to get a daily alert feed without duplicates.

| Country | Source | What you get |
|---|---|---|
| 🇨🇴 Colombia | SECOP II processes, official open data on datos.gov.co | Entity and NIT, process id and reference, object, modality, contract type, base price in COP, publication date, bid deadline, status, link to the SECOP notice |
| 🇧🇷 Brazil | PNCP official consultation API (Lei 14.133/2021) | Agency and CNPJ, PNCP control number, object, modalidade (pregão, concorrência, dispensa…), estimated value in BRL, proposal opening and closing dates, state and city, link to the PNCP notice |

### Why use it

- **Sales teams selling to government**: get every new tender for your products in Colombia and Brazil each morning, in Slack, email, a spreadsheet or your CRM.
- **One schema for two countries**: the same fields for SECOP and PNCP, with dates in ISO 8601 and the currency next to every amount.
- **No duplicates**: with *Only new since my last run*, a scheduled search returns only tenders it has not delivered before, and you only pay for those.
- **AI agents**: give an agent a reliable tool to search public tenders through the Apify MCP server.

Only official public open-data APIs are used. No login, no scraping of personal pages, and no personal data: supplier names and IDs and the names of public officials are never included, and Colombian processes titled with a private person's name (individual contracts, not open tenders) are skipped.

### How to use it

1. Pick the **Sources** and add **Keywords** in the local language (for example `software`, `computadores`, `vigilancia`, `tecnologia`).
2. Optionally narrow by **Brazil: states**, **Colombia: departments**, **Brazil: procurement methods** or **Minimum estimated value**.
3. Run it, or schedule it daily with **Only new since my last run** turned on, and connect the dataset to an integration (Slack, email, Google Sheets, Make, Zapier, webhooks).

### Output example

```json
{
  "source": "PNCP",
  "country": "BR",
  "id": "BR-PNCP-17176399000169-1-000036/2026",
  "reference": "25/0602-9000599-0",
  "title": "Contratação de empresa especializada para hidrojateamento e sucção das redes de esgoto…",
  "buyer": { "name": "SUPERINTENDENCIA DOS SERVICOS PENITENCIARIOS", "taxId": "17176399000169", "unit": "POLÍCIA PENAL DO ESTADO DO RIO GRANDE DO SUL", "region": "RS", "city": "Porto Alegre", "level": "Estadual" },
  "procurementMethod": "Dispensa",
  "procurementMethodDetails": "Lei 14.133/2021, Art. 75, VIII",
  "status": "Divulgada no PNCP",
  "isOpen": true,
  "value": { "amount": 74353.33, "currency": "BRL" },
  "publishedAt": "2026-10-26T06:41:05-03:00",
  "tenderPeriod": { "startDate": "2026-10-26T10:00:00-03:00", "endDate": "2026-11-03T10:00:00-03:00" },
  "url": "https://pncp.gov.br/app/editais/17176399000169/2026/36"
}
```

Colombian rows have the same shape with `"source": "SECOP_II"`, `"country": "CO"`, values in COP and a link to the SECOP II notice. A JSON summary of each run (delivered, already seen, filtered, errors per source) is saved as `OUTPUT` in the key-value store.

### Input

| Field | Default | Notes |
|---|---|---|
| `sources` | `["secop2", "pncp"]` | |
| `keywords` | empty | Matches title or description, any keyword, accent- and case-insensitive |
| `daysBack` | 7 | Ignored when `dateFrom` is set |
| `dateFrom`, `dateTo` | — | `YYYY-MM-DD`, publication date |
| `onlyOpen` | true | Skips closed tenders and passed deadlines |
| `onlyNew` | false | Remembers ids per search (keywords and filters, not dates) |
| `pncpModalities` | 4, 5, 6, 7, 8 | Concorrência, pregão and dispensa |
| `brazilStates` | all | `SP`, `RJ`, … |
| `colombiaDepartments` | all | As written in SECOP, e.g. `Antioquia` |
| `includeDirectContracting` | false | Colombia "Contratación directa" (not open competitions) |
| `minValue` | — | Local currency |
| `maxItems` | 1000 | |

### Use cases

- **B2G sales teams**: a daily list of new tenders in Colombia and Brazil that match your keywords.
- **Bid consultants**: monitor several clients' sectors with one scheduled run per client.
- **Market research**: how much the public sector buys of a product, by region and by entity.
- **AI agents**: ask for open tenders on a topic and get structured results to summarize or rank.

### Use with AI agents (MCP)

Every Apify Actor is also a tool for AI agents. Add this Actor to Claude, Cursor, VS Code or any MCP client with the Apify MCP server:

```text
https://mcp.apify.com?tools=ceibadata/latam-public-tenders
```

Or run it locally:

```bash
npx -y @apify/actors-mcp-server --tools ceibadata/latam-public-tenders
```

Then just ask, for example:

> Find open public tenders about software or cybersecurity published in Colombia (SECOP II) and Brazil (PNCP) in the last 7 days.

#### Example input (API / AI agents)

```json
{
  "sources": [
    "secop2",
    "pncp"
  ],
  "keywords": [
    "software",
    "ciberseguridad"
  ],
  "daysBack": 7,
  "onlyOpen": true,
  "onlyNew": true,
  "maxItems": 200
}
```

From code, one call returns the results:

```bash
curl -X POST "https://api.apify.com/v2/acts/ceibadata~latam-public-tenders/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' -d @input.json
```

### Pricing

Pay per event: **US$3 per 1,000 tenders** delivered (US$0.003 each). Tenders skipped as already seen are free. Set a maximum cost per run in Apify and the Actor stops cleanly when it is reached.

### Notes

- PNCP publishes thousands of processes a day; use keywords, states or methods to keep runs small and fast.
- Runs never end in a timeout: about 45 seconds before the run's timeout the Actor stops, saves what it found and says so in the run summary (`timeBudgetReached`). Raise the timeout or narrow the search to get more.
- Running with no changes to the input (or an empty input) does a quick sample: up to 20 tenders. Set your own keywords, dates or limits for a full search.
- SECOP II open data on datos.gov.co is published by Colombia Compra Eficiente with a delay of a few days, so the default window is 7 days; with *Only new since my last run* you never get the same tender twice.
- The PNCP API limits request rates; the Actor paces itself and retries, and if one method or state still fails the others are delivered and the error is listed in the run summary.
- Data belongs to the governments of Colombia and Brazil and is published under their open-data terms.

### Support

Questions or a country you need (Mexico, Chile, Peru…)? Open an issue on the Actor page. Ceiba Data is an AI-operated studio; we answer every issue.

# Actor input Schema

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

secop2 = Colombia SECOP II (datos.gov.co). pncp = Brazil Portal Nacional de Contratações Públicas.

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

Keep tenders whose title or description contains any of these words (accent- and case-insensitive). Use Spanish for Colombia and Portuguese for Brazil, e.g. software, tecnologia, computadores. Leave empty for everything.

## `daysBack` (type: `integer`):

Publication window when no dates are given: today and the previous N-1 days.

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

Optional. Overrides Days back.

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

Optional. Defaults to today.

## `onlyOpen` (type: `boolean`):

Skip tenders that are closed or whose bid deadline has passed.

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

Remember what this search already returned and deliver only tenders you have not seen. Ideal for a daily schedule that feeds email, Slack or a CRM. You are only charged for new tenders.

## `pncpModalities` (type: `array`):

PNCP modalidades to include. Default: concorrência (4, 5), pregão (6, 7) and dispensa (8).

## `brazilStates` (type: `array`):

Two-letter state codes, e.g. SP, RJ, MG. Empty = all states.

## `colombiaDepartments` (type: `array`):

Department names exactly as SECOP writes them, e.g. Antioquia, Valle del Cauca, Distrito Capital de Bogotá. Empty = all.

## `includeDirectContracting` (type: `boolean`):

SECOP 'Contratación directa' processes are not open competitions and are mostly individual service contracts. Off by default.

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

In local currency (COP for Colombia, BRL for Brazil). Tenders without an estimated value are skipped when set.

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

Stop after delivering this many tenders in one run.

## Actor input object example

```json
{
  "sources": [
    "secop2",
    "pncp"
  ],
  "keywords": [
    "software",
    "tecnologia"
  ],
  "daysBack": 7,
  "onlyOpen": true,
  "onlyNew": false,
  "pncpModalities": [
    "4",
    "5",
    "6",
    "7",
    "8"
  ],
  "includeDirectContracting": false,
  "maxItems": 1000
}
```

# Actor output Schema

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

One row per tender: source, country, id, title, description, buyer, procurement method, status, estimated value and currency, publication date, bid deadline and link to the official notice.

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

JSON record with delivered, skippedSeen, filteredOut, bySource, errors, the date window and stoppedEarly.

# 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 = {
    "sources": [
        "secop2",
        "pncp"
    ],
    "keywords": [
        "software",
        "tecnologia"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ceibadata/latam-public-tenders").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 = {
    "sources": [
        "secop2",
        "pncp",
    ],
    "keywords": [
        "software",
        "tecnologia",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("ceibadata/latam-public-tenders").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 '{
  "sources": [
    "secop2",
    "pncp"
  ],
  "keywords": [
    "software",
    "tecnologia"
  ]
}' |
apify call ceibadata/latam-public-tenders --silent --output-dataset

```

## MCP server setup

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

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/4Lk1XAnW91draZ9Ce/builds/NxgVQJeedpdRaJJlL/openapi.json
