# Atas para Carona — PNCP (`kman-br/atas-carona-pncp`) Actor

Atas de Registro de Preço vigentes no PNCP abertas a adesão (carona), com itens, preços, fornecedores com privacidade, vigência e score de oportunidade. Busca por UF, município, objeto e fornecedor; acompanhamento semanal de mudanças.

- **URL**: https://apify.com/kman-br/atas-carona-pncp.md
- **Developed by:** [Kman](https://apify.com/kman-br) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 ata enriquecidas

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

## Atas para Carona — PNCP (Atas de Registro de Preço vigentes)

Encontra **Atas de Registro de Preço (ARP) vigentes** no PNCP que outros órgãos podem usar por **adesão ("carona", Lei 14.133, art. 86)** e devolve um **ranking** com itens, preços homologados, fornecedores (CNPJ), dias de vigência restantes e um `score_oportunidade`.

Para quem: equipes comerciais B2G (quem tem ata vende a carona; quem não tem quer saber quais existem, de quem e até quando), consultorias de licitação e órgãos que procuram ata para aderir.

### Como funciona

1. Lista as atas do PNCP (API pública de consulta, sem chave): as **incluídas ou atualizadas nos últimos `dias_atualizacao` dias**, ou, com `cnpj_orgao`, **todas as atas vigentes hoje** desse órgão. (O PNCP tem mais de 500 mil atas vigentes; não dá para varrer tudo a cada run.)
2. Descarta sem gastar requisição: atas canceladas, sem adesão permitida (`possibilidadeAdesao = false`), com menos de `vigencia_minima_dias` de vigência ou sem as palavras-chave no objeto.
3. Lê o detalhe da ata (UF, município e esfera do órgão gerenciador; a listagem não traz UF) e aplica `uf`, `municipios_ibge` e `esferas`.
4. Lê os itens da compra vinculada e o resultado (fornecedor vencedor e preço homologado) de até `max_itens_por_ata` itens.
5. Calcula o score, ordena e grava.

### Saída (uma linha por ata)

| Campo | Conteúdo |
|---|---|
| `status` | `ok` (ata com pelo menos um item com fornecedor homologado; **cobrada**), `parcial` (sem resultado homologado; não cobrada) ou `erro` (falha da fonte ou do input; não cobrada) |
| `ata_id`, `numero_ata`, `ano_ata`, `compra_id` | Identificação no PNCP |
| `orgao_gerenciador` | `{cnpj, nome, uf, municipio, codigo_ibge, esfera}` |
| `unidade`, `modalidade`, `objeto` | Unidade gerenciadora, modalidade da compra e objeto |
| `vigencia_inicio`, `vigencia_fim`, `dias_vigencia_restantes` | Vigência da ata |
| `possibilidade_adesao` | `true`, `false` ou `null` (não informado na fonte: confirme no edital/ata) |
| `cancelado`, `data_cancelamento` | Cancelamento |
| `itens[]` | `{numero_item, descricao, unidade, quantidade, valor_unitario, valor_total, valor_estimado, fornecedor_tipo, fornecedor_cnpj, fornecedor_razao}`; uma linha por fornecedor homologado. Sem resultado: valor estimado da compra e fornecedor `null` |
| `itens_total_na_compra`, `valor_total` | Total de itens da compra e soma dos itens lidos |
| `score_oportunidade` | 0 a 100 = vigência restante (até 1 ano) × valor (escala log; R$ 100 milhões = 1) × aderência às palavras-chave (0,5 a 1) |
| `atas_da_mesma_compra` | Outras atas da mesma compra (ver abaixo) |
| `mudanca` | Só no modo diff: `nova`, `cancelada` ou `vencendo` |
| `link_pncp`, `source_url`, `source_name`, `retrieved_at`, `warnings`, `error_message` | Link da página da ata, URL da API, fonte, data da coleta (Brasília), avisos e erro |

### Entrada

| Campo | Padrão | Descrição |
|---|---|---|
| `modo` | `busca` | `busca` (ranking) ou `diff_semanal` (só atas novas, canceladas ou com até 30 dias de vigência desde o run anterior com os mesmos filtros) |
| `palavras_chave` | — | Qualquer uma no objeto da ata, sem diferença de acento ou maiúscula |
| `uf` | `["SP"]` | UF do órgão gerenciador. Vazio = todas |
| `municipios_ibge` | — | Códigos IBGE de 7 dígitos |
| `esferas` | — | `federal`, `estadual`, `municipal`, `distrital` |
| `vigencia_minima_dias` | `60` | Dias mínimos até o fim da vigência |
| `valor_minimo` | — | Soma mínima dos itens lidos (R$) |
| `cnpj_fornecedor` | — | Só atas em que esse CNPJ venceu algum item lido (atas de um concorrente). CPF não é aceito |
| `cnpj_orgao` | — | Todas as atas vigentes hoje do órgão |
| `dias_atualizacao` | `7` | Janela de atas incluídas/atualizadas no PNCP (sem `cnpj_orgao`) |
| `agrupar_por_compra` | `true` | Uma compra com várias atas vira um item só |
| `maxItems` | `10` | Máximo de atas no resultado |
| `max_itens_por_ata` | `5` | Itens lidos por ata (cada item com resultado = 1 requisição) |

Run sem input: atas de **SP** atualizadas nos **últimos 7 dias**, com **60+ dias** de vigência, até **10 atas** com até **5 itens** cada (cerca de 2 minutos).

### Cobrança (pay-per-event)

- `rodada`: US$ 0,01, cobrado uma única vez por run, no início da busca. Sem orçamento (`ACTOR_MAX_TOTAL_CHARGE_USD`) o run não busca e grava só um diagnóstico grátis. **Atenção:** a rodada é cobrada mesmo que a fonte (PNCP) esteja fora do ar nesse run.
- Prazo: o run para de coletar/entregar perto de `ACTOR_TIMEOUT_AT` (margem de 45 s) e, no `diff_semanal`, salva o estado a cada ata entregue, então um run interrompido não recobra atas já entregues.
- `ata-enriquecida` (evento por ata, nome mantido): US$ 0,03, cobrado por ata com status `ok` (com itens e fornecedor). Atas `parcial` e itens de `erro` não são cobrados.
- O teto de gasto do usuário é respeitado: ao atingi-lo, o Actor para de gravar.
- No `diff_semanal`, a última ata efetivamente cobrada também é salva quando a plataforma informa que o teto foi atingido. Uma tentativa rejeitada sem cobrança permanece pendente; o resumo conta somente atas entregues.

### Limites conhecidos

- **A API não liga cada item a uma ata.** Os itens vêm da compra; quando a compra tem várias atas (uma por fornecedor, em geral), os itens e fornecedores são os da compra inteira, com aviso. Por isso, com `agrupar_por_compra` (padrão), a compra vira um item só, e as outras atas aparecem em `atas_da_mesma_compra`. Confira a ata no PNCP antes de oferecer ou pedir a carona.
- Só a primeira página de itens (até 50) é lida; com `max_itens_por_ata` menor, o aviso indica quantos itens a compra tem.
- `possibilidade_adesao` vem vazia em parte das atas; essas entram com aviso.
- A busca sem `cnpj_orgao` cobre só as atas incluídas ou atualizadas na janela de `dias_atualizacao`.

### LGPD

- Fornecedor **pessoa física**: documento sai mascarado inteiro (`***.***.***-**`) e o nome é omitido, com aviso em `warnings`.
- **MEI / empresário individual** (razão social com nome de pessoa e/ou CPF): CPF removido e nome mascarado com as iniciais (ex.: `45.123.456 M*** A*** S***`), com aviso.
- O campo `usuario` da fonte (quem publicou) não é copiado. Não há busca por pessoa (CPF é recusado no input).

***

## Price Registration Minutes for "carona" — PNCP (English)

Finds **active Price Registration Minutes (Atas de Registro de Preço)** on Brazil's PNCP that other public bodies can **join without a new tender ("carona", Law 14.133, art. 86)** and returns a **ranking** with items, awarded prices, suppliers (CNPJ), days of validity left and an opportunity score.

**How it works:** lists minutes added or updated in the last `dias_atualizacao` days (or all active minutes of one agency with `cnpj_orgao`), drops cancelled ones, those closed to joining, those with less than `vigencia_minima_dias` left or without the keywords, reads each minute's detail (state, city, government level), then reads the linked purchase's items and awarded supplier for up to `max_itens_por_ata` items, scores and sorts.

**Output:** one row per minute: `ata_id`, managing agency (`orgao_gerenciador`: CNPJ, name, state, city, IBGE code, level), `objeto`, validity dates and `dias_vigencia_restantes`, `possibilidade_adesao`, `cancelado`, `itens[]` (description, unit, quantity, unit price, total, supplier type/CNPJ/name), `valor_total`, `score_oportunidade` (0–100 = remaining validity × value on a log scale × keyword match), `atas_da_mesma_compra`, `mudanca` (diff mode), `link_pncp`, `source_url`, `retrieved_at`, `warnings`, `status`.

**Input:** `modo` (`busca` = ranking, default; `diff_semanal` = only new, cancelled or ending-within-30-days minutes since the previous run with the same filters), `palavras_chave`, `uf` (default `["SP"]`), `municipios_ibge`, `esferas`, `vigencia_minima_dias` (default 60), `valor_minimo`, `cnpj_fornecedor` (a competitor's minutes; CPF is not accepted), `cnpj_orgao`, `dias_atualizacao` (default 7), `agrupar_por_compra` (default `true`), `maxItems` (default 10), `max_itens_por_ata` (default 5). An empty input returns up to 10 São Paulo minutes updated in the last 7 days with 60+ days left (about 2 minutes).

**Pricing:** pay-per-event `rodada` (US$0.01, once per run) and `ata-enriquecida` (US$0.03), the latter charged only for `ok` rows (minutes with items and an awarded supplier). `parcial` and `erro` rows are free.

**Known limits:** the PNCP API does not link items to a specific minute; items come from the purchase, so when a purchase has several minutes the items/suppliers are those of the whole purchase (warned; grouped into one row by default). Only the first page of items (up to 50) is read. `possibilidade_adesao` is empty for part of the minutes (kept, with a warning).

**Privacy (LGPD):** individual suppliers have their CPF fully masked (`***.***.***-**`) and their name omitted; sole-proprietor (MEI) names are masked to initials and embedded CPFs removed; the source's `usuario` field is not copied; there is no search by person.

# Actor input Schema

## `modo` (type: `string`):

busca: atas vigentes que passam nos filtros, ordenadas pelo score. diff_semanal: compara com o run anterior com os mesmos filtros e devolve só atas novas, canceladas ou com até 30 dias de vigência.

## `palavras_chave` (type: `array`):

Qualquer uma no objeto da ata (sem diferença de acento ou maiúscula). Ex.: notebook, ambulância, medicamento.

## `uf` (type: `array`):

Siglas (ex.: SP, MG). Vazio = todas. A listagem do PNCP não filtra UF: o Actor lê o detalhe de cada ata (com cache por órgão).

## `municipios_ibge` (type: `array`):

Códigos IBGE de 7 dígitos do município da unidade gerenciadora (ex.: 3550308 = São Paulo).

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

federal, estadual, municipal ou distrital. Vazio = todas.

## `vigencia_minima_dias` (type: `integer`):

Só atas com pelo menos esse número de dias até o fim da vigência.

## `valor_minimo` (type: `number`):

Soma dos itens lidos da ata (homologado; estimado quando não há resultado).

## `cnpj_fornecedor` (type: `string`):

Só atas em que esse CNPJ venceu algum item lido (ver as atas de um concorrente). CPF não é aceito (LGPD).

## `cnpj_orgao` (type: `string`):

Com CNPJ, lista todas as atas vigentes hoje desse órgão (ignora dias_atualizacao).

## `dias_atualizacao` (type: `integer`):

Sem cnpj_orgao, o Actor percorre as atas incluídas ou atualizadas no PNCP nesse período (o PNCP tem mais de 500 mil atas vigentes; não dá para varrer todas a cada run).

## `agrupar_por_compra` (type: `boolean`):

Ligado: uma compra com várias atas vira um item só (as outras atas ficam em atas_da_mesma_compra), porque a API não liga cada item a uma ata. Desligado: um item por ata, com os mesmos itens repetidos.

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

Atas coletadas antes de ordenar pelo score e gravar.

## `max_itens_por_ata` (type: `integer`):

Itens da compra lidos por ata (cada item com resultado custa 1 requisição).

## `estadoStoreName` (type: `string`):

Store nomeado com o estado do modo diff_semanal.

## Actor input object example

```json
{
  "modo": "busca",
  "palavras_chave": [],
  "uf": [
    "SP"
  ],
  "vigencia_minima_dias": 60,
  "dias_atualizacao": 7,
  "agrupar_por_compra": true,
  "maxItems": 10,
  "max_itens_por_ata": 5,
  "estadoStoreName": "atas-carona-pncp-estado"
}
```

# Actor output Schema

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

Itens do dataset padrão.

# 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 = {
    "modo": "busca",
    "palavras_chave": [],
    "uf": [
        "SP"
    ],
    "vigencia_minima_dias": 60,
    "dias_atualizacao": 7,
    "maxItems": 10,
    "max_itens_por_ata": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("kman-br/atas-carona-pncp").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 = {
    "modo": "busca",
    "palavras_chave": [],
    "uf": ["SP"],
    "vigencia_minima_dias": 60,
    "dias_atualizacao": 7,
    "maxItems": 10,
    "max_itens_por_ata": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("kman-br/atas-carona-pncp").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 '{
  "modo": "busca",
  "palavras_chave": [],
  "uf": [
    "SP"
  ],
  "vigencia_minima_dias": 60,
  "dias_atualizacao": 7,
  "maxItems": 10,
  "max_itens_por_ata": 5
}' |
apify call kman-br/atas-carona-pncp --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kman-br/atas-carona-pncp"
        }
    }
}
```

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/1NR2qbGt9UeCm13Jp/builds/4cpc6JYVq3hlG50Rv/openapi.json
