# Tanzania, Zambia & Botswana Registered Medicines (`a-g-d/africa-medicines`) Actor

Registered medicines from the TMDA (Tanzania), ZAMRA (Zambia) and BoMRA (Botswana) public registers as English-keyed JSON: registration number, brand and generic names, ingredients, strength, form, holder, local representative, manufacturer, countries and ISO dates.

- **URL**: https://apify.com/a-g-d/africa-medicines.md
- **Developed by:** [Aloever Dulay](https://apify.com/a-g-d) (community)
- **Categories:** E-commerce, Other
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product records

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

## Tanzania, Zambia & Botswana Registered Medicines (TMDA, ZAMRA, BoMRA)

The public registers of medicines authorised in **Tanzania** (Tanzania Medicines and Medical
Devices Authority, TMDA), **Zambia** (Zambia Medicines Regulatory Authority, ZAMRA) and
**Botswana** (Botswana Medicines Regulatory Authority, BoMRA), as clean JSON with the same
English keys for all three countries: registration number, brand and generic names, active
ingredients, strength, dosage form, holder, local representative, manufacturer, countries,
and ISO registration and expiry dates.

About 14,950 registered products on 2026-10-14:

| `countries` | Register                                                   | Products |
| ----------- | ---------------------------------------------------------- | -------- |
| `TZ`        | TMDA registered medicines (human and veterinary)           | 5,656    |
| `ZM`        | ZAMRA registered medicines (human and veterinary)          | 3,514    |
| `BW`        | BoMRA registered human medicines (the "drug enquiry" page) | 5,779    |

### Who needs this

- **Pharmaceutical companies, distributors and importers** checking which products are
  registered in Tanzania, Zambia and Botswana, who holds each registration and when it
  expires.
- **Market-access and regulatory-affairs teams** comparing portfolios across the three
  markets, watching competitors' registrations and upcoming expiries.
- **Procurement, tender and supply-chain teams, NGOs and donors** verifying that a product
  and its manufacturer are registered before buying or shipping.
- **Pharmacovigilance, research and journalism** studying what is registered, by whom and
  from which countries.
- **AI agents and automations** that need one stable schema instead of three portals.

### Input

| Field                | Type    | Default            | Description                                                                                                  |
| -------------------- | ------- | ------------------ | ------------------------------------------------------------------------------------------------------------ |
| `countries`          | array   | `["TZ","ZM","BW"]` | Which registers to read: `TZ` Tanzania, `ZM` Zambia, `BW` Botswana.                                          |
| `brandName`          | string  | `""`               | Brand (trade) name contains this text, any case (`panadol`).                                                 |
| `genericName`        | string  | `""`               | Generic name or an active ingredient contains this text, any case (`amoxicillin`).                           |
| `registrationNumber` | string  | `""`               | Registration number contains this text, ignoring spaces and case (`TAN 22 HM`, `ZAMRA-HM-25`, `BOT2404268`). |
| `manufacturer`       | string  | `""`               | Manufacturer name contains this text, any case (`cipla`).                                                    |
| `holder`             | string  | `""`               | Registrant / marketing authorisation holder name contains this text, any case (`aurobindo`).                 |
| `registeredSince`    | string  | `""`               | Registered on or after this date (`YYYY-MM-DD`).                                                             |
| `expiringBefore`     | string  | `""`               | Registration expires before this date (`YYYY-MM-DD`).                                                        |
| `maxItemsPerCountry` | integer | `100`              | Stop each country after this many products (1-10,000).                                                       |
| `proxyConfiguration` | object  | no proxy           | Optional Apify Proxy, if a portal is unreachable from Apify's network.                                       |

Filters combine with AND. The portals themselves filter on brand name, registration number
and holder (and, in Zambia, manufacturer), which keeps those searches to one or two
requests; every filter is also checked on each product, so results are the same in all
three countries. The registers are listed in the regulator's record order, not by date, so
`registeredSince`, `expiringBefore` and `genericName` read the whole register (1 to 2
minutes per country).

### Output

One dataset item per registered product, with the same keys for every country; a field a
register does not publish is `null` (for example `packSize` and `schedule` outside Botswana).
Text is kept as the register publishes it with the whitespace tidied; dates are ISO
(`YYYY-MM-DD`). The Output tab on this page documents every field, with one table view per
country, and a run summary (`OUTPUT`) reports per country what was stored and why it
stopped.

A real Tanzania item (2026-10-14):

```json
{
  "country": "TZ",
  "countryName": "Tanzania",
  "regulator": "TMDA",
  "registrationNumber": "TAN 22 HM 0470",
  "brandName": "Doxyzen",
  "genericName": "Doxycycline HCl",
  "activeIngredients": ["Doxycycline Hyclate equivalent to Doxycycline 100 mg"],
  "strength": "100",
  "dosageForm": "Capsules",
  "packSize": null,
  "classification": "Human Medicinal Product",
  "schedule": null,
  "holder": "ZENUFA LABORATORIES LTD",
  "holderCountry": "Tanzania",
  "localRepresentative": "ZENUFA LABORATORIES LTD",
  "manufacturer": "Zenufa Laboratories Ltd",
  "manufacturerCountry": "Tanzania",
  "registeredAt": "2022-12-05",
  "expiresAt": "2027-12-04",
  "registrationStatus": "Registered/Compliant",
  "validityStatus": "Registered/Compliance",
  "atcCode": null,
  "sourceUrl": "https://imis2.tmda.go.tz/portal/#/public/registered-medicines",
  "fetchedAt": "2026-10-14T22:34:33.855Z"
}
```

A real Zambia item:

```json
{
  "country": "ZM",
  "countryName": "Zambia",
  "regulator": "ZAMRA",
  "registrationNumber": "ZAMRA-HM-25-12",
  "brandName": "Azivent 500 Tablets",
  "genericName": "Azithromycin",
  "activeIngredients": ["Azithromycin Dihydrate eq to Azithromycin 500 mg"],
  "strength": "500 mg",
  "dosageForm": "Film-coated Tablets",
  "packSize": null,
  "classification": "Human Medicinal Product",
  "schedule": null,
  "holder": "Aristo Pharmaceuticals Private Limited",
  "holderCountry": "India",
  "localRepresentative": "Orange Pharma",
  "manufacturer": "Aristo Pharmaceuticals Private Limited",
  "manufacturerCountry": null,
  "registeredAt": "2025-01-17",
  "expiresAt": "2030-01-16",
  "registrationStatus": "Registered/Compliant",
  "validityStatus": "Registered/Compliance",
  "atcCode": null,
  "sourceUrl": "https://app.zamra.co.zm:42882/portal/#/public/registered-medicines",
  "fetchedAt": "2026-10-14T22:34:34.492Z"
}
```

A real Botswana item:

```json
{
  "country": "BW",
  "countryName": "Botswana",
  "regulator": "BoMRA",
  "registrationNumber": "BOT2500021",
  "brandName": "ARCHIFAR 500MG",
  "genericName": "MEROPENEM",
  "activeIngredients": ["Meropenem trihydrate 500mg"],
  "strength": "500mg",
  "dosageForm": "Powder for solution for injection of infusion",
  "packSize": "Single Vials",
  "classification": "Generic Medicines",
  "schedule": "S2",
  "holder": "COSPHARM INVESTMENTS NAMIBIA (PTY) LTD",
  "holderCountry": "Namibia",
  "localRepresentative": "Cospharm Investments Pty Ltd.",
  "manufacturer": "Medochemie Ltd.",
  "manufacturerCountry": "Cyprus",
  "registeredAt": "2025-02-20",
  "expiresAt": "2030-02-20",
  "registrationStatus": "Registered/Compliant",
  "validityStatus": "Registered/Compliance",
  "atcCode": null,
  "sourceUrl": "https://brims.bomra.co.bw/#/public/drug-enquiry",
  "fetchedAt": "2026-10-14T22:34:37.506Z"
}
```

Notes on the fields:

- **Company names** (`holder`, `localRepresentative`, `manufacturer`) are names only: the
  street addresses and plant designations some registers add after a name are cut off
  ("ADCOCK INGRAM LIMITED (AIL) 1 New Road, …" becomes "ADCOCK INGRAM LIMITED (AIL)";
  "Hetero Labs Limited, Unit-III" becomes "Hetero Labs Limited"). Several manufacturers
  are joined with "; ".
- **Countries** are English names as published; TMDA's capitals are title-cased
  ("UNITED KINGDOM" becomes "United Kingdom"). Zambia's register sometimes puts an address
  fragment in the manufacturer country (" India 118-120"); such values become `null`.
- **Dates** are the register's own. A few registration dates lie in the future (data-entry
  errors in the register, e.g. 2030-06-03); they are kept as published.
