Brazil ANVISA Registered Products Lookup
Pricing
$20.00 / 1,000 matched product record returneds
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
Maintained by CommunityActor 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 bymaxResultsPerQuery.manufacturerCnpjs— exact-match search by the CNPJ of the registration holder (detentor do registro), punctuation optional. Capped bymaxResultsPerQuery.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 toproductNames/manufacturerCnpjssearches (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.
Data source, legal basis & terms of use
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):
| Category | File | Rows (2026-08-17) | Backed by a published data dictionary? |
|---|---|---|---|
| Medicamentos | DADOS_ABERTOS_MEDICAMENTOS.csv | 43,455 | Yes |
| Cosméticos | DADOS_ABERTOS_COSMETICO.csv | 13 | Yes |
| Saneantes | TA_DA_PRODUTO_SANEANTE.CSV | 28,626 | Yes |
| Produtos para Saúde | TA_PRODUTO_SAUDE_SITE.csv | 115,111 | No (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:
- Inconsistent date formats across files — ANVISA's own CSVs are not
internally consistent: some date fields are
dd/mm/yyyy, others aremm/dd/yyyy, determined empirically per field using unambiguous (day>12) examples, not assumed. Full writeup with verified examples:anvisa_products_lookup/dates.pymodule docstring. - Server-side TLS chain misconfiguration —
dados.anvisa.gov.brdoes not send its intermediate CA certificate, so a fresh HTTP client (this Actor, on Apify's infra) failsCERTIFICATE_VERIFY_FAILEDby 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-maintainedcertifibundle, 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 theproduto_saudemulti-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 classpncp-lookupshipped and had to fix post-build, ADR-010) that a barehttpxtimeout/connect error is always wrapped, never left to crash the Actor — viahttpx.MockTransport, no real network calls in the automated suite.certs.py— the embedded certificate loads into a realssl.SSLContextwithout error and verification staysCERT_REQUIRED(the fix adds a trusted intermediate, it never disables verification).search.py— exact/substring/accent-insensitive matching and themaxResultsPerQuerycap.main.py— the pure_coerce_str_listinput-parsing helper. Likeceis-lookup's test suite, the fullasync with Actor:lifecycle isn't exercised by the automated unit tests (noACTOR_*env vars in this test environment) — covered instead by the liveapify-cli runbelow.
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.jsonexactly 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-schemapasses for both schemas. - Independently diagnosed and fixed the TLS chain issue live (see above)
—
curl,openssl s_client, and Python'ssslmodule against both the system CA store andcertifi'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-opsActor.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 ascnpj-lookup/pncp-lookup. The charging code path (including theevent_charge_limit_reachedhandling) 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-lookupADR-006,pncp-lookupADR-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-lookupapplied 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:
cd products/anvisa-products-lookup && npx apify-cli push— builds and deploys on Apify's infrastructure.- 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). - Set pay-per-event pricing (
.actor/pay_per_event.json'sproduct-recordevent at $0.02) and publish (isPublic: true, categories Business + Lead generation, matching the prior three) via the Apify REST APIPUT /v2/acts/{actorId}— the same calls already proven working on this account three times (cnpj-lookupADR-007,pncp-lookupADR-011), should need no further owner action. - Optional, non-blocking: a Store logo (
assets/directory reserved, empty) — same "ready but not required to publish" statuspncp-lookupshipped with (ADR-011). - Report real usage/revenue into
BUSINESS.mdonce it exists — do not fabricate numbers before they exist.