# PNCP Licitações Scraper – Brazil Public Tenders (Editais) API (`opentenders/pncp-licitacoes-scraper`) Actor

Search open public tenders (licitações, editais, pregões) on Brazil's official PNCP portal by keyword, state, modality, government level and date. Get buyer, object, estimated value, deadlines, line items, edital PDFs and official links as JSON/CSV. From $10 per 1,000 tenders.

- **URL**: https://apify.com/opentenders/pncp-licitacoes-scraper.md
- **Developed by:** [Giordano Horacio](https://apify.com/opentenders) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 tender founds

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

## PNCP Scraper – Brazil Public Tenders, Contracts & Atas (Licitações, Editais) API

Search **public tenders, signed contracts and price-registration minutes in Brazil** (licitações, editais, contratos, atas de registro de preços) straight from **PNCP**, the official *Portal Nacional de Contratações Públicas* where every federal, state and municipal buyer must publish under Law 14.133/2021. Filter by keyword, state (UF), modality, government level and publication date, and get clean JSON/CSV/Excel with the tender object, buyer, estimated value, proposal deadline, official links and, optionally, every **line item** (what is being bought, quantity, unit price) and **document** (edital PDF).

Built for **B2G sales teams, tender-monitoring tools, procurement analysts and researchers** who need Brazilian government procurement data every day without reading the portal by hand.

> Busque editais e licitações abertas em todo o Brasil pela API oficial do PNCP: palavra-chave, UF, modalidade, esfera, data de publicação. Saída limpa em JSON/CSV/Excel, com itens e documentos do edital. Pague só pelo que receber.

### What you get

- **Three document types** (`documentType`): **editais** (tender notices: 39,000+ open, 800,000+ historical), **contratos** (signed contracts with supplier, global value and validity: 35,000+ published per week) and **atas** (price-registration minutes: who won, validity, whether other buyers may adhere). Federal, state, municipal and district buyers.
- **Supplier intelligence**: contracts include the winning company's name and CNPJ. Natural-person suppliers are omitted.
- **Keyword search** over the tender object, exactly like the PNCP site search.
- **Filters**: status (receiving proposals / closed / finished), one or more states, modalities (Pregão Eletrônico, Dispensa, Concorrência, Credenciamento, …), government level, municipality (IBGE code).
- **Incremental monitoring**: set `publishedAfter` to yesterday in a daily schedule and receive only new tenders. The run stops as soon as it reaches older tenders, so it stays cheap.
- **Line items and documents** (`includeDetails`): description, quantity, unit, estimated unit and total price per item, plus direct links to the edital and annexes.
- **Official links**: the PNCP page and the originating system (Compras.gov.br, BNC, Licitanet, Portal de Compras Públicas, …) where you actually bid.
- **No proxies, no browser**: uses PNCP's public JSON API, so runs take seconds and cost cents.

### Pricing

Pay per event, no subscription:

| Event | Price |
|---|---|
| Tender found (`tender`) | **$10.00 per 1,000** tenders |
| Tender with line items and documents (`tender-with-details`) | **$20.00 per 1,000** tenders |

Each tender is charged once: either `tender` or, when `includeDetails` is on, `tender-with-details` (never both). 1,000 open tenders with full line items and documents cost $20; other Store actors charge $40–100 per 1,000 for less. Apify's free plan ($5 monthly credit) covers about 500 tenders per month. Cap your spend with `maxItems` and the run's *Maximum total charge*. Empty results and error rows are never charged.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `documentType` | string | `edital` | `edital` (tender notice), `ata` (price-registration minutes) or `contrato` (signed contract). |
| `keyword` | string | `""` | Full-text search over the tender object, e.g. `software`, `material hospitalar`, `energia solar`. Empty = all tenders matching the filters. |
| `status` | array | type default | Editais: `recebendo_proposta` (open for bids, default), `propostas_encerradas` (under evaluation), `encerradas` (finished). Atas and contratos: `vigente` (in force, default), `nao_vigente` (expired). Values of the other type are ignored. |
| `ufs` | array | `[]` | States, e.g. `["SP","MG"]`. Empty = whole country. |
| `modalidades` | array | `[]` | Modality IDs: `6` Pregão Eletrônico, `4` Concorrência Eletrônica, `8` Dispensa, `9` Inexigibilidade, `12` Credenciamento, `15` Chamada pública, `7` Pregão Presencial, … (full list in the input editor). |
| `esferas` | array | `[]` | `F` federal, `E` state, `M` municipal, `D` Federal District. |
| `municipioIbge` | string | | 7-digit IBGE code of one municipality, e.g. `3550308` (São Paulo). |
| `publishedAfter` | string | | `YYYY-MM-DD`. Only tenders published on PNCP on or after this date. |
| `sort` | string | `-data` | `-data` newest first, `relevancia` best keyword match. |
| `maxItems` | integer | `100` | Stop after this many tenders. Caps your cost. |
| `includeDetails` | boolean | `false` | Editais only: also fetch line items and documents (two extra requests per tender, charged as `tender-with-details`). Ignored for atas and contratos. |
| `minResults` | integer | | Monitoring only: fail the run if fewer tenders are found. |

Example: all open **Pregão Eletrônico** tenders mentioning *software* in São Paulo and Minas Gerais, with items:

```json
{
    "keyword": "software",
    "status": ["recebendo_proposta"],
    "ufs": ["SP", "MG"],
    "modalidades": ["6"],
    "includeDetails": true,
    "maxItems": 200
}
```

Contracts signed with any supplier for *vigilância* in Bahia, still in force:

```json
{
    "documentType": "contrato",
    "keyword": "vigilância",
    "ufs": ["BA"],
    "maxItems": 500
}
```

Daily monitor: everything published since yesterday, nationwide:

```json
{
    "keyword": "",
    "publishedAfter": "2026-10-22",
    "maxItems": 5000
}
```

### Output

One row per document. Flat fields export cleanly to CSV/Excel; `itens` and `documentos` are arrays (editais with `includeDetails` only). `tipoDocumento` says which type the row is. Fields that do not apply to a type are `null`: editais fill `propostasAbertura`/`propostasEncerramento` and `valorTotalEstimado`; contratos fill `fornecedorCnpj`, `fornecedorNome`, `valorGlobal`, `dataAssinatura`, `vigenciaInicio`, `vigenciaFim`, `tipoContrato` and `idContratacao` (the tender it came from); atas fill `vigenciaInicio`/`vigenciaFim`, `permiteAdesao` and `sequencialCompra`.

```json
{
    "idPncp": "46523080000160-1-000180/2026",
    "tipoDocumento": "edital",
    "titulo": "Edital nº 051/2026",
    "objeto": "Contratação de empresa especializada para fornecimento, implantação, licenciamento e suporte de sistema em modelo SaaS...",
    "urlPncp": "https://pncp.gov.br/app/editais/46523080000160/2026/180",
    "urlSistemaOrigem": "https://www.bbmnetlicitacoes.com.br/...",
    "modalidadeId": "6",
    "modalidade": "Pregão - Eletrônico",
    "modoDisputa": "Aberto",
    "registroDePrecos": false,
    "situacao": "Divulgada no PNCP",
    "cancelado": false,
    "temResultado": false,
    "valorTotalEstimado": 1334054.07,
    "valorTotalHomologado": null,
    "valorGlobal": null,
    "orcamentoSigiloso": false,
    "propostasAbertura": "2026-10-24T08:00",
    "propostasEncerramento": "2026-11-07T09:00",
    "dataAssinatura": null,
    "vigenciaInicio": null,
    "vigenciaFim": null,
    "publicadoEm": "2026-10-23T16:56:05.123",
    "atualizadoEm": "2026-10-23T16:56:05.123",
    "numero": "051",
    "ano": "2026",
    "sequencial": "180",
    "sequencialCompra": null,
    "idContratacao": null,
    "tipoContrato": null,
    "fornecedorCnpj": null,
    "fornecedorNome": null,
    "fornecedorTipoPessoa": null,
    "orgaoCnpj": "46523080000160",
    "orgaoNome": "MUNICIPIO DE SAO CAETANO DO SUL",
    "unidadeCodigo": "1",
    "unidadeNome": "PREFEITURA MUNICIPAL DE SAO CAETANO DO SUL",
    "esfera": "Municipal",
    "poder": "Executivo",
    "uf": "SP",
    "municipio": "São Caetano do Sul",
    "codigoIbge": "3548807",
    "amparoLegal": ["Lei 14.133/2021, Art. 28, I"],
    "fonteOrcamentaria": null,
    "exigeConteudoNacional": false,
    "permiteAdesao": null,
    "itens": [
        {
            "numeroItem": 1,
            "descricao": "Licenciamento de software de gestão...",
            "materialOuServico": "Serviço",
            "quantidade": 12,
            "unidadeMedida": "MÊS",
            "valorUnitarioEstimado": 8500,
            "valorTotal": 102000,
            "criterioJulgamento": "Menor preço",
            "situacao": "Em andamento",
            "beneficio": "Não se aplica"
        }
    ],
    "documentos": [
        {
            "titulo": "EDITAL_E_ANEXOS_PE_0512026",
            "tipo": "Edital",
            "url": "https://pncp.gov.br/pncp-api/v1/orgaos/46523080000160/compras/2026/180/arquivos/1",
            "publicadoEm": "2026-10-23T16:56:05",
            "ativo": true
        }
    ],
    "coletadoEm": "2026-10-23T20:41:12.345Z"
}
```

A contract row looks like this (abridged):

```json
{
    "idPncp": "27150549000119-2-000123/2026",
    "tipoDocumento": "contrato",
    "titulo": "Contrato nº 171/2026",
    "objeto": "Aquisição, subscrição e upgrade da solução de backup...",
    "urlPncp": "https://pncp.gov.br/app/contratos/27150549000119/2026/123",
    "tipoContrato": "Contrato (termo inicial)",
    "valorGlobal": 1120500,
    "dataAssinatura": "2026-10-13",
    "vigenciaInicio": "2026-10-13",
    "vigenciaFim": "2031-10-12",
    "idContratacao": "27080605000196-1-000853/2026",
    "fornecedorCnpj": "02092332000179",
    "fornecedorNome": "CLM SOFTWARE COMÉRCIO IMPORTAÇÃO E EXPORTAÇÃO LTDA",
    "fornecedorTipoPessoa": "PJ",
    "orgaoNome": "MUNICIPIO DE CARIACICA",
    "uf": "ES",
    "municipio": "Cariacica"
}
```

Values are in BRL. Dates are as published by PNCP (Brasília time, no timezone suffix). Missing data is `null`, never invented.

If the input is invalid or nothing matches, the dataset contains a single explanatory row instead of silently returning nothing:

```json
{ "error": true, "errorType": "NO_RESULTS", "message": "No tenders found for keyword=\"...\" ...", "input": { "...": "..." } }
```

### Use it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/opentenders~pncp-licitacoes-scraper/run-sync-get-dataset-items?format=json" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keyword":"energia solar","ufs":["BA"],"maxItems":50}'
```

Works with the Apify API, JavaScript and Python clients, MCP server, Make, Zapier, n8n and Google Sheets integrations. Schedule it in Apify to run every morning and pipe new tenders into your CRM.

### Limitations

- PNCP exposes at most 10,000 results per query. If more match, narrow the search with `keyword`, `ufs`, `modalidades` or `publishedAfter` (the actor warns in the log).
- Each state, modality, level and status value is a separate query (the PNCP API accepts one value per filter). The actor caps this at 60 combinations per run.
- Coverage is what buyers publish on PNCP. Tenders under the old Law 8.666 that were never published on PNCP are not included. Some buyers omit the estimated value or budget source.
- Dates returned by PNCP for `propostasAbertura` / `propostasEncerramento` can be empty for direct contracting (dispensa, inexigibilidade).
- Line items and documents (`includeDetails`) are available for editais only.
- When a contract's supplier is a natural person (`fornecedorTipoPessoa` = `PF`), the name and tax ID are left `null`. Only companies are exposed.
- This actor reads public open data; it does not submit proposals or access anything behind a login.

### FAQ

**Is this data legal to use?** Yes. PNCP is the Brazilian government's open-data portal for public procurement; publication there is mandatory by law and the API is public. There is no personal data in the output, only public bodies, companies' tax IDs (CNPJ) and tender contents.

**How do I get only new tenders every day?** Create a schedule with `publishedAfter` set to yesterday's date (or use the integration's date expression), `maxItems` high enough, and your usual filters. Only newly published tenders are returned and charged.

**What is the difference between the statuses?** `recebendo_proposta` is open for bids. `propostas_encerradas` means bidding closed and the buyer is evaluating. `encerradas` is awarded, deserted or cancelled. Select several to combine them.

**How do I find who won a tender?** Run with `documentType: "contrato"` or `"ata"` and the same keyword/filters: each row has the supplier's name and CNPJ (contracts) and the contract value and validity. `idContratacao` links a contract back to its tender's `idPncp`.

**Can I filter by buyer (CNPJ)?** Use `keyword` with the buyer name, or post-filter on `orgaoCnpj`. A direct CNPJ filter is on the roadmap.

**Do I get the edital PDF?** With `includeDetails`, each tender lists its documents with direct download URLs. The actor does not download the files themselves.

**Something broke?** Open an issue on the Issues tab with the run ID. PNCP occasionally changes its API; the actor fails loudly with a clear message instead of returning wrong data.

# Actor input Schema

## `documentType` (type: `string`):

<b>Edital</b> = tender notices (default). <b>Ata</b> = price-registration minutes (atas de registro de preços: who won, unit prices, validity, adhesion allowed). <b>Contrato</b> = signed contracts (supplier, global value, validity).

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

Full-text search over the tender object/description, e.g. <code>software</code>, <code>material hospitalar</code>, <code>energia solar</code>. Leave empty to list every tender matching the filters.

## `status` (type: `array`):

Leave empty for the default: editais receiving proposals, or atas/contratos in force (vigente). Editais also accept proposals closed / under evaluation and finished; atas and contratos also accept expired (não vigente). Pick several to combine them; values that do not apply to the chosen document type are ignored.

## `ufs` (type: `array`):

Brazilian states to search. Empty = whole country. Each state costs one extra request per page.

## `modalidades` (type: `array`):

Procurement modality. Empty = all modalities.

## `esferas` (type: `array`):

Federal, state, municipal or district (Brasília) buyers. Empty = all.

## `municipioIbge` (type: `string`):

Optional 7-digit IBGE code of one municipality, e.g. <code>3550308</code> for São Paulo. Find codes at cidades.ibge.gov.br.

## `publishedAfter` (type: `string`):

Only tenders published on PNCP on or after this date. Ideal for scheduled daily runs: set it to yesterday to get only new tenders. Applied while paging newest-first, so the run stops early and stays cheap.

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

Newest first (default) or best keyword match first.

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

Stop after this many tenders. This caps your cost.

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

Editais only: also fetch each tender's line items (what is being bought: description, quantity, unit, estimated unit price) and the list of official documents (edital PDF etc.). Two extra requests per tender; charged as a separate, higher-priced event. Ignored for atas and contratos.

## `minResults` (type: `integer`):

Optional. Fail the run if fewer tenders than this are found. Use it in a scheduled test task so you get an alert when PNCP changes or goes down. Leave empty for normal use.

## Actor input object example

```json
{
  "documentType": "edital",
  "keyword": "software",
  "status": [
    "recebendo_proposta"
  ],
  "ufs": [],
  "modalidades": [],
  "esferas": [],
  "sort": "-data",
  "maxItems": 100,
  "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 = {
    "keyword": "software",
    "status": [
        "recebendo_proposta"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("opentenders/pncp-licitacoes-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 = {
    "keyword": "software",
    "status": ["recebendo_proposta"],
}

# Run the Actor and wait for it to finish
run = client.actor("opentenders/pncp-licitacoes-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 '{
  "keyword": "software",
  "status": [
    "recebendo_proposta"
  ]
}' |
apify call opentenders/pncp-licitacoes-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,opentenders/pncp-licitacoes-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/hoPAd0hYbYbjBFx4J/builds/eNGatI1yzyvDYnNv1/openapi.json
