# Panama RUC Scraper — DGI Company Registry & E-Invoicing Status (`registralia/panama-ruc-scraper`) Actor

Consulta RUC Panamá in bulk: look up Panamanian companies by RUC or name in the DGI's public e-invoicing registry — legal name, RUC, affiliation and issuing status, invoicing mode, affiliation date, commercial activity. JSON, CSV or Excel.

- **URL**: https://apify.com/registralia/panama-ruc-scraper.md
- **Developed by:** [Nico Dennis Günther](https://apify.com/registralia) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $14.00 / 1,000 company record returneds

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

## Panama RUC Scraper — DGI Company Registry & E-Invoicing Status

Scrape Panama's public **DGI registry of electronic invoicers** (*Facturadores Electrónicos*, Dirección General de Ingresos) by **RUC** or **company name** and get back a clean, English-keyed record: legal name, RUC, whether the taxpayer is affiliated to electronic invoicing and actually issuing e-invoices, its invoicing mode, affiliation date and registered commercial activity — plus a **tax-delinquency flag** from the DGI's official *Listado de Morosos* (taxpayers with arrears older than twelve months), with the amount owed per tax.

One RUC in, one structured record out — or one company name in, every registered match out. No account, no API key, no captcha solving: this Actor reads the same public search page a Panamanian accountant uses (*Consulta RUC Panamá*) and normalizes it for machines.

### What you get

For RUC `280-134-61098`:

```json
{
  "found": true,
  "query": "280-134-61098",
  "queryType": "ruc",
  "country": "PA",
  "ruc": "280-134-61098",
  "rucType": "company",
  "legalName": "BANCO GENERAL S A",
  "isAffiliated": true,
  "isIssuingElectronicInvoices": true,
  "invoicingMode": "pac",
  "invoicingModeOriginal": "PAC",
  "affiliationDate": "2023-11-02",
  "commercialActivity": "Servicios financieros, excepto seguros y fondos de pensiones",
  "dgiDelinquentListChecked": true,
  "onDgiDelinquentList": false,
  "dgiDelinquentTotalUsd": 0,
  "dgiDelinquentTaxes": [],
  "dgiDelinquentListDate": "2026-01-13",
  "source": "DGI — Dirección General de Ingresos de Panamá, Facturadores Electrónicos",
  "scrapedAt": "2026-09-19T10:20:00.000Z"
}
```

### Why this data matters

**Electronic invoicing is mandatory in Panama.** Since the DGI's phased roll-out, a business that is not affiliated to *Factura Electrónica* cannot issue a valid tax invoice — and an invoice you cannot deduct is a cost. `isAffiliated` and `isIssuingElectronicInvoices` tell you, from the authority's own list, whether a supplier can bill you legally today.

**The RUC is confirmed by the state, not by the supplier.** You get the legal name the DGI holds against that RUC, so the name on the contract, the name on the invoice and the name in the registry can be matched automatically.

**Names resolve to RUCs.** A name search returns every registrant whose name contains your text, with its RUC — the fastest way to turn a supplier list without tax IDs into one with them.

**Commercial activity and affiliation date** add context for KYB: what the company is registered to do, and how long it has been in the e-invoicing system.

**The delinquency flag is the DGI's own list.** Under Resolución 201-10281 the DGI publishes every natural and legal person with tax arrears older than twelve months, by RUC and tax type. `onDgiDelinquentList` tells you whether your counterparty is on it, `dgiDelinquentTotalUsd` how much is owed, and `dgiDelinquentTaxes` splits it by tax (`202 - ITBMS`, `101 - RENTA`, …). A supplier with six figures of unpaid ITBMS is a different credit risk from one with a clean record — now you see it in the same row.

### Use cases

| You are | You use it for |
|---|---|
| Accounts payable / procurement | Check that a Panamanian supplier can issue valid e-invoices before paying |
| KYB / AML platform | Confirm RUC ↔ legal name and enrich with activity and affiliation date |
| Fintech / lender | Verify borrowers and merchants against a government list |
| B2B sales team | Resolve company names to RUCs and qualify by activity |
| Data team | Enrich a Panama company list with authoritative registry fields |

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `queries` | array | — | RUC numbers (`280-134-61098`, `8-222-2782`, `155780087-2-2026`) for exact matches and/or company names for name searches. One per line; mixing is fine. |
| `maxResultsPerName` | integer | `50` | Cap per name search. RUC searches return the single exact match. |
| `checkDelinquentList` | boolean | `true` | Downloads the DGI *Listado de Morosos* once per run (~14 MB, 10–20 s) and adds the delinquency fields to every RUC-bearing record. Turn off for name-only runs where you do not need it. |
| `includeRaw` | boolean | `false` | Attaches the untouched registry row under `raw` for auditing. |
| `maxConcurrency` | integer | `3` | Parallel lookups, capped at 5. It is a public service; stay polite. |
| `requestTimeoutSecs` | integer | `30` | |
| `maxRetries` | integer | `3` | Exponential backoff on 429 and 5xx. |
| `proxyConfiguration` | object | off | Only needed if the registry rate-limits the datacenter IP. |

Simplest possible run:

```json
{ "queries": ["280-134-61098", "Banco General"] }
```

### Output notes

- Every RUC query produces exactly one dataset item; a name query produces one item per match (`matchIndex` / `matchTotal` tell you where you are in the result set).
- Failures are data, not silence: a RUC or name with no match comes back with `found: false` and `error: "not_found"`; network problems come back as `lookup_failed`.
- `rucType` is inferred from the RUC's shape — `company` for Registro Público folio formats, `natural_person` for province-based cédula formats and E-/N-/PE- prefixes, `unknown` otherwise.
- `invoicingMode` is `pac` (invoices through an authorised provider, *Proveedor Autorizado Calificado*) or `free_invoicer` (the DGI's free tool); the Spanish original is kept in `invoicingModeOriginal`.
- Dates are ISO (`YYYY-MM-DD`).
- Delinquency fields: `dgiDelinquentListChecked` (was the list available this run), `onDgiDelinquentList`, `dgiDelinquentTotalUsd`, `dgiDelinquentTaxes` (`[{ "tax": "202 - ITBMS", "amountUsd": 887.03 }]`) and `dgiDelinquentListDate` (publication date of the list as served by the DGI). The list has no names, so it is matched by RUC only.
- A RUC that is **not** in the e-invoicing registry but **is** on the delinquent list comes back as `found: false, error: "not_found"` **with** the delinquency fields — you still learn what the DGI holds against it.

### Pricing

Pay per event, and you only pay for what the registry actually returned:

| Event | Price | When |
|---|---|---|
| Company record | **$0.014** | Once per record returned — one per RUC found, one per match in a name search, and one per RUC that is missing from the e-invoicing registry but present on the delinquent list (you received DGI data) |
| Actor start | $0.0001 | Container startup. Not an access fee. |

**Not-found RUCs and names are free**, so a dirty input list costs you nothing extra. There is no minimum spend and no subscription.

A worked example: verifying 500 supplier RUCs — 500 × $0.014 = **$7.00**.

### Notes on the source

Data comes from two public DGI publications: the *Facturadores Electrónicos* search at `dgi-fep.mef.gob.pa`, and the *Listado de Morosos* workbook at `dgi.mef.gob.pa/listados-moroso/`. This Actor does not bypass any access control, does not authenticate and does not solve captchas — it submits the same public search form a browser does and downloads the same public file, passing the values through unchanged.

**Delinquent list freshness.** The DGI updates the workbook on its own schedule (typically weeks apart). `dgiDelinquentListDate` tells you which edition your run used; a taxpayer who settled yesterday can still appear until the next edition.

**Coverage.** This is the registry of taxpayers affiliated to Panama's electronic-invoicing system, not the complete RUC roll. A RUC that is `not_found` here may still exist as a taxpayer that has not yet joined e-invoicing — the message says so explicitly. As the mandate expands, coverage of active businesses grows with it.

**Personal data.** Sole traders (*personas naturales*) appear with their cédula-based RUC. Treat those records as personal data under your own GDPR / Ley 81 obligations.

**Not an official DGI product.** This Actor is an independent tool built by Echocall LLC. It is not affiliated with, endorsed by, or operated by the Dirección General de Ingresos, the Ministerio de Economía y Finanzas or any Panamanian government body. "DGI" and "RUC" are used descriptively to name the public data source.

### Roadmap

Next for Panama: officers and directors from the Registro Público, once the public interface can be read without circumventing anything. Same schema across the region: Ecuador (SRI, with ghost-taxpayer flags and firm tax debts) and Costa Rica (Hacienda, with *moroso* / *omiso* flags) are already live — see Related Actors.

### FAQ

**How do I look up a RUC number in Panama?**

The DGI publishes its list of electronic invoicers as an open search. This Actor queries it for you and hands back structured JSON, CSV or Excel instead of a web page — one row per RUC, in bulk.

**What is a RUC in Panama?**

The *Registro Único de Contribuyentes* is Panama's tax identifier. For companies it derives from the Registro Público folio (for example `280-134-61098` or the newer `155780087-2-2026`); for natural persons it is the cédula (`8-222-2782`) or a residency-based number (`E-8-123456`). The *DV* (check digits) are not part of the registry's display and are not needed for the search.

**Can I search by company name?**

Yes. Any entry that is not shaped like a RUC is treated as a name and matched against the registry's name field, returning every registrant that contains it, up to `maxResultsPerName`.

**Does a `not_found` mean the company does not exist?**

No. It means the RUC is not in the electronic-invoicing registry. The company may exist and simply not be affiliated yet; the error message states this.

**What does `onDgiDelinquentList: true` mean exactly?**

That the RUC appears on the DGI's published list of taxpayers with arrears older than twelve months (*Listado de Morosos*), in the edition dated `dgiDelinquentListDate`. It is the authority's own statement, not our assessment. Amounts are as published, in USD (Panama's balboa is pegged 1:1).

**Is scraping the DGI registry legal?**

This Actor reads a public government service. It does not authenticate, does not bypass access controls and does not solve captchas. Sole traders are natural persons, so treat their records as personal data under your own obligations.

**How much does a lookup cost?**

$0.014 per record returned; misses are free. Every new Apify account includes free monthly usage credit, which covers a few hundred lookups before you pay anything.

### Related Actors

- **Ecuador SRI RUC Scraper** — the official Ecuadorian registry with ghost-taxpayer fraud flags and firm tax debts.
- **Costa Rica Cedula Scraper** — Costa Rica's Hacienda registry, including the *moroso* and *omiso* flags.
- **LATAM Company Registry Scraper** — one call for a mixed list of Ecuadorian RUCs and Costa Rican cédulas, returning a single shared schema.

# Actor input Schema

## `queries` (type: `array`):

One entry per line: a Panamanian RUC (e.g. 280-134-61098 or 8-222-2782) for an exact match, or a company name (e.g. Banco General) for a name search. RUCs and names can be mixed.

## `maxResultsPerName` (type: `integer`):

A name search can match many registrants (10 per registry page). Stop after this many records per name. RUC searches always return the exact match only.

## `checkDelinquentList` (type: `boolean`):

Downloads the DGI <i>Listado de Morosos</i> (taxpayers with arrears older than 12 months) once per run and adds <code>onDgiDelinquentList</code>, <code>dgiDelinquentTotalUsd</code> and the per-tax breakdown to every RUC-bearing record. Adds roughly 10–20 seconds to the run.

## `includeRaw` (type: `boolean`):

Attach the untouched registry row (Spanish labels) under a `raw` field, for auditing.

## `maxConcurrency` (type: `integer`):

How many queries to run at once. The DGI site is a public service — keep this low.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for the registry to answer one request before giving up and retrying.

## `maxRetries` (type: `integer`):

How often to retry a request after rate limiting or a server error, with exponential backoff.

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

Optional. Only needed if the registry rate-limits the datacenter IP.

## Actor input object example

```json
{
  "queries": [
    "280-134-61098",
    "155780087-2-2026",
    "Banco General"
  ],
  "maxResultsPerName": 50,
  "checkDelinquentList": true,
  "includeRaw": false,
  "maxConcurrency": 3,
  "requestTimeoutSecs": 30,
  "maxRetries": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `companies` (type: `string`):

One normalized record per matching RUC: legal name, RUC, e-invoicing affiliation and issuing status, invoicing mode, affiliation date and registered commercial activity.

# 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 = {
    "queries": [
        "280-134-61098",
        "Banco General"
    ],
    "checkDelinquentList": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("registralia/panama-ruc-scraper").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 = {
    "queries": [
        "280-134-61098",
        "Banco General",
    ],
    "checkDelinquentList": True,
}

# Run the Actor and wait for it to finish
run = client.actor("registralia/panama-ruc-scraper").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 '{
  "queries": [
    "280-134-61098",
    "Banco General"
  ],
  "checkDelinquentList": true
}' |
apify call registralia/panama-ruc-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,registralia/panama-ruc-scraper"
        }
    }
}
```

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/JLVV6tqq1T2nqxAuh/builds/OB0Mm3y4qvsBE4p6x/openapi.json