- **ATC codes** are rare: TMDA publishes the ATC group's name (cut at 50 characters), not
  the code, so `atcCode` is usually `null`.
- **sourceUrl** is the country's public register page. Its rows load through the portal's
  own search, so the link opens the register, not the product.

### Pricing

Pay per event:

| Event            | Charged for                                    |
| ---------------- | ---------------------------------------------- |
| `product-record` | Each registered product stored in the dataset. |

Apify's standard run-start event covers starting the actor. Products are stored first and
charged after, so you never pay for data you did not receive. When your spending limit runs
out, the run stops cleanly and never stores an unpaid product.

### Data sources and politeness

- **Sources:** each regulator's public registered-medicines page, linked from its website:
  TMDA's at `https://imis2.tmda.go.tz/portal/#/public/registered-medicines`, ZAMRA's at
  `https://app.zamra.co.zm:42882/portal/#/public/registered-medicines` and BoMRA's at
  `https://brims.bomra.co.bw/#/public/drug-enquiry`. The three run the same registration
  system; the actor asks it for rows the way each page's search does (up to 500 per
  request). No login, no captcha.
- **TLS:** certificates are always verified. The Zambian and Botswanan servers leave out
  the intermediate certificate of their (valid) certificate chain; the actor carries the
  issuers' published intermediates (DigiCert, SSL.com) and adds them to the trusted
  certificates for those two hosts only.
