Folios y CAF

Listar los CAF de una empresa, contar los folios de un rango y volver a bajar un CAF puntual con folioInicial.

Esta guía cubre tres operaciones de CAF que se usan juntas, en este orden:

  1. caf_v1_listar: qué CAF autorizó el SII para la empresa y el tipo de documento.
  2. caf_v1_estado_folios, opcional: cuántos folios de uno de esos CAF el SII todavía no recibió, cuántos ya no permite anular y cuántos se anularon.
  3. caf_v1_reobtener con folioInicial: volver a bajar uno de esos CAF, ya timbrado.

Ninguna de las tres pide folios nuevos: para eso está caf_v1_descargar. Las tres están vigentes desde el despliegue de la API del 2026-10-17 (versión 1.5.0 del contrato).

Antes de empezar

  • El certificado va en el cuerpo del POST, con Data y Contrasenna, como en las demás operaciones de CAF. Mande siempre el cuerpo: sin él, caf_v1_listar y caf_v1_estado_folios responden CERT_REQUERIDO. caf_v1_reobtener también, desde el despliegue de la versión 1.5.3; hasta entonces responde un error del framework en JSON.
  • Pase ambiente explícito, 0 o 1, y el mismo en las tres. Si lo omite, las tres corren en producción. Con un número distinto de 0 y 1, caf_v1_listar y caf_v1_estado_folios corren en homologación y caf_v1_reobtener en producción: no corren en el mismo ambiente. Más en Ambientes.
  • El certificado no se valida en el mismo ambiente en las tres. caf_v1_listar y caf_v1_estado_folios lo validan en el ambiente pedido. caf_v1_reobtener, también con folioInicial, lo valida siempre en producción, aunque pida ambiente=0. Un certificado habilitado solo en el ambiente de certificación del SII sirve para listar con ambiente=0, pero no para reobtener: el error habla del certificado, no del ambiente.
  • El titular del certificado tiene que estar autorizado por la empresa para operar con folios (CAF) en el SII. No hace falta que administre usuarios. Además, caf_v1_listar y caf_v1_estado_folios consultan la opción de anulación masiva del SII: una empresa que no está habilitada ahí recibe CONTRIBUYENTE_SIN_PERMISO, y eso lo tiene que resolver la empresa con el SII.
  • Las tres hablan con el SII en serie y pueden tardar decenas de segundos. Configure un timeout de cliente de al menos 70 segundos. Pasados 60 segundos, la capa de entrada de la API responde 504 con una página HTML, sin código: está en Tiempos de respuesta y 504.

Paso 1: listar los CAF

caf_v1_listar es POST /v1/caf/{rut}/listar/{tipoDocumento}:

curl -u '<usuario>:<apikey>' -X POST \
  -H 'Accept: application/json' -H 'Content-Type: application/json' \
  -d '{"Data": "<pfx en base64>", "Contrasenna": "********"}' \
  'https://api.enrolamiento.cl/v1/caf/11111111-1/listar/33?ambiente=0'

La respuesta trae Cafs, un elemento por CAF, ordenados por FolioInicial de mayor a menor:

{
  "Cafs": [
    { "FolioInicial": 1101, "FolioFinal": 1200, "Cantidad": 100, "Fecha": "12-03-2026", "Dueno": "Usuario Ejemplo", "RUTDueno": "12345678-5" },
    { "FolioInicial": 1001, "FolioFinal": 1100, "Cantidad": 100, "Fecha": "05-01-2026", "Dueno": "Usuario Ejemplo", "RUTDueno": "12345678-5" }
  ]
}
  • Vienen todos los CAF que el SII lista, también los ya usados o anulados enteros. Que un CAF esté en la lista no dice que le queden folios: para eso está el paso 2.
  • Cafs vacía quiere decir que el SII no lista CAF de ese tipo para la empresa. Nunca es nula.
  • Es una lectura: no timbra ni anula nada, y repetirla no cambia nada en el SII.
  • Reemplaza a caf_v1_anulacion_masiva_listar para listar CAF: el mismo modelo de respuesta, pero en el ambiente pedido y verificando el permiso del certificado.

Errores de este paso. Los del certificado (CERT_REQUERIDO, CERT_EXPIRADO, CERT_NO_VALIDO y los demás de la tabla de la operación), CERT_SIN_PERMISO si el titular no está autorizado por la empresa, SEC_EMP_NOT_AUTHORIZED si la empresa opera en la modalidad MiPyme, CONTRIBUYENTE_SIN_PERMISO, SII_ERROR_CXN (reintentable; desde el despliegue de la versión 1.5.3, también cuando el SII pide volver a iniciar sesión) y SII_RESPUESTA_INESPERADA (no reintentable). Esta operación nunca responde 429.

Paso 2: contar los folios de un CAF

