#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

PlanExtractores
Diagnóstico (prueba)2
Starter2
API5
Enterprise Bronce / Silver / GoldIlimitados

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

CampoTipoDescripción
extractor_idstringIdentificador del extractor (ext_…).
namestringNombre que le diste (1–120 caracteres).
is_enabledbooleanfalse lo deja configurado pero sin correr.
trigger_kindstringQué lo dispara: connection_created, connection_reactivated o schedule.
schedule_kindstring | nullCadencia, solo con trigger_kind: schedule.
schedule_specobjectParámetros de la cadencia. {} cuando no lleva.
timezonestringZona horaria IANA que decide en qué día cae la cadencia. Por defecto America/Mexico_City.
scopestringCuánto hacia atrás descarga: full_history, last_n_months o since_watermark.
scope_monthsinteger | nullN meses, solo con scope: last_n_months (1–240).
data_source_keysstring[]Fuentes de datos que trae.
created_atstringFecha de creación (ISO 8601).

#Disparadores

trigger_kindCuándo corre
connection_createdAl conectar un RFC a tu organización.
connection_reactivatedAl reconectar un RFC (por ejemplo, tras reactivar su cobro).
scheduleEn 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.

scopeRango que descarga
full_historyTodo el histórico disponible (desde 2018) hasta hoy.
last_n_monthsLos últimos scope_months meses (aproximados a 30 días cada uno) hasta hoy. Requiere scope_months entre 1 y 240.
since_watermarkDesde 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_kindschedule_specSignificado
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.

ClaveFuente
sat_cfdi_issuedCFDIs emitidos.
sat_cfdi_receivedCFDIs recibidos.
sat_csfConstancia de Situación Fiscal.
sat_opinion_32dOpinión de Cumplimiento (32-D).
sat_obligationsObligaciones fiscales.
sat_declaracion_anualDeclaración Anual.
sat_declaracion_mensualDeclaración Mensual.
sat_miinformacionMi Información Fiscal. Obligatoria (ver abajo).
sat_certificatesCertificados y llaves públicas (CSD y e.firma).
sat_rugRegistro Ú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 PATCH no la quita. Un data_source_keys que 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-entities restringe 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_at má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:

SuperficieComportamiento con una ventana acotada
Listado y detalle de CFDIsDevuelven solo los CFDIs dentro de la ventana
Drill-downs de riesgo, retenciones, deducciones, concentraciónIgual: 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

GET/extractors

Devuelve 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
curl https://api.clarisfy.com/v1/extractors \
  -H "Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe"

Respuesta 200 OK:

JSON
[
  {
    "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

POST/extractors

#Cuerpo de la petición

CampoTipoDescripción
namestringRequerido. Nombre del extractor (1–120 caracteres).
trigger_kindstringRequerido. connection_created, connection_reactivated o schedule.
scopestringRequerido. full_history, last_n_months o since_watermark.
data_source_keysstring[]Requerido. Al menos una fuente de datos.
schedule_kindstring | nullRequerido con trigger_kind: schedule; debe ir en null con los demás.
schedule_specobject | nullParámetros de la cadencia. Por defecto {}.
scope_monthsinteger | nullRequerido con scope: last_n_months (1–240); debe ir en null con los demás.
timezonestringZona horaria IANA. Por defecto America/Mexico_City.
is_enabledbooleanPor defecto true.

#Ejemplo

cURL
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:

JSON
{
  "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 HTTPCausa
403La credencial no tiene rol owner o admin.
409Tu plan ya no permite otro extractor. El mensaje dice cuántos permite y cuántos tienes.
422Una 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

PATCH/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:

cURL
# 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ámetroTipoDescripción
extractor_idstringIdentificador del extractor (ext_…).

#Ejemplo

cURL
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 HTTPCausa
400extractor_id con formato inválido.
403La credencial no tiene rol owner o admin.
404El extractor no existe o es de otra organización.
422Una 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

POST/extractors/{extractor_id}/run

Corre 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
curl -X POST https://api.clarisfy.com/v1/extractors/ext_01jtvm3qbwfr8at3kbq72yaeb1/run \
  -H "Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe"

#Respuesta

JSON
{
  "status": "dispatched",
  "connections": 3,
  "dispatched": 2
}
CampoTipoDescripción
statusstringdispatched, o no_connections si todavía no tienes ningún RFC activo — eso no es un error, no hay de dónde descargar.
connectionsintegerRFCs conectados para los que corrió.
dispatchedintegerDescargas 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 HTTPCausa
400extractor_id con formato inválido.
403La credencial no tiene rol owner o admin.
404El extractor no existe o es de otra organización.
409El extractor está pausado. Actívalo primero: ejecutar uno pausado contradiría el haberlo pausado.
429Ya 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

DELETE/extractors/{extractor_id}

Elimina el extractor y libera su lugar en el plan. Responde 204 No Content, sin cuerpo.

cURL
curl -X DELETE https://api.clarisfy.com/v1/extractors/ext_01jtvm3qbwfr8at3kbq72yaeb1 \
  -H "Authorization: Bearer clf_live_secret_9K3mZ1pQ7rTx8vB4nH6dLwYe"

#Errores

Código HTTPCausa
400extractor_id con formato inválido.
403La credencial no tiene rol owner o admin.
404El extractor no existe o es de otra organización.