# Colombia Sanitary Product Registrations - INVIMA, Per Record (`nexgensignal/co-sanitary-product-registration-records`) Actor

Colombia INVIMA sanitary product registrations (datos.gov.co ui32-p9f2) as clean per-registration records - product, modality, group, status and issue/expiry dates. Holder and party names dropped; no personal data. CC BY-SA 4.0, $0.05 per record.

- **URL**: https://apify.com/nexgensignal/co-sanitary-product-registration-records.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** Business, Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 sanitary registration records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Colombia Sanitary Product Registrations - INVIMA, Per Record

Colombia's INVIMA sanitary-registration registry (`datos.gov.co` resource `ui32-p9f2`) as clean,
per-registration reference data - **one row per distinct sanitary registration**, with every holder,
party and party-role column structurally removed so the dataset carries **no natural-person data**.

Each record is a registration: the file number (`expediente`), the sanitary registration number
(`rsynso`), the registered product, the authorised modality/use, the product group, the current status,
the issue and expiry dates, and the issuing INVIMA directorate. A single computed value, `party_count`,
reports how many source party-rows were folded into the registration - the aggregate itself, never a
party name.

### What one record represents

INVIMA (Instituto Nacional de Vigilancia de Medicamentos y Alimentos) publishes its registry as one row
per **registration-party pair**: the same registration recurs once for each party attached to it
(manufacturer, importer, packager - and, critically, natural-person roles such as **legal representative**,
**attorney/apoderado** and **pharmaceutical chemist**). This Actor collapses that to **one row per distinct
registration** by grouping on the registration attributes and counting the parties. The party names and
party roles are never selected, never grouped and never delivered.

The live registry holds **1,382,588 party-rows**, which fold into **392,556 distinct registrations** - the
grain this Actor delivers. Because INVIMA publishes no count on the resource, that figure was measured live
against the door at build time and is restated here so the number is auditable rather than asserted.

### Coverage and volume

**Colombia INVIMA sanitary product registrations - 392,556 distinct registrations (folded live from
1,382,588 source party-rows; measured at build time, INVIMA publishes no count on the resource).**

The registry spans foods, medicines, medical devices, cosmetics and other health-supervised product groups.
The Actor pages the Socrata SODA API with a server-side `GROUP BY` over the nine registration attributes,
20,000 groups at a time, and stops as soon as your **Maximum records** cap is met - so a small run samples
cheaply and a large run pulls the whole registry.

### Licence and attribution

Colombia open data on `datos.gov.co` is published under **Creative Commons Attribution-ShareAlike 4.0
(CC BY-SA 4.0)**. The full notice travels on every record:

> INVIMA (Colombia). Colombia open data (datos.gov.co), CC BY-SA 4.0. Reproduced unchanged with attribution; ShareAlike applies to any redistributed database. Product-registration attributes only; every holder/party name (titular, nombrerol) and party role (rol) is structurally dropped - no natural-person data.

The required attribution - `Instituto Nacional de Vigilancia de Medicamentos y Alimentos (INVIMA) - Colombia` - is stamped on every record. ShareAlike applies to any
database you redistribute from this data.

### Person-data policy

This is the defining property of the cell. The source registry attaches parties to each registration, and
some party roles are **held by natural persons** - the legal representative, the attorney (apoderado) and
the pharmaceutical chemist (quimico farmaceutico) among them, whose names appear in the source `nombrerol`
column. This Actor **structurally excludes** the holder column (`titular`), the party-name column
(`nombrerol`) and the party-role column (`rol`): they are never named in the query's `SELECT`/`GROUP BY`,
never read, and never delivered. A per-record assertion additionally rejects any of those keys, plus
generic person markers, if the source schema ever changed (verified with a planted-row test that injects a
person name into a holder/party field and confirms the record is refused). The result carries product,
registration and status information only - no natural-person data.

### Interpretation caveat

One record per distinct INVIMA sanitary registration: registration file (expediente) x sanitary number (rsynso) x product x modality x product group x status x issue/expiry dates x INVIMA directorate. party\_count is the number of source party-rows folded in (the only computed value). Holder names, party names and party roles are never read, grouped or emitted.

Values are reproduced verbatim from the registry; the Actor never rewrites a field. `party_count` is a
count of the folded source rows for that registration - it is the number of attached party-records, not a
measure of product volume or sales. Dates are the registry's own issue and expiry stamps.

### Data quality and freshness

