# Brazil Jobs Scraper: Greenhouse & Lever (Vagas BR) (`kman-br/vagas-ats`) Actor

Vagas de empresas brasileiras pelas APIs públicas de job board do Greenhouse e do Lever, com cidade, UF e modelo de trabalho normalizados, filtros por termo, UF, cidade e data, e contato pessoal de recrutador removido do texto.

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

## Pricing

Pay per event

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

## Brazil Jobs — Greenhouse & Lever (Vagas BR)

Job postings from Brazilian companies, read from the **official public job board APIs** of Greenhouse and Lever, with Brazilian location normalization (city, state/UF, remote/hybrid/on-site) and recruiter personal contact removed from the text.

> Independent tool. Not affiliated with, endorsed or sponsored by Greenhouse Software, Lever/Employ Inc. or any listed employer. Company names and trademarks belong to their owners.

### What it does

- Calls only two public GET endpoints, one request per company:
  - `https://boards-api.greenhouse.io/v1/boards/{token}/jobs?content=true`
  - `https://api.lever.co/v0/postings/{site}?mode=json`
- Ships with a curated, hand-verified list of Brazilian company boards (`data/empresas-br.json`). You can pass your own tokens.
- Normalizes location to `cidade`, `uf`, `pais` and `modelo_trabalho` (`remoto`, `hibrido`, `presencial`).
- Filters locally by term, UF, city, work model and publication date.
- Waits at least 1 second between companies (Lever asks for `Crawl-delay: 1`).

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `empresas` | string\[] | curated BR list | `greenhouse:token`, `lever:site` or a bare token (tried on the ATS chosen in `ats`). Max 50. |
| `ats` | `todos` | `greenhouse` | `lever` | `todos` | |
| `termo` | string | — | Matches title or description, accent/case-insensitive. |
| `ufs` | string\[] | — | e.g. `["SP","RJ"]` |
| `cidades` | string\[] | — | Accent-insensitive. |
| `modelo` | `todos` | `remoto` | `hibrido` | `presencial` | `todos` | |
| `publicadasDesde` | `YYYY-MM-DD` | — | Uses published date, or updated date when missing. |
| `incluirDescricao` | boolean | `true` | |
| `manterEmailInstitucional` | boolean | `false` | Keeps generic mailboxes (rh@, vagas@, careers@). Personal e-mails are always removed. |
| `maxItems` | integer | `200` | Hard cap 1000, enforced in code. |

Memory is fixed at 256 MB. Each run also has a **cost guard**: it tracks the bytes downloaded and the compute reserved until the end of the run, and stops opening new company boards (or cancels a download in progress) before the estimated platform cost could exceed what the run has already earned. With no matching jobs, that is roughly 9 MB of boards per run (the curated list is about 3 MB); each charged job widens the room. When it trips, the run ends successfully with `status: parcial`, `completo: false` and `motivo: teto_margem`.

### Output (one item per job)

`id`, `ats`, `empresa`, `titulo`, `departamento`, `cidade`, `uf`, `pais`, `modelo_trabalho`, `publicada_em`, `atualizada_em`, `prazo`, `descricao_texto`, `url_vaga`, `source_url`, `retrieved_at`, `warnings`, `status`.

Never included: application `questions`, `demographic_questions`, `data_compliance`, free-form `metadata`, or any candidate field. When no job is returned, the dataset gets one free diagnostic record (`sem_resultado` or `fonte_indisponivel`). The key-value record `RUN_SUMMARY` has the run status, `completo`, stop reason (`maxItems`, `teto_cobranca`, `prazo_interno`, `teto_margem`), per-company HTTP status, charged events and a `margem` block (bytes downloaded, estimated cost).

Warnings: `teto_margem:<ats>:<token>` (download cancelled by the cost guard), `contato_removido`, `modelo_trabalho_inferido` (city found, no remote/hybrid marker), `empresa_nao_encontrada:<ats>:<token>` (404), `empresa_falhou:...`, `maxItems_limitado:<n>`.

### Pricing (pay per event)

| Event | When | Price |
|---|---|---|
| `inicio-run` | Once per run, after the input is validated | US$0.005 |
| `vaga` | Each job item with status `ok` | US$0.002 |

Invalid input is never charged. Diagnostic records are free. The run respects your maximum charge per run.

### Privacy

Job postings are company data. The only personal data that can appear is a recruiter's contact inside the free text, so the Actor replaces e-mails with `[email removido]`, Brazilian phone numbers with `[telefone removido]`, and drops lines such as `Recrutador(a): Name` / `Recruiter: Name`, adding the warning `contato_removido`. No candidate data is read or stored.