caf_v1_estado_folios es POST /v1/caf/{rut}/estado-folios/{tipoDocumento}/{folioInicial}/{folioFinal}. Tome FolioInicial y FolioFinal de un CAF del paso 1, o un subrango: el rango tiene que caber entero en un solo CAF.

curl -u '<usuario>:<apikey>' -X POST \
  -H 'Accept: application/json' -H 'Content-Type: application/json' \
  -d '{"Data": "<pfx en base64>", "Contrasenna": "********"}' \
  'https://api.enrolamiento.cl/v1/caf/11111111-1/estado-folios/33/1001/1100?ambiente=0'
{ "Rut": "11111111-1", "TipoDocumento": 33, "FolioInicial": 1001, "FolioFinal": 1100,
  "Cantidad": 100, "Disponibles": 60, "Utilizados": 38, "Anulados": 2 }

Qué dice cada número:

CampoQué es
CantidadLos folios del rango: FolioFinal - FolioInicial + 1. Siempre es Disponibles + Utilizados + Anulados.
DisponiblesLos que el SII todavía no recibió ni anuló. Lo informa el SII.
UtilizadosLos que el SII ya no permite anular: en la práctica, los de documentos que el SII recibió. No lo informa el SII: se calcula como Cantidad - Disponibles - Anulados.
AnuladosLos anulados en el SII. Lo informa el SII.

Disponibles no es la cantidad de folios libres para emitir. Puede incluir folios que usted ya usó en documentos que aún no envió al SII. Para decidir qué folio emitir, use su propio foliado. Para saber el último folio emitido, use caf_v1_consulta: esta operación cuenta un rango.

Consulte bajo demanda, un CAF a la vez. Cada llamada es una consulta completa al SII, y no hay una consulta de varios CAF juntos. Recorrer todos los CAF del paso 1 cuesta una llamada por CAF, y cada una cuenta para el límite de requests. Si necesita varios CAF, haga una llamada por CAF y en secuencia. La suma de los subrangos de un CAF no tiene por qué coincidir con una sola consulta del CAF entero si entre una y otra se emitieron o anularon folios.

Errores de este paso. Antes de validar el certificado o consultar al SII, también con el RUT de prueba: PARAMETRO_FUERA_DE_RANGO si un folio es menor que 1 o folioInicial es mayor que folioFinal, y NO_SOPORTADO_BOLETAS si pide boletas (39 o 41) en producción; las boletas solo se consultan con ambiente=0. Después, los mismos del paso 1, más CAF_NO_ENCONTRADO si el rango no cabe entero en un solo CAF del listado del SII, y SII_RESPUESTA_INESPERADA si los conteos del SII no cuadran con el rango: nunca un 200 con ceros. Esta operación nunca responde 429.

Paso 3: volver a bajar un CAF con folioInicial

caf_v1_reobtener es POST /v1/caf/{rut}/reobtener/{tipoDocumento}. Sin folioInicial devuelve el último CAF, como siempre. Con folioInicial, el FolioInicial de un CAF del paso 1, devuelve el CAF que empieza en ese folio:

curl -u '<usuario>:<apikey>' -X POST \
  -H 'Accept: application/json' -H 'Content-Type: application/json' \
  -d '{"Data": "<pfx en base64>", "Contrasenna": "********"}' \
  'https://api.enrolamiento.cl/v1/caf/11111111-1/reobtener/33?folioInicial=1101&ambiente=0'
  • No pide folios nuevos. El CAF ya está timbrado: repetir la llamada vuelve a bajar el mismo CAF. No se aplica el filtro de 3 meses de descargarCafAntiguos, que con folioInicial no se usa.
  • El certificado se valida en producción, aunque pida ambiente=0. Vea Antes de empezar.
  • El CAF se busca solo en la primera página del listado de reobtención del SII, que no es la fuente de caf_v1_listar. Un CAF que el paso 1 muestra, de los más antiguos, puede no estar en esa primera página: la respuesta es CAF_NO_ENCONTRADO aunque el CAF exista. Hoy la API no tiene cómo reobtener ese CAF, y caf_v1_descargar con ultimoFolio tampoco: mira la misma primera página y, si no encuentra el CAF, pide folios nuevos. En ese caso, contacte a soporte con el RUT, el tipo de documento y el folio inicial.
  • Pídalos en secuencia. Si su cuenta tiene el control de solicitudes concurrentes de CAF, las solicitudes del mismo RUT, tipo de documento y ambiente se atienden de a una, entre caf_v1_descargar, caf_v1_reobtener y caf_v1_anular. Si va a bajar varios CAF del mismo RUT y tipo, no los pida en paralelo. El detalle está en 409 y 429.

Verifique el CAF que recibe

La respuesta es un string JSON con el XML del CAF en base64 (ver Formatos). Antes de usarlo, verifique que el CAF empiece en el folio que pidió: el <D> de <RNG> del XML tiene que ser folioInicial. Una API sin la versión 1.5.0 ignora el parámetro en silencio y devuelve el último CAF con un 200. Si no empieza ahí, no use ese CAF: vuelva a pedirlo o contacte a soporte.