- **robots.txt:** the TMDA and ZAMRA portal hosts have none; BoMRA's portal disallows only
  its application folders and login pages, not the register; the regulators' main sites
  allow everything or disallow only `/wp-admin/`. The actor still
  - waits **at least 1 second** after each request to a portal ends before the next one
    starts (retries included; a constant, not an input),
  - uses **one connection per portal**, one request at a time (the three countries run
    side by side, each on its own portal),
  - identifies itself honestly as
    `africa-medicines-actor/0.1 (+https://apify.com/a-g-d/africa-medicines)`,
  - asks only for the rows it needs: 10 products per country take one request each.
- **Measured on 2026-10-14:** 10 products per country in 8 s (3 requests); a brand search
  for "paracetamol" in all three in 4 s (31 products, 3 requests); the whole Zambian
  register (3,514) in 28 s (8 requests, about 1.5 MB each); all three whole registers
  (14,949) in 2 min 17 s (32 requests). Tanzania's pages arrive compressed (about 130 KB
  per 500 rows); Zambia's and Botswana's do not (0.7 to 1.9 MB).
- **Resilience:** connection errors, timeouts, HTTP 5xx and 429, and error answers are
  retried with exponential backoff and jitter inside a run-wide budget. A refusal, a
  challenge page or a changed answer stops that country with a clear message rather than
  working around it. **One country down does not stop the others**: their products are
  stored, the run summary names the country that failed and why, and the run fails only
  when every requested country fails.
- **Run timeout:** the default run timeout is 30 minutes, far more than the three whole
  registers need. If a run would still outlast its timeout (for example a shorter one you
  set), the actor stops requesting 20 seconds before it, keeps everything stored and ends
  SUCCEEDED with a status message saying so.
- **Terms:** TMDA's website has a terms page ("These are the terms of use for this
  website. Your continued use of this site confirms your acceptance of these terms.", with
  no further clauses) and a copyright statement ("This website and its contents are
  copyright of the Tanzania Medicines and Medical Devices Authority. All rights
  reserved."). BoMRA's website footer reads "© 2026 BoMRA. All rights reserved."; ZAMRA's
  "© Copyright ZAMRA 2026". None of them mentions automated access. The registers are
  published so the public can check which medicines are authorised. Check each
  regulator's terms for your own use of the data.

### Data and privacy

The registers publish product and company data: registered products, the companies that
hold, make or represent them, and dates. The actor outputs only the fields listed above, an
allowlist:

- **Never output:** the portals' account and audit columns (in Tanzania and Zambia one
  of them carries staff e-mail addresses), their `nationalID` column, internal record ids
  other than the registration number, any e-mail address, phone number or street address.
  These columns are not even read from the answer.
- **Company names without addresses.** Botswana's register adds the company's street
  address to the holder and manufacturer columns, and Zambia's sometimes does; the actor
  keeps the name and drops the address. Any text value that contains an e-mail address or
  a phone number is output as `null`.