`party_count` is delivered as a real number; every other field is the registry's verbatim string. The
`record_id` is the composite registration key, so the dataset is safe to diff, deduplicate or upsert. Every
run re-reads the live resource, so the data is as fresh as INVIMA republishes, and each record's
`observed_at` stamp dates the snapshot. The run's `RUN_RECEIPT` records how many records were delivered and
charged and confirms `charge_equals_delivered`.

### Provenance and compliance

Every run reads `www.datos.gov.co/robots.txt` at runtime; the gate result (URL, status, byte length,
SHA-256 of the policy, crawl-delay) is written to the run's `RUN_RECEIPT`. The `/resource/` API path is
outside the registry's disallowed `/browse` paths, and the Actor honours the published crawl-delay. The API
is keyless. The Actor never bypasses a block or fetches through a mirror.

### Inputs

- **Maximum records** (`maxRecords`) - hard cap on registration records delivered and billed. You are
  billed only for records actually delivered.

### Output

Records land in the Actor's default dataset and export as JSON, CSV, Excel or via the Apify API. A tabular
**overview view** surfaces the registration file, sanitary number, product, modality, group, status,
issue/expiry dates and `party_count`.

### Fields in detail

The record leads with the composite `record_id`, then `expediente` (registration file), `rsynso` (sanitary
registration number), `producto` (registered product), `modalidad` (authorised use/modality), `grupo`
(product group), `estadoregistro` (status, e.g. Vigente/Vencido), `fechaexpedicion` (issue date),
`fechavencimiento` (expiry date) and `nombredireccion` (issuing INVIMA directorate - an organisational unit,
never a person). `party_count` is the only computed value. The provenance block - source, source\_dataset,
licence, attribution, caveat, observed\_at - closes every record.

### Scaling and limits

Set **Maximum records** low to sample cheaply or high to pull the full registry. The Actor pages the SODA
API with a server-side aggregate and delivers incrementally, so memory stays flat regardless of how many
records you request, and you are billed only for what is delivered. Because INVIMA republishes the registry
on its own cycle, re-running the Actor picks up new registrations and status changes automatically, and
each record's `observed_at` stamp dates the snapshot - schedule a run to keep a downstream compliance or
market-monitoring table current. A registration expiring or lapsing shows up as a changed `estadoregistro`
or `fechavencimiento` on the next run, so a simple diff surfaces the registrations that moved.

### Why the registration grain

The source registry is party-shaped - one row per registration-party pair - which is convenient for the
regulator but wrong for most downstream uses: it inflates every registration by its number of parties and,
because some parties are natural persons, it embeds personal data in what is otherwise a product catalogue.
Folding to the registration grain fixes both problems at once. You get one clean row per registration, a
`party_count` if you care how many parties were attached, and zero natural-person data. If you need the
registration-to-product mapping, the product and modality are on the record; if you need to track status
over time, the status and expiry date are on the record and change between runs, so a diff surfaces exactly
the registrations that lapsed, renewed or changed use.

### Typical uses

Compliance and market-monitoring teams use this cell to keep a live table of which products hold a valid
Colombian sanitary registration, when each expires, and in what product group and modality - the backbone
of an import-eligibility or shelf-audit check. Analysts use it to size a product category (how many active
food or medicine registrations exist) or to watch renewals and lapses over time. Because the record is
keyed on the registration and carries the issue and expiry dates, it drops straight into a warehouse as a
slowly-changing dimension, and a scheduled run keeps it current with no manual reconciliation.

### Sibling Actors

It sits beside the fleet's CPSC product-recall records and the Colombia SISMED medicine-price records, which draw related product-safety and price registries. It shares its engineering - the runtime robots gate, push-then-charge billing and
verbatim-value discipline - with the fleet's other public-data records Actors. Where a sibling draws the
same door for a different grain (medicine prices from SISMED), this cell stays strictly at the registration
grain and folds away every party row, so the two never double-count.

# Actor input Schema

## `maxRecords` (type: `integer`):

Maximum records delivered and billed. You are billed only for records actually delivered. Raise it to pull the full set.

## Actor input object example

```json
{
  "maxRecords": 500
}
```

# Actor output Schema

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

The delivered Colombia sanitary product registration record.

# 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 = {
    "maxRecords": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/co-sanitary-product-registration-records").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 = { "maxRecords": 500 }

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/co-sanitary-product-registration-records").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 '{
  "maxRecords": 500
}' |
apify call nexgensignal/co-sanitary-product-registration-records --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgensignal/co-sanitary-product-registration-records"
        }
    }
}

```

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/0gvlGmeu2TFBoj8mj/builds/zKepnfVL91LjRLBuc/openapi.json