### FAQ

**Is it legal?** The Actor only reads data the platforms publish for this purpose. Greenhouse documents that "Job Board data is publicly available, so authentication is not required for any GET endpoints" (developers.greenhouse.io/job-board.html). Lever's Postings API README says published postings "are publicly viewable. These jobs may be scraped by third parties" (github.com/lever/postings-api). The Actor never logs in, never calls candidate or application endpoints, keeps the 1-second pace and links back to the original posting. Gupy is deliberately not supported, because its terms forbid aggregating its job listings. You are responsible for how you use the data, including LGPD duties.

**Why is my company missing?** Only companies that use Greenhouse or Lever have these boards. Pass the token from the company's board URL (`boards.greenhouse.io/<token>` or `jobs.lever.co/<site>`).

**Why does a run stop early?** It stops at `maxItems`, at your charge limit, at the cost guard (`teto_margem`: too many large boards with no matching job; narrow `empresas` or loosen the filters), or at an internal deadline (~90 s after the run start, and always 20 s before the platform timeout). Items already saved are kept and the run ends successfully with `status: parcial`.

***

## Vagas BR — Greenhouse e Lever (português)

Vagas de empresas brasileiras lidas nas **APIs públicas oficiais de job board** do Greenhouse e do Lever, com local normalizado para o Brasil (cidade, UF e modelo remoto/híbrido/presencial) e o contato pessoal de recrutador removido do texto.

> Ferramenta independente. Sem vínculo, endosso ou patrocínio da Greenhouse Software, da Lever/Employ Inc. ou das empresas listadas. Nomes e marcas pertencem aos donos.

### O que faz

- Usa só dois endpoints GET públicos, uma requisição por empresa (os mesmos listados acima).
- Vem com uma lista curada de empresas brasileiras, verificada uma a uma (`data/empresas-br.json`). Você pode passar outros tokens.
- Normaliza o local em `cidade`, `uf`, `pais` e `modelo_trabalho`.
- Filtra localmente por termo, UF, cidade, modelo de trabalho e data de publicação.
- Espera pelo menos 1 segundo entre empresas (o Lever pede `Crawl-delay: 1`).

### Entrada

- `empresas`: tokens no formato `greenhouse:token`, `lever:site` ou só o token (tentado nos ATS escolhidos). Vazio usa a lista curada. Máximo de 50.
- `ats`: `todos`, `greenhouse` ou `lever`.
- `termo`: filtro no título e na descrição, sem diferenciar acento e maiúscula.
- `ufs`, `cidades`, `modelo` (`remoto`, `hibrido`, `presencial`, `todos`), `publicadasDesde` (AAAA-MM-DD).
- `incluirDescricao` (padrão `true`), `manterEmailInstitucional` (padrão `false`).
- `maxItems`: padrão 200, teto de 1000 imposto no código.

A memória é fixa em 256 MB. Cada run tem uma **trava de custo**: conta os bytes baixados e o compute reservado até o fim do run, e para de abrir novos job boards (ou cancela o download em curso) antes que o custo estimado passe do que o run já faturou. Sem nenhuma vaga casando, isso dá cerca de 9 MB de boards por run (a lista curada tem uns 3 MB); cada vaga cobrada abre mais espaço. Quando dispara, o run termina com sucesso, `status: parcial`, `completo: false` e `motivo: teto_margem`.

### Saída

Um item por vaga, com os campos listados na seção em inglês. Nunca saem perguntas de candidatura, perguntas demográficas, `data_compliance`, `metadata` livre ou qualquer campo de candidato. Sem vagas, o dataset recebe um registro de diagnóstico gratuito. O registro `RUN_SUMMARY` traz status, `completo`, motivo de parada (inclusive `teto_margem`), HTTP de cada empresa, eventos cobrados e o bloco `margem` (bytes baixados e custo estimado).

### Custo

Evento `inicio-run` (uma vez por run, depois de validar o input): US$0,005. Evento `vaga` (cada vaga com status `ok`): US$0,002. Input inválido não é cobrado, registros de diagnóstico são gratuitos, e o teto de gasto do run é respeitado.

### Privacidade (LGPD)

A vaga é dado da empresa. O único dado pessoal possível é o contato do recrutador no texto livre. Por isso, e-mails viram `[email removido]`, telefones brasileiros viram `[telefone removido]` e linhas como `Recrutador(a): Nome` saem, com o aviso `contato_removido`. Nenhum dado de candidato é lido ou guardado.