- **Only the register is read.** The actor calls the registered-products search and no
  other part of the portals (not the retention lists or account data some of them also
  serve).
- **People named as companies.** A register occasionally names a natural person as local
  representative (Zambia lists a few individuals). The actor outputs the name as the
  regulator publishes it on its public register, and nothing else about them. Each
  country's data protection law applies to personal data you store: use the data for the
  purpose it is published for, checking products and their registrations.

### Limitations

- **Which products are listed is each register's choice.** All three list registered,
  compliant products (status "Registered/Compliant"); suspended, withdrawn or expired
  registrations are not in these public lists. Tanzania and Zambia include veterinary
  medicines; Botswana's list is human medicines.
- **Record order, not date order.** The portals return products in their own record order,
  so date filters read the whole register; a full register still takes only 30 seconds to
  2 minutes.
- **Reported totals.** Tanzania's and Zambia's portals report a total slightly above the
  rows they serve (5,712 against 5,656; 3,666 against 3,514): they count some products
  twice. The actor reads until the last page and stores each product once.
- **Data quality is the register's.** Missing strengths, units published apart from the
  number (Tanzania's "100"), schedules written three ways in Botswana ("S2", "Schedule 2",
  "2") and the odd future date are kept as published.
- **A run is a snapshot.** Products added while a run pages through a register belong to
  the next run.

# Changelog

This Actor's version history is a separate document: https://apify.com/a-g-d/africa-medicines/changelog.md

# Actor input Schema

## `countries` (type: `array`):

Which registers to read. Each country is read on its own, side by side with the others; one register being down does not stop the rest.

## `brandName` (type: `string`):

The brand (trade) name contains this text, any case, e.g. "panadol". Leave empty for all.

## `genericName` (type: `string`):

The generic name or an active ingredient contains this text, any case, e.g. "amoxicillin". Leave empty for all.

## `registrationNumber` (type: `string`):

The registration number contains this text, ignoring spaces and case, e.g. "TAN 22 HM", "ZAMRA-HM-25" or "BOT2404268". Leave empty for all.

## `manufacturer` (type: `string`):

The manufacturer's name contains this text, any case, e.g. "cipla". Leave empty for all.

## `holder` (type: `string`):

The registrant or marketing authorisation holder's name contains this text, any case, e.g. "aurobindo". Leave empty for all.

## `registeredSince` (type: `string`):

Only products registered on or after this date (YYYY-MM-DD). The registers are not ordered by date, so the whole register is read.

## `expiringBefore` (type: `string`):

Only products whose registration expires before this date (YYYY-MM-DD). The whole register is read.

## `maxItemsPerCountry` (type: `integer`):

Stop each country after storing this many products (1 to 10,000). A whole register takes 1 to 3 minutes.

## `proxyConfiguration` (type: `object`):

Optional. Use Apify Proxy if a regulator's portal is unreachable from Apify's network.

## Actor input object example

```json
{
  "countries": [
    "TZ",
    "ZM",
    "BW"
  ],
  "brandName": "",
  "genericName": "",
  "registrationNumber": "",
  "manufacturer": "",
  "holder": "",
  "registeredSince": "",
  "expiringBefore": "",
  "maxItemsPerCountry": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `products` (type: `string`):

One item per registered product matching the input: country, regulator, registration number, brand and generic names, active ingredients, strength, dosage form, pack size, classification, schedule, holder and its country, local representative, manufacturer and its country, registration and expiry dates, statuses, ATC code, source page and fetch time. The dataset has one table view per country.

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

The OUTPUT record: per country, whether it succeeded, why it stopped, products stored, pages and rows read, and the error when a country failed.

# 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 = {
    "countries": [
        "TZ",
        "ZM",
        "BW"
    ],
    "maxItemsPerCountry": 10,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("a-g-d/africa-medicines").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 = {
    "countries": [
        "TZ",
        "ZM",
        "BW",
    ],
    "maxItemsPerCountry": 10,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("a-g-d/africa-medicines").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 '{
  "countries": [
    "TZ",
    "ZM",
    "BW"
  ],
  "maxItemsPerCountry": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call a-g-d/africa-medicines --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,a-g-d/africa-medicines"
        }
    }
}
```

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/rKoQgwRtJMPG6Tgup/builds/Dc2T9pIbSIOMXnMvQ/openapi.json
