# SAM.gov Scraper: Federal Contract Opportunities Monitor (`hanielazevedo/samgov-contract-opportunities`) Actor

SAM.gov federal contract opportunities feed: solicitations, sources sought, awards. Filter by NAICS, set-aside, agency, state, keywords. Monitor mode delivers only new notices each run. No login or API key. $2 per 1,000 notices.

- **URL**: https://apify.com/hanielazevedo/samgov-contract-opportunities.md
- **Developed by:** [Haniel Azevedo](https://apify.com/hanielazevedo) (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 opportunities

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

**English** · [Português (BR)](#português-br)

**Every new US federal contract opportunity from SAM.gov, filtered your way and delivered as clean JSON, with no login or API key, and in monitor mode only the notices you haven't seen yet.**

Solicitations, combined synopses, sources sought, presolicitations, special notices, justifications and award notices come from **SAM.gov's official public daily extract** (not by scraping the website). Filter by keywords, NAICS, PSC, set-aside, agency, state and dates, or turn on **monitor mode** to get only new or changed notices each run. Resumable downloads, retries and clear error codes keep scheduled runs reliable.

### Who it's for

- **Small businesses and government contractors** who want a daily list of bids in their NAICS codes, set-asides and states without checking SAM.gov by hand.
- **Capture managers, BD teams and proposal writers** who track agencies, sources sought and RFPs and need to hear about new opportunities early.
- **GovCon consultants and bid-matching tools** building alerts, CRMs or newsletters on top of federal contract data.
- **Developers and analysts** who want typed JSON instead of the 220 MB CSV extract or the rate-limited keyed API.

### Try it

Click **Start** without changing anything. The prefilled input returns the 50 newest open opportunities posted or updated in the last 3 days, across all agencies:

```json
{
  "postedWithinDays": 3,
  "openOnly": true,
  "maxResults": 50
}
```

It finishes in a few seconds because the Actor stops reading the file once it has enough recent notices. In our test run (31 Oct 2026) it returned 50 notices (22 combined synopses/solicitations, 16 solicitations, 5 special notices, 3 presolicitations, 3 sources sought, 1 justification) for **$0.10**. An empty input `{}` uses the same 3-day window and 50-notice limit, but also includes award notices and notices past their deadline. Then add your `keywords`, `naicsCodes`, `setAsides` or `states`.

### How to use it

**Search** (default): returns every matching notice posted or amended in the date window.

```json
{
  "keywords": ["cybersecurity", "zero trust"],
  "naicsCodes": ["5415"],
  "setAsides": ["ANY"],
  "noticeTypes": ["Solicitation", "Combined Synopsis/Solicitation", "Sources Sought"],
  "states": ["VA", "MD", "DC"],
  "postedWithinDays": 7,
  "openOnly": true,
  "maxResults": 200
}
```

**Monitor**: schedule it daily (Console > Schedules). Each run delivers only notices that are **new**, or **updated** (amended, new deadline, award) since the last run, so you pay for each notice once. The memory is kept in the named key-value store `samgov-opportunities-state`, one entry per saved search (derived from your filters, or set `stateKey`). With `firstRun: "baseline"` the first run records what already exists without delivering or charging it.

```json
{ "mode": "monitor", "naicsCodes": ["236220"], "states": ["TX"], "postedWithinDays": 3, "firstRun": "baseline" }
```

Filters: `keywords` (word-prefix, case and accent-insensitive, searched in title, solicitation number and description), `excludeKeywords`, `naicsCodes` (2-6 digit prefixes), `pscCodes` (1-4 character prefixes), `setAsides` (codes plus `ANY` / `NONE`), `noticeTypes`, `agencies` (name words or CGAC/FPDS/AAC codes), `states` (place of performance, office, or either), `postedFrom` / `postedTo` / `postedWithinDays` (default 3 days), `responseDeadlineFrom` / `responseDeadlineTo`, `openOnly`. `maxResults` defaults to 50.

### Schedule daily SAM.gov bid alerts (step by step)

1. In **Input**, set your filters: **NAICS codes**, **Set-asides**, **States**, **Keywords** or **Agencies**.
2. Set **Mode** to `monitor` and **Monitor: first run** to `baseline`, so the first run only records what is already open and charges nothing for it.
3. Click **Save as a new task**, give it a name, and run it once to create the baseline.
4. Open **Schedules**, create a schedule (for example every day at 12:00 UTC, after SAM.gov regenerates its extract around 03:30 UTC) and add the task.
5. On the task's **Integrations** tab, add Slack, Gmail, Zapier, Make or a webhook, triggered when a run succeeds.
6. Each day you get only the notices that are new or changed since the last run, and you pay $0.002 for each one.

### Use with AI agents (MCP) and Python

**MCP:** add this Actor as a tool in Claude Desktop, Cursor, VS Code or any MCP client through the Apify MCP server: `https://mcp.apify.com?tools=hanielazevedo/samgov-contract-opportunities` (sign in with your Apify account or pass your API token). The agent sees the input schema and can run the Actor and read the dataset itself.

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("hanielazevedo/samgov-contract-opportunities").call(run_input={
    "mode": "search",
    "naicsCodes": [
        "541512"
    ],
    "setAsides": [
        "ANY"
    ],
    "postedWithinDays": 7,
    "openOnly": True,
    "maxResults": 100
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

### Sample output

One record per notice. This item comes from the test run above (description shortened, `secondaryContact` removed):

```json
{
  "noticeId": "ff9c886ead754999bbe7add4b0ad67e1",
  "solicitationNumber": "041115-27-0002",
  "title": "Pressure Seal V-Fold Mailer",
  "noticeType": "Solicitation",
  "baseNoticeType": "Solicitation",
  "active": true,
  "postedDate": "2026-10-30",
  "postedAt": "2026-10-30T14:05:49",
  "responseDeadline": "2026-11-04T14:00:00-05:00",
  "responseDeadlineDate": "2026-11-04",
  "responseDeadlineUtc": "2026-11-04T19:00:00.000Z",
  "archiveDate": "2026-11-19",
  "archiveType": "auto15",
  "department": "COMMERCE, DEPARTMENT OF",
  "subTier": "US CENSUS BUREAU",
  "office": "DEPT OF COMMERCE CENSUS",
  "cgacCode": "013",
  "fpdsCode": "1323",
  "aacCode": "1333LB",
  "setAsideCode": "SBA",
  "setAside": "Small Business Set Aside - Total",
  "naicsCode": "322220",
  "pscCode": "7530",
  "placeOfPerformance": {
    "streetAddress": null,
    "city": "Charlestown",
    "state": "IN",
    "zip": "47111",
    "country": "USA"
  },
  "officeAddress": {
    "organizationType": "OFFICE",
    "city": "SUITLAND",
    "state": "MD",
    "zip": "20746",
    "countryCode": "USA"
  },
  "award": null,
  "primaryContact": {
    "title": null,
    "fullName": "Andrea Begens",
    "email": "andrea.f.begens@census.gov",
    "phone": null,
    "fax": null
  },
  "additionalInfoLink": null,
  "samUrl": "https://sam.gov/opp/ff9c886ead754999bbe7add4b0ad67e1/view",
  "description": "The Government is currently reviewing vendor questions and coordinating responses with the requiring activity. Responses to submitted questions, along with any applicable amendment(s) to the solicitation, are anticipated to be posted next w…",
  "descriptionLength": 1428,
  "changeType": null,
  "fingerprint": "09c721882440",
  "sourceFileLastModified": "2026-10-31T03:30:30.000Z",
  "retrievedAt": "2026-10-31T21:10:13.617Z"
}
```

### What you get (fields)

One record per notice (about 70,000 active notices in the extract at any time):

| Field | Example |
|---|---|
| `noticeId`, `solicitationNumber`, `title` | `b5b75f61...`, `36C78627Q0031`, `S208--Request for Information...` |
| `noticeType`, `baseNoticeType` | `Sources Sought` |
| `postedDate`, `postedAt` | `2026-10-30`, `2026-10-30T12:40:50` (US Eastern, as published) |
| `responseDeadline`, `responseDeadlineDate`, `responseDeadlineUtc` | raw value, `2026-11-13`, `2026-11-13T21:30:00.000Z` |
| `department`, `subTier`, `office`, `cgacCode`, `fpdsCode`, `aacCode` | `VETERANS AFFAIRS, DEPARTMENT OF`, `036`, `3600`, `36C786` |
| `setAsideCode`, `setAside` | `SDVOSBC`, `Service-Disabled Veteran-Owned Small Business (SDVOSB) Set-Aside (FAR 19.14)` |
| `naicsCode`, `pscCode` | `561730`, `S208` |
| `placeOfPerformance` | `{ streetAddress, city, state, zip, country }` |
| `officeAddress` | `{ organizationType, city, state, zip, countryCode }` |
| `award` | `{ number, date, amount, awardee, awardeeWithheld }` or `null` |
| `primaryContact`, `secondaryContact` | `{ title, fullName, email, phone, fax }` or `null` |
| `description`, `descriptionLength` | full plain-text description (optional, can be truncated) |
| `samUrl`, `additionalInfoLink` | `https://sam.gov/opp/<noticeId>/view` |
| `changeType` | monitor mode: `new` or `updated` |
| `fingerprint`, `sourceFileLastModified`, `retrievedAt` | provenance |

Values are cleaned: dates are ISO, deadlines with a time zone are converted to UTC, set-aside codes are unwrapped (`["SBA"]` becomes `SBA`), emails are lowercased, PSC codes are uppercased, and text typed into phone/fax fields that is not a phone number is dropped.

### How much does it cost to scrape SAM.gov?

Pay per event:

| Event | Price | When |
|---|---|---|
| `apify-actor-start` | $0.00005 | Once per run (default 256 MB memory) |
| `opportunity` | **$0.002** | Each notice delivered to the dataset |

Runs that deliver nothing (no matches, monitor runs with nothing new, baselines, or a failed download) cost only the start fee. `maxResults` and the run's maximum charge both cap what you pay, and the Actor stops reading as soon as either is reached.

| Job | Calculation | Cost |
|---|---|---|
| The prefilled input (50 notices) | 50 × $0.002 | **$0.10** |
| 1,000 notices | 1,000 × $0.002 | **$2.00** |
| 10,000 notices | 10,000 × $0.002 | **$20.00** |
| Daily monitor, about 20 new matching notices a day, for 30 days | 600 × $0.002 + 30 × $0.00005 | **$1.20** |
| Monitor baseline on the first run (`firstRun: "baseline"`) | start fee only | **$0.00005** |

### Reliability and error codes

- The extract (about 220 MB) is streamed and parsed on the fly. Because it is sorted newest first, the Actor stops reading once rows fall out of your date window: a 3-day search reads only the top of the file.
- Dropped connections and stalls are resumed from the last byte (HTTP Range + If-Match), alternating between the SAM.gov endpoint and its public S3 mirror, with exponential backoff.
- If SAM.gov regenerates the file mid-download, the run restarts once on the new file without duplicating output.
- Columns are mapped by name, so a reordered or extended extract keeps working. A missing required column fails clearly.
- An empty extract (0 bytes, or a header row with no notices) fails with `SOURCE_EMPTY` instead of "succeeding" with 0 items.
- Every run writes a `SUMMARY` record (key-value store) with counts, bytes read, the source file timestamp and an error code.

| Code | Meaning |
|---|---|
| `INVALID_INPUT` | An input value is invalid (the message says which). Run fails, nothing charged beyond the start. |
| `SOURCE_TIMEOUT`, `SOURCE_UNAVAILABLE`, `SOURCE_HTTP_ERROR`, `SOURCE_TRUNCATED` | SAM.gov could not be read after retries. Run fails. |
| `SOURCE_EMPTY` | SAM.gov published an empty extract (no rows, or headers only). Run fails, nothing charged; retry in a few hours. Monitor state is left unchanged. |
| `SOURCE_SCHEMA_CHANGED` | SAM.gov changed the extract format (an HTML error page, or required columns missing). Run fails. |
| `SOURCE_STALE` | Warning: the extract has not been regenerated for more than 48 hours. |
| `MAX_RESULTS_REACHED`, `CHARGE_LIMIT_REACHED` | Stopped at your limit. In monitor mode the rest is delivered next run. |
| `NO_RESULTS` | Nothing matched (or nothing new). |
| `BASELINE_CREATED` | Monitor baseline saved; nothing delivered. |
| `STATE_ERROR` | Monitor state could not be read or saved. |

### Data source, freshness and terms

- **Source:** the *Contract Opportunities* full CSV extract published by GSA on [SAM.gov Data Services](https://sam.gov/data-services) (public, no login, `privacy=Public`). It is regenerated once a day (about 03:30 UTC), so notices posted after the last regeneration appear the next day. It contains active notices only. For real-time needs use the official [SAM.gov Opportunities API](https://open.gsa.gov/api/get-opportunities-public-api/).
- **Terms:** the [SAM.gov Terms of Use](https://sam.gov/about/terms-of-use) state that SAM.gov data is available "via APIs and extracts" and that "if you want to share data publicly, only share data from public versions of APIs"; this Actor uses only the public extract and does not scrape the website. They also state: "Most material on our site is free of copyright and may be copied and distributed without permission... Citation of the GSA site and a link back is much appreciated." Source: GSA, SAM.gov (https://sam.gov). Every record links back to its SAM.gov page.
- **D\&B data:** the terms note that base award notices with an award date before 4 April 2022 may contain Dun & Bradstreet data that must not be redistributed in bulk. For those notices the Actor withholds the awardee name (`award.awardee: null`, `award.awardeeWithheld: true`); amounts, dates and award numbers are kept.
- This is an independent tool, **not an official GSA or SAM.gov product**. Notice content is written by contracting offices; always confirm details on SAM.gov before bidding.

### FAQ

**What happens if SAM.gov is down or publishes an empty file?** Downloads are retried and resumed. If SAM.gov still can't be read, the run fails with `SOURCE_TIMEOUT`, `SOURCE_UNAVAILABLE` or `SOURCE_HTTP_ERROR`. GovCon users have reported that the public CSV extract sometimes ships with headers only. The Actor detects that (and 0-byte files) and fails with `SOURCE_EMPTY` rather than returning 0 items as if nothing matched. Nothing is charged, monitor state is not touched, and the next scheduled run picks up where you left off.

**What are the limits?** `maxResults` (default 50, up to 1,000,000) and your *Maximum cost per run* cap each run. The extract holds about 70,000 active notices. It is regenerated once a day, so it is not real-time. Archived notices older than the extract are not included.

**How does monitor mode work?** With `mode: "monitor"` on a daily schedule, each run delivers only notices that are new or changed since the previous run, and you pay for each once. If a run hits `maxResults`, the rest arrives in the next run. Use `firstRun: "baseline"` to skip what already exists, and `stateKey` to name a saved search.

**Where does the data come from? Is this legal?** From the official public *Contract Opportunities* extract on SAM.gov Data Services, which GSA publishes for reuse. No login, no API key and no website scraping. See [Data source, freshness and terms](#data-source-freshness-and-terms) for the terms quotes and how Dun & Bradstreet data is withheld.

**Which output formats can I export?** The dataset exports to JSON, CSV, Excel, XML, RSS or HTML, and you can fetch it through the API. Nested fields (`placeOfPerformance`, `award`, contacts) are flattened in CSV/Excel.

**What can I connect it to?** Apify Schedules and webhooks, Zapier, Make, n8n, Google Sheets, Slack or email alerts (through those tools), the Apify API and SDKs, and the Apify MCP server for AI agents. A common setup is a daily monitor run that posts new notices to Slack or a spreadsheet.

**Why "scraper" if it reads an extract?** "SAM.gov scraper" is what people search for. This Actor gives the same result more reliably by reading the official public extract instead of the website.

### Other Actors by Haniel

- [PDF to Markdown & Text Extractor with OCR (DOCX)](https://apify.com/hanielazevedo/document-to-markdown-ocr): PDF, scanned PDF, DOCX, HTML and images to clean Markdown or text for RAG and AI agents. $3 per 1,000 documents.
- [Consulta CNPJ em Lote: Brazil CNPJ Lookup (Receita Federal)](https://apify.com/hanielazevedo/brazil-cnpj-company-lookup): Bulk Brazil CNPJ lookup: legal name, CNAE, partners (QSA), address, Simples Nacional and MEI. $1.20 per 1,000 companies.
- [Greenhouse, Lever & Ashby Jobs Scraper: New Jobs Monitor](https://apify.com/hanielazevedo/greenhouse-lever-ashby-new-jobs-monitor): Jobs from Greenhouse, Lever and Ashby career pages, with a monitor mode that returns only new postings. $1.50 per 1,000 jobs.
- [Floor Plan Takeoff: PDF Room Areas, Wall LF & Door Counts](https://apify.com/hanielazevedo/floor-plan-takeoff): Construction takeoff from vector floor-plan PDFs: room SF, wall linear feet, door counts and a check overlay. $2.50 per measured sheet.

***

### Português (BR)

**Todas as novas oportunidades de contratação do governo federal dos EUA no SAM.gov, filtradas do seu jeito e entregues em JSON limpo, sem login nem chave de API. No modo monitor, só os avisos que você ainda não viu.**

Solicitations, sources sought, pré-solicitações, avisos especiais, justificativas e avisos de adjudicação vêm do **extrato diário oficial e público do SAM.gov** (sem raspar o site). Filtre por palavras-chave, NAICS, PSC, set-aside (reserva para pequenas empresas), órgão, estado e datas.

#### Para quem é

- **Pequenas empresas e fornecedores do governo** que querem uma lista diária de licitações nos seus códigos NAICS, set-asides e estados.
- **Times de BD, captura e propostas** que acompanham órgãos, sources sought e RFPs.
- **Consultorias de GovCon e ferramentas de alerta** que montam CRMs, newsletters ou alertas.
- **Desenvolvedores e analistas** que querem JSON tipado em vez do CSV de 220 MB ou da API com chave e limites.

#### Experimente

Clique em **Start** sem mudar nada. A entrada pré-preenchida (`{"postedWithinDays": 3, "openOnly": true, "maxResults": 50}`) traz as 50 oportunidades abertas mais recentes dos últimos 3 dias, de todos os órgãos, em poucos segundos. No nosso teste (31/10/2026) vieram 50 avisos por **US$ 0,10**. A entrada vazia `{}` usa a mesma janela de 3 dias e o limite de 50, mas inclui também avisos de adjudicação e avisos com prazo vencido. Depois adicione `keywords`, `naicsCodes`, `setAsides` ou `states`.

#### Como usar

- **search** (padrão): todos os avisos que atendem aos filtros na janela de datas (`postedWithinDays`, padrão 3 dias; `maxResults`, padrão 50).
- **monitor**: agende uma execução diária. Cada execução entrega apenas avisos `new` (novos) ou `updated` (alterados: emenda, novo prazo, adjudicação), então você paga cada aviso uma vez. O estado fica no key-value store nomeado `samgov-opportunities-state`, uma entrada por busca salva. Com `firstRun: "baseline"`, a primeira execução registra o que já existe sem entregar nem cobrar.

#### Alertas diários de licitações do SAM.gov (passo a passo)

1. Em **Input**, defina os filtros: **NAICS codes**, **Set-asides**, **States**, **Keywords** ou **Agencies**.
2. Coloque **Mode** em `monitor` e **Monitor: first run** em `baseline` (a primeira execução só registra o que já existe, sem cobrar).
3. Clique em **Save as a new task** e rode uma vez.
4. Em **Schedules**, crie um agendamento diário (por exemplo 12:00 UTC, depois da atualização do extrato por volta de 03:30 UTC) com essa task.
5. Na aba **Integrations** da task, adicione Slack, Gmail, Zapier, Make ou um webhook.
6. Todo dia chegam só os avisos novos ou alterados, a US$ 0,002 cada.

#### Exemplo de saída

Veja o JSON real na seção em inglês. Campos principais: `noticeId`, `title`, `noticeType`, `postedDate`, `responseDeadlineUtc`, `department`/`subTier`/`office`, `setAsideCode`, `naicsCode`, `pscCode`, `placeOfPerformance`, `award`, contatos, descrição completa e `samUrl` (link público no SAM.gov).

#### Quanto custa raspar o SAM.gov?

| Evento | Preço | Quando |
|---|---|---|
| `apify-actor-start` | US$ 0,00005 | Uma vez por execução (256 MB, o padrão) |
| `opportunity` | **US$ 0,002** | Por aviso entregue |

Exemplos: a entrada pré-preenchida (50 avisos) custa **US$ 0,10**; 1.000 avisos custam **US$ 2,00**; 10.000 avisos custam **US$ 20,00**; um monitor diário com cerca de 20 avisos novos por dia custa cerca de **US$ 1,20 por mês**. Execuções sem entrega (sem resultados, baseline ou falha de download) pagam só a taxa de início.

#### Códigos de erro

`INVALID_INPUT` (entrada inválida), `SOURCE_TIMEOUT` / `SOURCE_UNAVAILABLE` / `SOURCE_HTTP_ERROR` / `SOURCE_TRUNCATED` (SAM.gov fora do ar após as novas tentativas), `SOURCE_EMPTY` (o SAM.gov publicou um extrato vazio ou só com cabeçalho: a execução falha sem cobrar; tente de novo em algumas horas), `SOURCE_SCHEMA_CHANGED` (formato mudou), `SOURCE_STALE` (aviso: extrato com mais de 48 h), `MAX_RESULTS_REACHED` / `CHARGE_LIMIT_REACHED` (parou no seu limite), `NO_RESULTS`, `BASELINE_CREATED` e `STATE_ERROR`. Toda execução grava um registro `SUMMARY`.

#### Perguntas frequentes

**E se o SAM.gov cair ou publicar um arquivo vazio?** O download é refeito e retomado. Há relatos de que o CSV público às vezes sai só com o cabeçalho; o Actor detecta isso e falha com `SOURCE_EMPTY` em vez de devolver 0 itens como se nada tivesse sido encontrado. Nada é cobrado e o estado do monitor não muda.

**Quais são os limites?** `maxResults` (padrão 50) e o *Maximum cost per run* limitam cada execução. O extrato tem cerca de 70 mil avisos ativos e é atualizado uma vez por dia (não é tempo real).

**Como funciona o modo monitor?** Agendado diariamente, entrega só avisos novos ou alterados; o que passar do `maxResults` vem na próxima execução.

**De onde vêm os dados? É legal?** Do extrato público oficial *Contract Opportunities* em SAM.gov Data Services, publicado pela GSA, atualizado uma vez por dia (por volta de 03:30 UTC). Os [Termos de Uso do SAM.gov](https://sam.gov/about/terms-of-use) disponibilizam os dados "via APIs and extracts" e informam que a maior parte do material é livre de direitos autorais, com citação da GSA e link de volta (cada registro traz o link do SAM.gov). Avisos de adjudicação anteriores a 04/04/2022 podem conter dados da Dun & Bradstreet: nesses casos o nome do vencedor é omitido (`awardeeWithheld: true`). Ferramenta independente, **não é um produto oficial da GSA nem do SAM.gov**; confirme os detalhes no SAM.gov antes de participar.

**Quais formatos de saída?** JSON, CSV, Excel, XML, RSS ou HTML pelo dataset, ou pela API.

**Integra com o quê?** Schedules e webhooks da Apify, Zapier, Make, n8n, Google Sheets, alertas no Slack ou por e-mail (por essas ferramentas), API e SDKs da Apify e o servidor MCP da Apify para agentes de IA.

#### Uso com agentes de IA (MCP) e Python

**MCP:** adicione este Actor como ferramenta no Claude Desktop, Cursor, VS Code ou outro cliente MCP pelo servidor MCP da Apify: `https://mcp.apify.com?tools=hanielazevedo/samgov-contract-opportunities`. O agente lê o schema de entrada, roda o Actor e lê o dataset.

**Python** (`pip install apify-client`): veja o exemplo na seção em inglês.

#### Outros Actors do Haniel

- [PDF to Markdown & Text Extractor with OCR (DOCX)](https://apify.com/hanielazevedo/document-to-markdown-ocr): PDF, PDF escaneado, DOCX, HTML e imagens para Markdown ou texto limpo, para RAG e agentes de IA. US$ 3 por 1.000 documentos.
- [Consulta CNPJ em Lote: Brazil CNPJ Lookup (Receita Federal)](https://apify.com/hanielazevedo/brazil-cnpj-company-lookup): Consulta CNPJ em lote: razão social, CNAE, sócios (QSA), endereço, Simples Nacional e MEI. US$ 1,20 por 1.000 empresas.
- [Greenhouse, Lever & Ashby Jobs Scraper: New Jobs Monitor](https://apify.com/hanielazevedo/greenhouse-lever-ashby-new-jobs-monitor): Vagas de páginas de carreira Greenhouse, Lever e Ashby, com modo monitor que traz só as vagas novas. US$ 1,50 por 1.000 vagas.
- [Floor Plan Takeoff: PDF Room Areas, Wall LF & Door Counts](https://apify.com/hanielazevedo/floor-plan-takeoff): Levantamento de quantitativos de plantas em PDF vetorial: área dos ambientes, metros lineares de parede e portas. US$ 2,50 por prancha medida.

# Actor input Schema

## `mode` (type: `string`):

<b>search</b> returns every matching notice. <b>monitor</b> remembers what it already delivered (in the named key-value store <code>samgov-opportunities-state</code>, one entry per saved search) and only delivers new or changed notices, so you pay once per notice. Schedule it daily.

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

Words or phrases matched (case/accent-insensitive, word-prefix) against title, solicitation number and, by default, the full description. Example: <code>cybersecurity</code>, <code>janitorial</code>, <code>zero trust</code>.

## `keywordMatch` (type: `string`):

Whether a notice must contain any or all of the keywords.

## `excludeKeywords` (type: `array`):

Drop notices containing any of these words.

## `searchDescription` (type: `boolean`):

Also match keywords inside the full notice description (more matches). Turn off to match title and solicitation number only.

## `naicsCodes` (type: `array`):

2-6 digit NAICS prefixes. <code>5415</code> matches 541511, 541512, 541519... Example: <code>541512</code>, <code>236220</code>.

## `pscCodes` (type: `array`):

1-4 character PSC/classification prefixes, e.g. <code>D3</code> (IT services), <code>R4</code>, <code>S201</code>.

## `setAsides` (type: `array`):

Keep only notices with these set-asides. <b>ANY</b> = any small-business set-aside, <b>NONE</b> = full and open.

## `noticeTypes` (type: `array`):

Keep only these notice types (e.g. Solicitation, Combined Synopsis/Solicitation, Sources Sought). Empty = all types.

## `agencies` (type: `array`):

Department, sub-tier or office names (word match, e.g. <code>Veterans Affairs</code>, <code>Army</code>, <code>NASA</code>), or exact CGAC / FPDS / AAC codes (e.g. <code>036</code>, <code>W912DY</code>).

## `states` (type: `array`):

2-letter US state codes, e.g. <code>VA</code>, <code>MD</code>, <code>DC</code>.

## `stateField` (type: `string`):

Which address the state filter checks.

## `postedWithinDays` (type: `integer`):

Only notices posted or amended in the last N days (US Eastern dates). 0 = no limit (the extract holds all active notices). Smaller windows are faster and download less.

## `postedFrom` (type: `string`):

YYYY-MM-DD. Combined with the window above, the later date wins.

## `postedTo` (type: `string`):

YYYY-MM-DD (inclusive).

## `responseDeadlineFrom` (type: `string`):

YYYY-MM-DD. Notices without a deadline are excluded when a deadline range is set.

## `responseDeadlineTo` (type: `string`):

YYYY-MM-DD (inclusive).

## `openOnly` (type: `boolean`):

Drop award notices and notices whose response deadline has passed.

## `maxResults` (type: `integer`):

Stop after this many notices. You pay per notice delivered, so this caps your cost per run.

## `includeDescription` (type: `boolean`):

Include the full plain-text notice description.

## `descriptionMaxChars` (type: `integer`):

0 = full text (descriptions can reach 32,000 characters).

## `includeUpdated` (type: `boolean`):

In monitor mode, re-deliver a notice already seen when its row changed (amendment, new deadline, award). Marked <code>changeType: "updated"</code>.

## `firstRun` (type: `string`):

<b>baseline</b> records current matches without delivering them, so you are only alerted about later notices.

## `stateKey` (type: `string`):

Optional name for this monitor's memory. By default it is derived from your filters, so changing filters starts a new monitor. Letters, digits, ! - \_ . ' ( ).

## `fullScan` (type: `boolean`):

Disable the early stop (the extract is sorted newest first, so by default reading stops once rows fall out of the date window). Only needed for unusual data.

## Actor input object example

```json
{
  "mode": "search",
  "keywords": [
    "cybersecurity"
  ],
  "keywordMatch": "any",
  "searchDescription": true,
  "stateField": "placeOfPerformance",
  "postedWithinDays": 3,
  "openOnly": true,
  "maxResults": 50,
  "includeDescription": true,
  "descriptionMaxChars": 0,
  "includeUpdated": true,
  "firstRun": "deliver",
  "fullScan": false
}
```

# Actor output Schema

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

One dataset item per SAM.gov contract opportunity notice (solicitation, sources sought, presolicitation, award, etc.) that matches the filters. In monitor mode, only notices that are new or changed since the previous run, marked with changeType.

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

SUMMARY record: mode, delivered notices (new and updated), charged opportunities, rows scanned and matched, notices skipped as already seen, the GSA public extract URL and last-modified time, and any run-level errorCode.

# 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 = {
    "postedWithinDays": 3,
    "openOnly": true,
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("hanielazevedo/samgov-contract-opportunities").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 = {
    "postedWithinDays": 3,
    "openOnly": True,
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("hanielazevedo/samgov-contract-opportunities").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 '{
  "postedWithinDays": 3,
  "openOnly": true,
  "maxResults": 50
}' |
apify call hanielazevedo/samgov-contract-opportunities --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hanielazevedo/samgov-contract-opportunities"
        }
    }
}
```

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/w3Xgtqr2sNQU6zifQ/builds/pazpyDWVOr55u1j0m/openapi.json
