The ANS (Agencia Nacional de Saude Suplementar) is Brazil’s regulatory agency for private/supplementary health insurance (planos de saude). Its open data portal provides data on beneficiaries, consumer complaints, and operator financial statements.
| Feature | Details |
|---|---|
| Source | HTTP CSV/ZIP (dadosabertos.ans.gov.br) |
| Data types | 3 (beneficiaries, complaints, financial) |
| Beneficiaries | Monthly, per-UF (Apr 2019–present) |
| Complaints | Annual, national (2011–present) |
| Financial | Quarterly (2007–present) |
| Operators | Snapshot registry (separate function) |
| Code | Name | Granularity | Availability |
|---|---|---|---|
| beneficiaries | Beneficiarios | Monthly, per-UF | Apr 2019–2025 |
| complaints | Demandas NIP | Annual, national | 2011–2026 |
| financial | Demonstracoes contabeis | Quarterly | 2007–2025 |
Beneficiary data provides consolidated counts of health plan enrollees broken down by operator, municipality, sex, age group, plan type, and more. Each file covers one state (UF) and one month.
| Variable | Description |
|---|---|
| ID_CMPT_MOVEL | Reference period (YYYY-MM) |
| CD_OPERADORA | Operator code at ANS |
| NM_RAZAO_SOCIAL | Operator name |
| SG_UF | State abbreviation |
| CD_MUNICIPIO | Municipality (IBGE code) |
| TP_SEXO | Sex (M/F) |
| DE_FAIXA_ETARIA | Age group |
| DE_CONTRATACAO_PLANO | Contract type (Individual, Coletivo Empresarial, etc.) |
| DE_SEGMENTACAO_PLANO | Plan segment (Ambulatorial, Hospitalar, etc.) |
| COBERTURA_ASSIST_PLAN | Coverage type (Medico-hospitalar, Odontologica) |
| TIPO_VINCULO | Beneficiary link (Titular, Dependente) |
| QT_BENEFICIARIO_ATIVO | Active beneficiary count |
Consumer complaints data covers demands filed through ANS’s NIP (Notificacao de Intermediacao Preliminar) system. Files are national (not per-UF) and annual.
# complaints filed in 2022
nip <- ans_data(year = 2022, type = "complaints")
nip
# multiple years
nip_multi <- ans_data(year = 2020:2023, type = "complaints")| Variable | Description |
|---|---|
| NUMERO_DA_DEMANDA | Complaint number |
| ABERTURA_DA_DEMANDA | Filing date |
| ASSUNTO | Subject |
| REGISTRO_OPERADORA | Operator registration |
| NOME_OPERADORA | Operator name |
| TIPO_DE_PLANO_CONTRATADO | Contract type |
| SEXO | Sex (M/F) |
| ESTADO_DO_BENEFICIARIO | Beneficiary state |
| CLASSIFICACAO_DA_NIP | NIP classification |
| NATUREZA_DA_NIP | NIP nature |
| SITUACAO_DA_NIP | NIP status |
Quarterly financial statements (demonstracoes contabeis) for all health plan operators.
# Q1 2023
fin_q1 <- ans_data(year = 2023, type = "financial", quarter = 1)
# all 4 quarters of 2023
fin_2023 <- ans_data(year = 2023, type = "financial")
# specific quarters
fin_q12 <- ans_data(year = 2023, type = "financial", quarter = 1:2)| Variable | Description |
|---|---|
| DATA | Reference date |
| REG_ANS | Operator registration |
| CD_CONTA_CONTABIL | Accounting code |
| DESCRICAO | Account description |
| VL_SALDO_INICIAL | Opening balance (R\() | | VL_SALDO_FINAL | Closing balance (R\)) |
The operator registry is a separate snapshot (not time-series), so it uses its own function:
# active operators
active <- ans_operators()
# cancelled operators
cancelled <- ans_operators(status = "cancelled")
# both combined
all_ops <- ans_operators(status = "all")| Variable | Description |
|---|---|
| REGISTRO_OPERADORA | ANS registration number |
| CNPJ | Tax ID |
| Razao_Social | Legal name |
| Nome_Fantasia | Trade name |
| Modalidade | Modality (Medicina de Grupo, Cooperativa, etc.) |
| UF | State |
| Data_Registro_ANS | ANS registration date |
# Q4 2023 financial data
fin <- ans_data(year = 2023, type = "financial", quarter = 4)
# join with operator registry for names
ops <- ans_operators()
fin |>
filter(grepl("^41", CD_CONTA_CONTABIL)) |> # revenue accounts
group_by(REG_ANS) |>
summarize(
revenue = sum(as.numeric(VL_SALDO_FINAL), na.rm = TRUE),
.groups = "drop"
) |>
left_join(
ops |> select(REGISTRO_OPERADORA, Razao_Social),
by = c("REG_ANS" = "REGISTRO_OPERADORA")
) |>
arrange(desc(revenue)) |>
head(10)ANS beneficiary counts complement SUS data by showing private coverage:
# private coverage (ANS)
ben <- ans_data(year = 2023, month = 12,
vars = c("SG_UF", "QT_BENEFICIARIO_ATIVO"))
private_by_uf <- ben |>
group_by(SG_UF) |>
summarize(
private_beneficiaries = sum(as.integer(QT_BENEFICIARIO_ATIVO), na.rm = TRUE),
.groups = "drop"
)
# total population (Census 2022)
pop <- censo_populacao(year = 2022, territorial_level = "state")
# private coverage rate
# private_by_uf |>
# left_join(pop, by = ...) |>
# mutate(coverage_pct = (private_beneficiaries / population) * 100) |>
# arrange(desc(coverage_pct))ans_data() routes parameters based on the
type:
| Parameter | beneficiaries | complaints | financial |
|---|---|---|---|
year |
required | required | required |
month |
optional (1–12) | ignored | ignored |
uf |
optional (27 UFs + XX) | ignored | ignored |
quarter |
ignored | ignored | optional (1–4) |
vars |
optional | optional | optional |
Unused parameters emit a warning but do not cause errors.
With the arrow package installed, data is cached in
Parquet format and can be queried lazily:
Downloaded data is cached locally for faster future access:
| Feature | ANS | DATASUS modules |
|---|---|---|
| Data source | HTTP CSV/ZIP | FTP .dbc/.DBF files |
| Column names | MixedCase (from CSV) | UPPERCASE |
parse parameter |
Not available | Available |
dictionary() |
Not available | Available |
quarter parameter |
Financial data | Not used |
| Operator registry | ans_operators() |
Not applicable |
dadosabertos.ans.gov.br)www.gov.br/ans/pt-br)www.ans.gov.br/anstabnet)