Brazil ANVISA Registered Products Lookup avatar

Brazil ANVISA Registered Products Lookup

Pricing

$20.00 / 1,000 matched product record returneds

Go to Apify Store
Brazil ANVISA Registered Products Lookup

Brazil ANVISA Registered Products Lookup

Lookup/search Brazil's official ANVISA registry of registered products - medications, cosmetics, sanitizers, and health products/medical devices - by registration number, product name, or manufacturer CNPJ. Charged per matched product record returned.

Pricing

$20.00 / 1,000 matched product record returneds

Rating

0.0

(0)

Developer

Alison Moura

Alison Moura

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

11 days ago

Last modified

Categories

Share

Brazil ANVISA Registered Products Lookup (Medicamentos, Cosméticos, Saneantes, Produtos para Saúde)

Look up or search Brazil's official ANVISA (health regulatory agency) registry of registered products — medications, cosmetics, sanitizers, and health products/medical devices — by registration number, product name, or manufacturer/registration-holder CNPJ. Get back clean, normalized JSON: product name, registration number, status, expiry, manufacturer, and (for medications) active ingredients and therapeutic class, or (for medical devices) risk class and physical manufacturer.

Who this is for

Pharmacies, distributors, importers, and marketplaces that need to confirm a product is genuinely ANVISA-registered before selling/listing it; regulatory-affairs and compliance teams tracking registration status and expiry dates across a portfolio; procurement/vendor-vetting workflows checking whether a supplier's products are validly registered; or anyone building on top of ANVISA's registries without wanting to hand-parse its raw open-data CSVs directly.

What you send in

{
"registrationNumbers": ["125680040"],
"productNames": ["dipirona sodica"],
"manufacturerCnpjs": ["73856593000166"],
"categories": ["medicamento"],
"maxResultsPerQuery": 50
}
  • registrationNumbers — exact-match lookup by ANVISA registration number, punctuation optional. Searched across every selected category (a bare number doesn't indicate which registry it belongs to).
  • productNames — accent-/case-insensitive substring search, e.g. "dipirona" matches "DIPIRONA SODICA". Capped by maxResultsPerQuery.
  • manufacturerCnpjs — exact-match search by the CNPJ of the registration holder (detentor do registro), punctuation optional. Capped by maxResultsPerQuery.
  • categories — which of the four registries to search: medicamento, cosmetico, saneante, produto_saude. Defaults to all four if omitted.
  • maxResultsPerQuery — default 50, max 200. Only applies to productNames/manufacturerCnpjs searches (summed across all categories searched); registration-number lookups are always exact-match and uncapped.

At least one of registrationNumbers, productNames, or manufacturerCnpjs is required.

What you get back

One dataset record per matched product:

{
"category": "medicamento",
"product_name": "DIPIRONA SODICA",
"registration_number": "125680040",
"process_number": "253510395140179",
"status": "Ativo",
"expiry_date": "2027-01",
"expiry_date_raw": "012027",
"manufacturer": { "cnpj": "73856593000166", "name": "PRATI DONADUZZI & CIA LTDA" },
"regulatory_category": "Genérico",
"therapeutic_class": "ANALGESICOS NAO NARCOTICOS",
"active_ingredients": ["dipirona"],
"risk_class": null,
"device_manufacturer": null,
"_meta": { "source_category": "medicamento", "source_file": "DADOS_ABERTOS_MEDICAMENTOS.csv", "retrieved_at": "2026-08-17T23:06:31Z" }
}

risk_class (Classe de Risco I–IV) and device_manufacturer (the physical maker, which can differ from the registration holder — e.g. an importer holding the registration for a foreign-made device) are only populated for produto_saude. therapeutic_class/active_ingredients/ regulatory_category are only meaningfully populated for medicamento.

A query that finds no match still gets a visibility record (not charged), so you can see what happened to every input:

{ "query_type": "registration_number", "query_input": "000000000", "registration_number": "000000000", "status": "not_found", "categories_searched": ["medicamento"] }
{ "query_type": "product_name", "query_input": "not a real drug xyz", "status": "no_matches", "categories_searched": ["medicamento", "cosmetico", "saneante", "produto_saude"] }

Note on status: passed through exactly as ANVISA publishes it, not collapsed into a single "active/inactive" boolean — the four registries use genuinely different, not-fully-verified vocabularies (see "What was actually tested vs. not" below for why).

Pricing

Pay-per-event: you are charged only for matched product records actually returned (event product-record) — the same "charge only for delivered value" rule as cnpj-lookup. A query that legitimately matches nothing is not charged. See the Actor's Store page for the current per-event price.

Pricing rationale: priced at the same tier as pncp-lookup ($0.02/record), not cnpj-lookup's $0.01. The underlying data is free open data either way, but this Actor's real operational cost per run is higher than cnpj-lookup's: it downloads and parses whole bulk CSV files (2.3KB–27MB, ~39MB combined across all four categories) rather than making one lightweight per-record JSON API call, and the deliverable — a point-in-time registry fact (is this product genuinely registered, what's its status/expiry) — sits in the same value tier as cnpj-lookup's company-registry lookup rather than the higher compliance-grade tier ceis-lookup charges ($0.03) for a completed sanctions check regardless of outcome.