### Perguntas frequentes

**É legal?** O Actor só lê o que as plataformas publicam para esse fim. O Greenhouse documenta que os dados do Job Board são públicos e que nenhum GET exige autenticação. O README da Postings API do Lever diz que as vagas publicadas são públicas e "may be scraped by third parties". O Actor não faz login, não chama endpoints de candidato ou de candidatura, respeita a pausa de 1 segundo e devolve o link da vaga original. A Gupy fica de fora de propósito, porque os termos dela proíbem agregar as vagas. O uso dos dados, inclusive as obrigações da LGPD, é responsabilidade de quem usa.

**Por que minha empresa não aparece?** Só entram empresas que usam Greenhouse ou Lever. Passe o token que aparece na URL do job board da empresa.

**Por que o run parou antes?** Ele para no `maxItems`, no teto de gasto, na trava de custo (`teto_margem`: muitos boards grandes sem vaga que case; reduza `empresas` ou afrouxe os filtros) ou no prazo interno (cerca de 90 s depois do início do run e sempre 20 s antes do timeout da plataforma). O que já foi gravado fica, e o run termina com sucesso e `status: parcial`.

### Related Actors

More Actors from the same publisher:

- [Greenhouse Jobs Scraper API](https://apify.com/kman-br/greenhouse-jobs): Job postings from public Greenhouse job boards, with departments and clean descriptions.
- [Lever Jobs Scraper API](https://apify.com/kman-br/lever-jobs): Job postings from public Lever job boards, with clean descriptions.
- [Workday Jobs Scraper API](https://apify.com/kman-br/workday-jobs): Job postings from public Workday career sites (myworkdayjobs.com), with clean descriptions.
- [Ashby Jobs Scraper API](https://apify.com/kman-br/ashby-jobs): Job postings from public Ashby job boards, with department, employment type and pay summary.
- [Brazil CNPJ Bulk Lookup - Receita Federal (CNPJ em Lote)](https://apify.com/kman-br/cnpj-lote): Bulk lookup of Brazilian company CNPJs in Receita Federal open data. Companies only, no partners or contacts.

Browse the full catalog: [kman-br.github.io](https://kman-br.github.io/) ([Português](https://kman-br.github.io/pt/)).

# Actor input Schema

## `empresas` (type: `array`):

Tokens do job board. Use "greenhouse:token" ou "lever:site"; token sem prefixo é tentado nos ATS escolhidos em "ats". Vazio = lista curada de empresas brasileiras. Máximo de 50 por run.

## `ats` (type: `string`):

Quais APIs consultar.

## `termo` (type: `string`):

Filtro local no título e na descrição, sem diferenciar acento e maiúscula.

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

Siglas de UF, por exemplo SP, RJ.

## `cidades` (type: `array`):

Nomes de cidade (comparação sem acento).

## `modelo` (type: `string`):

Filtra por modelo de trabalho: remoto, híbrido ou presencial. "Todos" não filtra.

## `publicadasDesde` (type: `string`):

Data AAAA-MM-DD. Usa a data de publicação; se faltar, a de atualização.

## `incluirDescricao` (type: `boolean`):

Inclui o texto da vaga já limpo e sanitizado.

## `manterEmailInstitucional` (type: `boolean`):

Mantém e-mails genéricos como rh@, vagas@ e careers@. E-mails pessoais sempre saem.

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

Limite de vagas cobradas no run. O teto é 1000 (200 no api.market) e é imposto no código.

## Actor input object example

```json
{
  "empresas": [
    "greenhouse:stone",
    "lever:neon"
  ],
  "ats": "todos",
  "modelo": "todos",
  "incluirDescricao": true,
  "manterEmailInstitucional": false,
  "maxItems": 200
}
```

# Actor output Schema

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

No description

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

RUN_SUMMARY: status, motivo (maxItems, teto_cobranca, prazo_interno), empresas consultadas e eventos cobrados.

# 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 = {
    "empresas": [
        "greenhouse:stone",
        "lever:neon"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kman-br/vagas-ats").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 = { "empresas": [
        "greenhouse:stone",
        "lever:neon",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("kman-br/vagas-ats").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 '{
  "empresas": [
    "greenhouse:stone",
    "lever:neon"
  ]
}' |
apify call kman-br/vagas-ats --silent --output-dataset

```

## MCP server setup

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

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/UOzWvddM22CHkYGAQ/builds/ZhmweyhybZ3jjUvnc/openapi.json
