#Extractores
Conectar un RFC descargaba todo su histórico. Un extractor convierte eso en una decisión: qué fuentes de datos traer, cuánto hacia atrás y con qué disparador.
Dos reglas definen el recurso:
- Un extractor pertenece a la organización y aplica a todos los RFCs que tenga conectados. No hay cadencia por RFC.
- Tu plan limita cuántos extractores puedes configurar, nunca su frecuencia.
#Límite por plan
| Plan | Extractores |
|---|---|
| Diagnóstico (prueba) | 2 |
| Starter | 2 |
| API | 5 |
| Enterprise Bronce / Silver / Gold | Ilimitados |
Los extractores deshabilitados también cuentan: son configuración que conservas. Al llegar al tope, POST /extractors responde 409 con un mensaje que dice cuántos permite tu plan y cuántos tienes, para que elijas entre borrar uno y subir de plan.
#El objeto Extractor
| Campo | Tipo | Descripción |
|---|---|---|
extractor_id | string | Identificador del extractor (ext_…). |
name | string | Nombre que le diste (1–120 caracteres). |
is_enabled | boolean | false lo deja configurado pero sin correr. |
trigger_kind | string | Qué lo dispara: connection_created, connection_reactivated o schedule. |
schedule_kind | string | null | Cadencia, solo con trigger_kind: schedule. |
schedule_spec | object | Parámetros de la cadencia. {} cuando no lleva. |
timezone | string | Zona horaria IANA que decide en qué día cae la cadencia. Por defecto America/Mexico_City. |
scope | string | Cuánto hacia atrás descarga: full_history, last_n_months o since_watermark. |
scope_months | integer | null | N meses, solo con scope: last_n_months (1–240). |
data_source_keys | string[] | Fuentes de datos que trae. |
created_at | string | Fecha de creación (ISO 8601). |
#Disparadores
trigger_kind | Cuándo corre |
|---|---|
connection_created | Al conectar un RFC a tu organización. |
connection_reactivated | Al reconectar un RFC (por ejemplo, tras reactivar su cobro). |
schedule | En la cadencia que definas con schedule_kind (ver Cadencia) y además al conectar o reconectar un RFC: un extractor diario no espera a la medianoche para ver un RFC que acabas de conectar. |
#Alcance
scope decide el rango de fechas fiscales (issued_at) que se descarga cada vez que el extractor corre. El rango siempre termina hoy.
scope | Rango que descarga |
|---|---|
full_history | Todo el histórico disponible (desde 2018) hasta hoy. |
last_n_months | Los últimos scope_months meses (aproximados a 30 días cada uno) hasta hoy. Requiere scope_months entre 1 y 240. |
since_watermark | Desde donde llegó la última extracción hasta hoy. En su primera corrida, cuando todavía no hay marca de agua, descarga el histórico completo. |
#Cadencia
schedule_kind y schedule_spec solo aplican con trigger_kind: schedule; con los otros disparadores schedule_kind debe ir en null. La timezone del extractor es la que decide en qué día cae la cadencia.
schedule_kind | schedule_spec | Significado |
|---|---|---|
daily | {} | Todos los días. |
every_n_days | {"n": 7} | Cada N días. |
nth_weekday_monthly | {"weekday": 0, "nth": 1} | El N-ésimo día de la semana de cada mes. weekday 0 = lunes; el ejemplo es el primer lunes. |
Cada cadencia se ejecuta a la medianoche de la zona horaria del extractor. Un mes sin la N-ésima ocurrencia se salta: {"weekday": 0, "nth": 5} no corre en los meses que solo tienen cuatro lunes.
Al guardar un extractor programado no se descarga nada en ese momento: se calcula su próxima corrida. Si configuras "primer lunes" un miércoles, la primera extracción es el lunes siguiente, no ese mismo miércoles.
#Fuentes de datos
data_source_keys es la lista de fuentes que el extractor trae. Un extractor no puede traer lo que la conexión del RFC no tenga habilitado: se descarga la intersección entre ambas.
| Clave | Fuente |
|---|---|
sat_cfdi_issued | CFDIs emitidos. |
sat_cfdi_received | CFDIs recibidos. |
sat_csf | Constancia de Situación Fiscal. |
sat_opinion_32d | Opinión de Cumplimiento (32-D). |
sat_obligations | Obligaciones fiscales. |
sat_declaracion_anual | Declaración Anual. |
sat_declaracion_mensual | Declaración Mensual. |
sat_miinformacion | Mi Información Fiscal. Obligatoria (ver abajo). |
sat_certificates | Certificados y llaves públicas (CSD y e.firma). |
sat_rug | Registro Único de Garantías (premium). |
#Fuentes obligatorias
GET /fiscal-entities/data-sources marca cada fuente con is_mandatory. Hoy la única es sat_miinformacion, y no es opcional: trae los datos de registro del propio contribuyente —régimen, obligaciones, medios de contacto— que el resto de la plataforma da por hechos al calcular alertas, contactos y la CSF.
Se agrega del lado del servidor, así que:
- El extractor que te devolvemos puede traer más claves de las que enviaste. No es un error: no la pediste y ahí está.
- Quitarla con
PATCHno la quita. Undata_source_keysque la omita reemplaza el resto de la lista y la conserva a ella. - Lo mismo al conectar un RFC: una lista explícita en
POST /fiscal-entitiesrestringe lo demás, pero la obligatoria queda habilitada igual. Si no fuera así, la intersección entre extractor y conexión la dejaría fuera.
Fíltrala de cualquier selector que construyas, usando is_mandatory y no una lista fija de claves: ofrecer una casilla para algo que siempre vuelve marcado es peor que no ofrecerla.
#La ventana de visibilidad
Un mismo RFC puede estar conectado por varias organizaciones y se descarga una sola vez (conexiones virtuales). Lo que separa a cada organización no es lo que existe, sino lo que cada una puede leer: un techo lógico sobre issued_at.
- Techo — no puedes leer CFDIs con
issued_atmás nuevo que tu última extracción, aunque el dato ya exista porque otra organización lo descargó. - Piso — un extractor de 3 meses no te muestra los 8 años que otra organización ya descargó del mismo RFC.
- La ventana solo se abre: una extracción la ensancha y nada la encoge, así que lo que veías ayer no desaparece hoy.
#Dónde aplica
La ventana aplica a toda lectura de datos fiscales, no solo al listado de CFDIs:
| Superficie | Comportamiento con una ventana acotada |
|---|---|
| Listado y detalle de CFDIs | Devuelven solo los CFDIs dentro de la ventana |
| Drill-downs de riesgo, retenciones, deducciones, concentración | Igual: las filas fuera de la ventana no aparecen |
Sumarios por periodo (YYYY-MM) | El mes que la ventana corta se recorta a la fecha del techo; no se sirve completo ni se descarta |
| Analíticas y reportes calculados al momento (conceptos, financiamiento, posición de IVA, exposición EFOS/FX) | Se calculan solo sobre lo que tu ventana alcanza, así que sus cifras cuadran con lo que puedes listar |
Reportes precalculados (/reports/...) | 409 — agregan el histórico completo del RFC y no tienen un borde mensual que recortar |
Esto significa que un sumario mensual puede no cuadrar con el mismo mes visto por otra organización conectada al mismo RFC: cada una ve su propia ventana. Si necesitas el mes completo, amplía la extracción del RFC.
#Lista tus extractores
/extractorsDevuelve los extractores de tu organización, del más antiguo al más reciente. Es un arreglo directo, sin envelope de paginación.
#Ejemplo
curl https://api.clarisfy.com/v1/extractors \
-H "Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe"Respuesta 200 OK:
[
{
"extractor_id": "ext_01jtvm3qbwfr8at3kbq72yaeb1",
"name": "CFDIs al día",
"is_enabled": true,
"trigger_kind": "schedule",
"schedule_kind": "every_n_days",
"schedule_spec": { "n": 7 },
"timezone": "America/Mexico_City",
"scope": "since_watermark",
"scope_months": null,
"data_source_keys": ["sat_cfdi_issued", "sat_cfdi_received"],
"created_at": "2026-08-01T18:24:11Z"
}
]#Crea un extractor
/extractors#Cuerpo de la petición
| Campo | Tipo | Descripción |
|---|---|---|
name | string | Requerido. Nombre del extractor (1–120 caracteres). |
trigger_kind | string | Requerido. connection_created, connection_reactivated o schedule. |
scope | string | Requerido. full_history, last_n_months o since_watermark. |
data_source_keys | string[] | Requerido. Al menos una fuente de datos. |
schedule_kind | string | null | Requerido con trigger_kind: schedule; debe ir en null con los demás. |
schedule_spec | object | null | Parámetros de la cadencia. Por defecto {}. |
scope_months | integer | null | Requerido con scope: last_n_months (1–240); debe ir en null con los demás. |
timezone | string | Zona horaria IANA. Por defecto America/Mexico_City. |
is_enabled | boolean | Por defecto true. |
#Ejemplo
curl -X POST https://api.clarisfy.com/v1/extractors \
-H "Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe" \
-H "Content-Type: application/json" \
-d '{
"name": "Alta de RFC: último año",
"trigger_kind": "connection_created",
"scope": "last_n_months",
"scope_months": 12,
"data_source_keys": ["sat_cfdi_issued", "sat_cfdi_received"]
}'Respuesta 201 Created — el extractor creado:
{
"extractor_id": "ext_01jtvm3qbwfr8at3kbq72yaeb1",
"name": "Alta de RFC: último año",
"is_enabled": true,
"trigger_kind": "connection_created",
"schedule_kind": null,
"schedule_spec": {},
"timezone": "America/Mexico_City",
"scope": "last_n_months",
"scope_months": 12,
"data_source_keys": ["sat_cfdi_issued", "sat_cfdi_received"],
"created_at": "2026-08-01T18:24:11Z"
}#Errores
| Código HTTP | Causa |
|---|---|
403 | La credencial no tiene rol owner o admin. |
409 | Tu plan ya no permite otro extractor. El mensaje dice cuántos permite y cuántos tienes. |
422 | Una clave de data_source_keys no existe o está inactiva, o el cuerpo no cumple las reglas de schedule_kind / scope_months. |
#Actualiza un extractor
/extractors/{extractor_id}Actualización parcial: solo se escriben los campos presentes en el cuerpo, así que un PATCH con únicamente is_enabled no borra la cadencia.
#Campos dependientes
Dos pares de campos van amarrados: un disparador schedule exige schedule_kind (y cualquier otro disparador exige que no lo haya), y el alcance last_n_months exige scope_months (y cualquier otro alcance exige que no lo haya).
Al actualizar, la mitad que deja de aplicar se limpia sola. Para volver schedule un extractor por evento basta con mandar el disparador:
# la cadencia guardada se borra sola — no mandes schedule_kind: null
-d '{"trigger_kind": "connection_created"}'La dirección contraria no se adivina: pasar a schedule sin schedule_kind, o a last_n_months sin scope_months, responde 422. Elegir una cadencia por ti significaría empezar a consultar al SAT con un ritmo que nunca pediste.
#Parámetros de ruta
| Parámetro | Tipo | Descripción |
|---|---|---|
extractor_id | string | Identificador del extractor (ext_…). |
#Ejemplo
curl -X PATCH https://api.clarisfy.com/v1/extractors/ext_01jtvm3qbwfr8at3kbq72yaeb1 \
-H "Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe" \
-H "Content-Type: application/json" \
-d '{"is_enabled": false}'Respuesta 200 OK — el extractor actualizado, con la misma forma que en la creación.
#Errores
| Código HTTP | Causa |
|---|---|
400 | extractor_id con formato inválido. |
403 | La credencial no tiene rol owner o admin. |
404 | El extractor no existe o es de otra organización. |
422 | Una clave de data_source_keys no existe o está inactiva; el cuerpo no cumple las reglas de schedule_kind / scope_months; o el resultado quedaría sin la cadencia o los meses que su forma exige (pasar a schedule o a last_n_months sin ellos). |
El límite del plan no se revalida al actualizar: un PATCH nunca crea un extractor, así que no puede rebasar tu cuota.
#Ejecuta un extractor ahora
/extractors/{extractor_id}/runCorre el extractor de inmediato para todos los RFCs activos de tu organización, sin esperar su cadencia ni una reconexión. Útil justo después de crearlo: un extractor diario configurado al mediodía no haría nada visible hasta la medianoche.
No mueve el calendario. El siguiente disparo programado sigue donde estaba, así que esto no es una forma de adelantar la cadencia.
curl -X POST https://api.clarisfy.com/v1/extractors/ext_01jtvm3qbwfr8at3kbq72yaeb1/run \
-H "Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe"#Respuesta
{
"status": "dispatched",
"connections": 3,
"dispatched": 2
}| Campo | Tipo | Descripción |
|---|---|---|
status | string | dispatched, o no_connections si todavía no tienes ningún RFC activo — eso no es un error, no hay de dónde descargar. |
connections | integer | RFCs conectados para los que corrió. |
dispatched | integer | Descargas despachadas al SAT. Menor que connections cuando varias comparten RFC: por no-duplicidad se descarga una vez y la ventana de cada una se mueve igual. |
#Errores
| Código HTTP | Causa |
|---|---|
400 | extractor_id con formato inválido. |
403 | La credencial no tiene rol owner o admin. |
404 | El extractor no existe o es de otra organización. |
409 | El extractor está pausado. Actívalo primero: ejecutar uno pausado contradiría el haberlo pausado. |
429 | Ya se ejecutó hace poco. Ventana de 10 minutos por extractor, porque cada ejecución despacha una descarga por RFC conectado y el SAT limita cuántas acepta. El detail trae retry_after_seconds y la respuesta incluye Retry-After. |
#Elimina un extractor
/extractors/{extractor_id}Elimina el extractor y libera su lugar en el plan. Responde 204 No Content, sin cuerpo.
curl -X DELETE https://api.clarisfy.com/v1/extractors/ext_01jtvm3qbwfr8at3kbq72yaeb1 \
-H "Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe"#Errores
| Código HTTP | Causa |
|---|---|
400 | extractor_id con formato inválido. |
403 | La credencial no tiene rol owner o admin. |
404 | El extractor no existe o es de otra organización. |