# SAT 69-B Check — Verificador de EFOS (México) (`nahua/sat-69b-check`) Actor

Verifica RFCs contra la lista completa del artículo 69-B del SAT (presuntos, desvirtuados, definitivos y sentencia favorable). Check Mexican RFCs against the SAT's official 69-B (EFOS) list.

- **URL**: https://apify.com/nahua/sat-69b-check.md
- **Developed by:** [Miguel Najera](https://apify.com/nahua) (community)
- **Categories:** Business, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 rfc verificado / rfc checkeds

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

## SAT 69-B Check — Verificador de EFOS (México) · by Nahua

**ES** · Verifica RFC contra la **lista del artículo 69-B del CFF** que el SAT publica en Datos Abiertos: presuntos, desvirtuados, definitivos y sentencia favorable. Cada resultado indica la situación, los oficios, las fechas de publicación, el historial de etapas y la fecha de corte de la lista.

**EN** · Checks Mexican RFCs against the **article 69-B list** the SAT publishes as open data: presumed, disproved, definitive and favorable ruling. Every result states the status, the oficios, the publication dates, the stage history and the list's cut-off date.

### Qué hace / What it does

1. Descarga el CSV oficial de Datos Abiertos del SAT y lo reutiliza hasta 24 horas.
2. Busca **exactamente** cada RFC (máximo 500 por ejecución).
3. Devuelve la situación vigente y todas las etapas del RFC en `historial`.

It downloads the official SAT open-data CSV, reuses it for up to 24 hours, looks up each RFC exactly (500 per run at most), and returns the current status plus every stage in `historial`.

### Entrada / Input

```json
{
  "rfcs": ["AAA080808HL8", "XAXX010101000"],
  "includeNotFound": true,
  "forceRefresh": false,
  "cacheTtlHours": 24
}
```

| Campo / Field | Tipo | Descripción |
|---|---|---|
| `rfcs` | `string[]` (1–500) | RFC a verificar; los duplicados se ignoran. También acepta texto separado por comas. / RFCs to check; duplicates are ignored. |
| `includeNotFound` | `boolean` (`true`) | Emitir también los RFC que no aparecen. / Also emit RFCs that do not appear. |
| `forceRefresh` | `boolean` (`false`) | Volver a descargar la lista aunque el caché siga vigente. / Re-download the list even if the cache is fresh. |
| `cacheTtlHours` | `integer` (1–168, `24`) | Vigencia del caché. / Cache TTL. |
| `cacheStoreName` | `string` | Store con nombre para el caché. Se crea en tu cuenta. / Named store for the cache, created in your account. |
| `sourceUrl` | `string` | URL del CSV; solo si el SAT lo mueve. / CSV URL; only if the SAT moves it. |

### Salida / Output

Un registro por RFC. Ejemplo con **datos ficticios**. / One item per RFC. Example with **fictitious data**.

```json
{
  "rfc": "EJE010101AB1",
  "valido": true,
  "found": true,
  "situacion": "Definitivo",
  "nombre": "EMPRESA EJEMPLO, S.A. DE C.V.",
  "anotacion": null,
  "numeroOficio": "500-05-2026-00002",
  "fechaOficio": "2026-02-20",
  "oficioIndividual": null,
  "fechaOficioIndividual": null,
  "medioDefensa": null,
  "fechaPublicacionSat": "2026-02-20",
  "fechaPublicacionDof": "2026-04-30",
  "codNota": null,
  "urlDof": null,
  "fuente": "SAT",
  "coberturaSat": "2026-09-30",
  "coberturaDof": null,
  "historial": [
    { "situacion": "Presunto", "fuente": "SAT", "oficioGlobal": "500-05-2025-00001", "fechaPublicacionSat": "2025-07-14", "fechaPublicacionDof": "2025-09-12" },
    { "situacion": "Definitivo", "fuente": "SAT", "oficioGlobal": "500-05-2026-00002", "fechaPublicacionSat": "2026-02-20", "fechaPublicacionDof": "2026-04-30" }
  ],
  "sourceUrl": "https://wu1agsprosta001.blob.core.windows.net/agsc-publicaciones/Datos_abiertos/Documents_AGAFF/Listado_completo_69-B.csv",
  "nota": "Información tomada de la lista de Datos Abiertos del SAT. Es informativa y no es una certificación: el portal oficial del SAT es la fuente autoritativa. / Information taken from the SAT open-data list. It is informational, not a certification: the official SAT portal is authoritative.",
  "advertencia": null
}
```

| Campo / Field | Significado / Meaning |
|---|---|
| `found` | `true` si el RFC aparece en la lista. `false` **solo** significa que no aparece en ella hasta `coberturaSat`. / `false` **only** means it does not appear in it up to `coberturaSat`. |
| `situacion` | `Presunto`, `Desvirtuado`, `Definitivo` o `Sentencia Favorable`. |
| `coberturaSat` | Fecha de corte que declara el archivo. / Cut-off date stated by the file. |
| `historial` | Todas las etapas del RFC, de la más antigua a la más reciente. / Every stage, oldest first. |
| `numeroOficio`, `fechaOficio` | Oficio global de la etapa vigente. / Global oficio of the current stage. |
| `fechaPublicacionSat`, `fechaPublicacionDof` | Fechas de publicación de la etapa vigente, tal como las trae el CSV del SAT. / Publication dates of the current stage, as stated in the SAT CSV. |
| `fuente` | Siempre `SAT`. / Always `SAT`. |
| `anotacion` | Texto legal pegado al nombre, como "En cumplimiento a la sentencia...". / Legal text attached to the name. |
| `advertencia` | Se llena si se usó una copia guardada porque el SAT no respondió. **Léelo siempre.** / Filled when a saved copy was used because the SAT did not respond. **Always read it.** |
| `nota` | Alcance del resultado. / Scope of the result. |
| `coberturaDof`, `urlDof`, `codNota`, `oficioIndividual`, `fechaOficioIndividual`, `medioDefensa` | Siempre `null`. Se conservan para que el esquema no cambie. / Always `null`, kept so the schema does not change. |

Si un RFC no aparece, `nota` lo dice con la fecha de corte y aclara que es informativo, no una certificación. Un RFC con formato inválido devuelve `valido: false`, no se consulta y no se cobra. El resumen de la ejecución queda en el registro `SUMMARY` del key-value store.

If an RFC does not appear, `nota` says so with the cut-off date and states that this is informational, not a certification. An invalid RFC returns `valido: false`, is not looked up and is not charged. The run summary is in the `SUMMARY` record of the key-value store.

### Precio / Pricing (pay-per-event)

| Evento / Event | Precio / Price | Cuándo / When |
|---|---|---|
| `apify-actor-start` | **US$ 0.001** por ejecución | Una vez al iniciar. / Once per run. |
| `rfc-checked` | **US$ 0.002** por RFC | Cada RFC válido consultado, aparezca o no. / Each valid RFC looked up, whether it appears or not. |

### Uso con agentes de IA (MCP) / AI agents (MCP)

```text
https://mcp.apify.com?tools=nahua/sat-69b-check
```

Agrega esa URL a tu cliente MCP. La primera conexión abre el navegador para iniciar sesión.

Prompt de ejemplo: *«Revisa estos RFC en el 69-B y dime la situación de cada uno y la fecha de corte de la lista.»*

Add that URL to your MCP client; the first connection opens the browser to sign in. Tell your agent to report `coberturaSat` and `advertencia`, not just `found`.

### Fuente y actualización / Data source and updates

- `Listado_completo_69-B.csv`, del [portal de Datos Abiertos del SAT](https://www.sat.gob.mx/minisitio/DatosAbiertos/contribuyentes_publicados.html), que indica uso, reutilización y redistribución libres.
- El SAT actualiza el archivo por cortes. El 6 de noviembre de 2026, el archivo vigente tenía corte al 30 de septiembre de 2026.
- El Actor se identifica como `nahua-apify-actor/1.0` y descarga el archivo una vez cada 24 horas como máximo, salvo que pidas `forceRefresh`.

From the SAT open-data portal, which states free use, reuse and redistribution. The SAT updates the file in batches; on November 6, 2026 the current file had a September 30, 2026 cut-off.

### Límites / Limits

**No es una certificación.** Es una consulta informativa de una lista publicada. El portal oficial del SAT es la fuente autoritativa.

*It is not a certification. The official SAT portal is authoritative.*

**Lo posterior al corte puede faltar.** El SAT publica notificaciones nuevas entre un corte y otro, así que `found: false` no descarta un RFC notificado después de `coberturaSat`. Para decisiones críticas, consulta también el portal del SAT.

*Anything after the cut-off may be missing, so `found: false` does not rule out an RFC notified after `coberturaSat`. For critical decisions, also check the SAT portal.*

**Filas suprimidas por orden judicial.** 91 filas del CSV tienen el RFC oculto (`XXXXXXXXXXXX`) y no se pueden consultar.

*91 CSV rows have the RFC masked by court order and cannot be looked up.*

**Una situación favorable tiene alcance limitado.** `Desvirtuado` y `Sentencia Favorable` se limitan a los comprobantes o actos revisados y dejan a salvo las facultades de la autoridad; no equivalen a una constancia de cumplimiento. Tampoco `Presunto` es una resolución final.

*Favorable stages are limited in scope and are not proof of compliance; `Presunto` is not a final ruling.*

**Solo artículo 69-B.** No cubre el 69-B Bis ni el artículo 69.

*Article 69-B only; 69-B Bis and article 69 are not covered.*

**Solo RFC exacto.** No hay búsqueda por nombre ni exportación de la lista.

*Exact RFC only: no name search and no list export.*

**La primera ejecución descarga la lista.** En cada cuenta, la primera ejecución descarga el CSV (4.9 MB) y prepara el caché. En nuestra prueba local tardó unos 6 segundos, y 1.5 segundos con caché. En Apify puede variar.

*The first run in each account downloads the CSV (4.9 MB) and builds the cache: about 6 seconds in our local test, 1.5 seconds cached. It may vary on Apify.*

### Privacidad / Privacy

La lista incluye personas físicas. Por eso:

- La salida solo contiene datos de los RFC que enviaste.
- El caché crea en tu cuenta un key-value store llamado `nahua-sat-69b-cache`. Guarda cada fila cifrada con una llave derivada de su RFC, no filas legibles. Es seudonimización: evita que el caché sea una copia consultable de la lista, pero no sustituye a un control de acceso.

*The list includes individuals. Output only holds the RFCs you sent, and the cache store created in your account holds rows encrypted with a key derived from each RFC, which is pseudonymization rather than access control.*

### Ejecución local / Local run

```bash
npm install
npm test
npx apify-cli run -i '{"rfcs":["AAA080808HL8","XAXX010101000"]}'
```

# Actor input Schema

## `rfcs` (type: `array`):

Lista de RFC (12 o 13 caracteres). Máximo 500 por ejecución; se eliminan duplicados. / List of RFCs (12 or 13 characters). Max 500 per run; duplicates are removed.

## `includeNotFound` (type: `boolean`):

Si es verdadero, cada RFC que NO aparece en la lista también genera un registro con found=false. / If true, RFCs absent from the list also produce an item with found=false.

## `forceRefresh` (type: `boolean`):

Ignora la vigencia del caché y vuelve a descargar el CSV del SAT. / Ignore the cache TTL and re-download the SAT CSV.

## `cacheTtlHours` (type: `integer`):

Horas durante las que se reutiliza la lista del SAT (1–168). / Hours the SAT list is reused (1–168).

## `cacheStoreName` (type: `string`):

Key-value store con nombre donde se guarda el caché entre ejecuciones; se crea en tu cuenta y solo contiene datos sellados por RFC, nunca filas legibles. Vacío = store de la ejecución: nada se reutiliza y cada ejecución descarga la lista. / Named key-value store for the cache; created in your account and holding only RFC-sealed data, never readable rows. Empty = the run store: nothing is reused and every run downloads the list.

## `sourceUrl` (type: `string`):

Solo cambia esto si el SAT mueve el archivo. / Only change this if the SAT moves the file.

## Actor input object example

```json
{
  "rfcs": [
    "AAA080808HL8",
    "XAXX010101000"
  ],
  "includeNotFound": true,
  "forceRefresh": false,
  "cacheTtlHours": 24,
  "cacheStoreName": "nahua-sat-69b-cache",
  "sourceUrl": "https://wu1agsprosta001.blob.core.windows.net/agsc-publicaciones/Datos_abiertos/Documents_AGAFF/Listado_completo_69-B.csv"
}
```

# Actor output Schema

## `resultados` (type: `string`):

Un registro por RFC con situación, fuente, cobertura e historial. / One item per RFC with status, source, coverage and history.

## `resumen` (type: `string`):

Conteos, fechas de cobertura y advertencias de la ejecución. / Counts, coverage dates and warnings for the run.

# 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 = {
    "rfcs": [
        "AAA080808HL8",
        "XAXX010101000"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nahua/sat-69b-check").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 = { "rfcs": [
        "AAA080808HL8",
        "XAXX010101000",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("nahua/sat-69b-check").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 '{
  "rfcs": [
    "AAA080808HL8",
    "XAXX010101000"
  ]
}' |
apify call nahua/sat-69b-check --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nahua/sat-69b-check"
        }
    }
}
```

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/HPv9PEEyqSXXqeUMN/builds/jMpf2UR7GDZzwqrb6/openapi.json