// Node.js: decodifica la respuesta de caf_v1_reobtener y verifica que el CAF empiece en folioInicial.
async function cafQueEmpiezaEn(respuesta, folioInicial) {
  const base64 = await respuesta.json(); // un string JSON
  const xml = Buffer.from(base64, 'base64').toString('latin1');
  const desde = /<RNG>\s*<D>\s*(\d+)\s*<\/D>/.exec(xml)?.[1];
  if (Number(desde) !== Number(folioInicial)) {
    throw new Error(`El CAF devuelto empieza en ${desde ?? '(sin RNG)'}, no en ${folioInicial}: no lo use.`);
  }
  return xml;
}

Errores de este paso. PARAMETRO_FUERA_DE_RANGO antes que todo, también con el RUT de prueba, si folioInicial no es un entero mayor o igual a 1 o viene repetido. Después, CERT_REQUERIDO si falta el cuerpo o le falta Data o Contrasenna (desde el despliegue de la versión 1.5.3, antes de esperar por otra solicitud en curso), los del certificado validado en producción; CAF_NO_ENCONTRADO si ningún CAF de la primera página empieza en folioInicial; y, si el listado o la descarga trajo una página del SII, NO_CAF, CERT_SIN_PERMISO, SEC_EMP_NOT_AUTHORIZED o SII_ERROR_CXN según la página, o UNKNOWN_ERROR_CAF con el motivo en el mensaje. Con folioInicial, UNKNOWN_ERROR_CAF no pide folios nuevos: el CAF ya está timbrado; lea el mensaje y reintente más tarde. Con el control de solicitudes concurrentes, también el 429 de CAF_REQUEST_IN_PROGRESS.

Qué hacer con cada código

CódigoPasoQué hacer
SII_ERROR_CXN1, 2 y 3Reintente respetando Retry-After (30 segundos), con espera exponencial (30, 60 y 120 segundos) y un tope de 3 intentos. En el SII de producción es frecuente e intermitente. Desde el despliegue de la versión 1.5.3, en los pasos 1 y 2 también llega cuando el SII pide volver a iniciar sesión: si persiste, espere 15 minutos y repita (ver Ambientes).
504 con una página HTML1, 2 y 3Es la capa de entrada de la API, que cortó a los 60 segundos. En los pasos 1 y 2, repita: son lecturas. En el paso 3, repita pasados 30 segundos: el pedido puede seguir en curso.
CAF_REQUEST_IN_PROGRESS3Espere los segundos de Retry-After y repita el mismo request.
CAF_NO_ENCONTRADO2Pida un rango que quepa entero en un CAF del paso 1.
CAF_NO_ENCONTRADO3Revise que folioInicial sea el FolioInicial de un CAF del paso 1. Si lo es, el CAF no está en la primera página: contacte a soporte. No lo reintente.
UNKNOWN_ERROR_CAF3Lea el mensaje y reintente más tarde. No pida folios nuevos por esto.
NO_CAF3El SII no registra CAF de ese tipo para la empresa: no hay nada que reobtener.
PARAMETRO_FUERA_DE_RANGO2 y 3Corrija el folio. Repetir da el mismo error.
NO_SOPORTADO_BOLETAS2Las boletas (39 y 41) solo se consultan con ambiente=0.
CERT_SIN_PERMISO1, 2 y 3Use el certificado de un usuario autorizado por la empresa para operar con folios.
CONTRIBUYENTE_SIN_PERMISO1 y 2La empresa tiene que habilitarse en la anulación masiva del SII.
SII_RESPUESTA_INESPERADA1 y 2No reintente; contacte a soporte con el RUT. Hasta el despliegue de la versión 1.5.3 también llega si el SII rechazó la sesión, por ejemplo al alternar de ambiente con el mismo certificado: vea Ambientes.

Un código que no está en esta tabla se resuelve con la tabla «Reintentos e idempotencia» de la operación y, si tampoco está ahí, con la regla de respaldo.

Probar sin el SII

Con el RUT 1-9 o un RUT de prueba de su perfil de cliente, las tres responden sin consultar al SII ni validar el certificado:

  • caf_v1_listar devuelve siempre un único CAF de ejemplo, del folio 1 al 10.
  • caf_v1_estado_folios responde cualquier rango válido con todos sus folios disponibles, sin contrastarlo con ese CAF de ejemplo.
  • caf_v1_reobtener responde una cadena vacía ("" en JSON), con o sin folioInicial. La verificación del <D> de <RNG> no aplica a esa respuesta.

PARAMETRO_FUERA_DE_RANGO y NO_SOPORTADO_BOLETAS sí llegan con el RUT de prueba, porque se revisan antes. Los errores del SII no se simulan: CAF_NO_ENCONTRADO, SII_ERROR_CXN y los rechazos solo se ven contra el SII, en certificación con una empresa real.

En esta página