Source: ANVISA's official open-data portal at dados.anvisa.gov.br, published under Brazil's federal Open Data Policy (Decreto nº 8.777/2016) as part of ANVISA's own "Plano de Dados Abertos" (PDA) — verified directly (not assumed): ANVISA's PDA overview page (gov.br/anvisa/pt-br/acessoainformacao/dadosabertos) states it publishes data "em compliance com... Decreto nº 8.777, de 11 de maio de 2016", and Brazil's federal open-data definition (gov.br/governodigital) states open licensing "dá a autorização para que esses dados sejam utilizados por qualquer pessoa, sem restrições, e para qualquer fim, inclusive comerciais" (authorizes use by anyone, without restriction, for any purpose, including commercial) — the same statutory basis already established and cleared for pncp-lookup (see DECISIONS.md ADR-010), with only an attribution/share-alike condition, no field found narrowing or contradicting it for these specific datasets.

No API key, no registration, no Gov.br login — unlike CEIS/CEPIM/CNEP (ceis-lookup), which required a Gov.br-authenticated key from Portal da Transparência. dados.anvisa.gov.br serves plain, unauthenticated CSV file downloads. api.anvisa.gov.br (ANVISA's separate, newer REST API portal, "Portal APIs ANVISA") is Client-ID/Client-Secret-gated behind Gov.br login (confirmed: it sits behind Cloudflare bot-protection that returned HTTP 403 to a direct fetch, and independent reporting confirms credentials require Gov.br authentication) — this Actor deliberately avoids that gated API and uses the open-data CSVs instead, which cover the same underlying registries with no such gate.

Four separate CSV files back the four categories (see anvisa_products_lookup/sources.py for the full reasoning behind each pick, including two cases where the obviously-named file turned out to be wrong):

CategoryFileRows (2026-08-17)Backed by a published data dictionary?
MedicamentosDADOS_ABERTOS_MEDICAMENTOS.csv43,455Yes
CosméticosDADOS_ABERTOS_COSMETICO.csv13Yes
SaneantesTA_DA_PRODUTO_SANEANTE.CSV28,626Yes
Produtos para SaúdeTA_PRODUTO_SAUDE_SITE.csv115,111No (see below)

Cosméticos scope note: 13 rows is not a bug — Brazil's cosmetics regulation only requires individual ANVISA registration for "Grau 2" (higher-risk, e.g. sunscreens, hair dyes) products; the much larger population of "Grau 1" cosmetics is only notified (self-declared, no individual registration), so it isn't in this open dataset at all.

Produtos para Saúde lower-certainty note: TA_PRODUTO_SAUDE_SITE.csv has no matching ANVISA-published data dictionary PDF (every other file does). It's used anyway because: it lives in the same open, unauthenticated dados.anvisa.gov.br domain as the documented files; its field names are self-explanatory and its content was spot-checked against what consultas.anvisa.gov.br's public search UI shows for the same registration numbers; and its DT_ATUALIZACAO_DADO column shows it refreshed within 24 hours of verification — clearly live and actively maintained. Disclosed as a lower-certainty source than the other three, not silently treated as equally authoritative.

Two real quirks discovered and handled, not glossed over:

  1. Inconsistent date formats across files — ANVISA's own CSVs are not internally consistent: some date fields are dd/mm/yyyy, others are mm/dd/yyyy, determined empirically per field using unambiguous (day>12) examples, not assumed. Full writeup with verified examples: anvisa_products_lookup/dates.py module docstring.
  2. Server-side TLS chain misconfigurationdados.anvisa.gov.br does not send its intermediate CA certificate, so a fresh HTTP client (this Actor, on Apify's infra) fails CERTIFICATE_VERIFY_FAILED by default. Verified as a genuine server misconfig (not a stale local CA store) by reproducing the failure with both the system CA bundle and an independently-maintained certifi bundle, then fixing it by fetching the exact missing intermediate from Sectigo's own certificate repository and adding it to the trust store — full writeup and SHA-256 fingerprint for independent verification: anvisa_products_lookup/certs.py.

Rate limits & fair use

None published, because this isn't a rate-limited query API — it's a bulk file download, refetched once per Actor run regardless of how many queries you send in that run.


For the Aurora project (internal)

Fourth product, built same-day as [bcb-institutions-lookup], [tse-electoral-lookup], and [ceis-lookup] per DECISIONS.md ADR-008's owner-directed expansion (this specific product completes the earlier OPPORTUNITIES.md/ADR-004 "government-portal/restrictive-API niche data reseller" thread with a fourth Brazilian official-data Actor). Picked up from a prior session that was interrupted by a Claude usage session limit right after research but before any code was written — this build redid the access/terms verification directly rather than trusting the prior session's unwritten notes.

Feasibility verdict: feasible, built, no ToS blocker found

Unlike DataJud (datajud-lookup, ADR-009 — killed by an explicit anti-commercial clause) and unlike CEIS (ceis-lookup — cleared, but gated behind a Gov.br-login-only API key), ANVISA's open-data CSVs are both legally clear (Decreto 8.777/2016 statutory basis, same as pncp-lookup) and technically open (no key, no login, no gate) — the best combination found across all four products in this batch. The one real technical blocker found (the TLS chain misconfiguration above) was a genuine infrastructure quirk, not a business/legal one, and had a clean fix rather than a walk-away.

What was actually tested vs. not

Tested and passing: 76/76 tests (pytest), ruff clean. Covers:

  • dates.py — all three date-format parsers, each against the exact real unambiguous example value that determined that field's convention (not synthetic dates).
  • text_utils.py — including both real data-quality quirks found in the source (HTML-entity-encoded characters, a mojibake "?" artifact), CNPJ/name splitting (including a razão social containing its own " - ", which a naive first-hyphen split would have broken), and accent-/case-insensitive matching.
  • normalize.py — all four category normalizers, tested against real rows captured directly from the live CSVs on 2026-08-17 (not hand-written fixtures) — tests/fixtures/*.csv, byte-preserved (cp1252) rather than re-encoded through a CSV writer. Covers the produto_saude multi-manufacturer-per-registration case and the "VIGENTE" non-date sentinel specifically.
  • sources.py — category resolution/validation.
  • client.py — download retry/backoff, non-retried 4xx, and (mirroring the exact bug class pncp-lookup shipped and had to fix post-build, ADR-010) that a bare httpx timeout/connect error is always wrapped, never left to crash the Actor — via httpx.MockTransport, no real network calls in the automated suite.
  • certs.py — the embedded certificate loads into a real ssl.SSLContext without error and verification stays CERT_REQUIRED (the fix adds a trusted intermediate, it never disables verification).
  • search.py — exact/substring/accent-insensitive matching and the maxResultsPerQuery cap.
  • main.py — the pure _coerce_str_list input-parsing helper. Like ceis-lookup's test suite, the full async with Actor: lifecycle isn't exercised by the automated unit tests (no ACTOR_* env vars in this test environment) — covered instead by the live apify-cli run below.

Live end-to-end verification against the real internet (this developer does not hold, and this product needs, no credential at all — unlike ceis-lookup's disclosed gap):

  • Downloaded and parsed all four real CSVs directly (43,455 / 13 / 28,626 / 115,111 rows respectively) and ran real registration-number, product-name, and manufacturer-CNPJ searches against each — including the DIPIRONA SODICA record used as the running example above (registration 125680040, Prati Donaduzzi, a real, well-known, currently-active Brazilian medication) and real matches in all three other categories (a sunscreen in cosméticos, a household cleaner in saneantes, a condom brand in produtos para saúde).
  • Ran the actual Actor entry point via the official npx apify-cli run (which reads .actor/actor.json exactly as the real platform would), not just the library functions directly — confirmed correct dedup (a registration-number query and an overlapping product-name query in the same run charge the matched record only once), correct "not found" handling for a registration number verified not to exist, and a clean exit code 0. apify-cli validate-schema passes for both schemas.
  • Independently diagnosed and fixed the TLS chain issue live (see above) — curl, openssl s_client, and Python's ssl module against both the system CA store and certifi's bundle all reproduced the same failure before the fix, and all three stopped failing after it.

Not tested / could not verify locally:

  • Real pay-per-event charging behavior: running locally/via apify-cli run, the Apify SDK correctly no-ops Actor.push_data(charged_event_name=...) with the log line "Ignored attempt to charge for an event - the Actor does not use the pay-per- event pricing", because no Apify platform pricing config exists outside a real platform run — same disclosed limitation as cnpj-lookup/ pncp-lookup. The charging code path (including the event_charge_limit_reached handling) is exercised on every match but only confirmable after deploying and monetizing on the real platform.
  • Docker build: no Docker on this VPS (no root/sudo, same standing constraint as every prior product — see AGENTS.md). The Dockerfile is byte-for-byte the same template already proven to build successfully on Apify's infrastructure three times (cnpj-lookup ADR-006, pncp-lookup ADR-011), with only the package name changed.
  • Whether Apify's platform container has the same missing-intermediate TLS problem independently of this VPS — moot either way, since the fix (bundling the intermediate) doesn't depend on which CA store the container starts with, but the first live platform run is still the first time this exact code path runs somewhere other than this VPS — flagged as the first thing to double-check during deployment, the same "don't assume, verify on the real platform" discipline pncp-lookup applied to its own VPS-vs-platform networking gap (ADR-011).
  • No real paid usage, no Apify Store listing yet.

Deployment (status: built, tested, zero owner-only blockers found)

Unlike ceis-lookup (blocked on a Gov.br-login API key) and unlike the very first product cnpj-lookup (which needed one-time payout/profile setup before its first-ever publish), this product needs no new owner action at all — payout billing info, public profile, and Store Terms acceptance are Apify account-level settings already completed during cnpj-lookup's deployment (ADR-007) and confirmed to carry over automatically to every subsequent Actor on the same account (pncp-lookup, ADR-011). The remaining steps are the same proven sequence, mechanical rather than blocked:

  1. cd products/anvisa-products-lookup && npx apify-cli push — builds and deploys on Apify's infrastructure.
  2. Real remote smoke test: npx apify-cli call -i '{"registrationNumbers": ["125680040"], "categories": ["medicamento"]}' -o — should return the DIPIRONA SODICA record shown above. Worth specifically confirming the TLS fix works unchanged on Apify's actual container (see "Not tested" above).
  3. Set pay-per-event pricing (.actor/pay_per_event.json's product-record event at $0.02) and publish (isPublic: true, categories Business + Lead generation, matching the prior three) via the Apify REST API PUT /v2/acts/{actorId} — the same calls already proven working on this account three times (cnpj-lookup ADR-007, pncp-lookup ADR-011), should need no further owner action.
  4. Optional, non-blocking: a Store logo (assets/ directory reserved, empty) — same "ready but not required to publish" status pncp-lookup shipped with (ADR-011).
  5. Report real usage/revenue into BUSINESS.md once it exists — do not fabricate numbers before they exist.