Errores y reintentos
Cómo leer un error de la API y cuándo es seguro reintentar.
Esta guía cubre las familias de errores de la API y cómo interpretar cada una, el catálogo de códigos y qué hacer con cada uno, y cuándo una operación se puede reintentar sin riesgo.
Las cuatro familias
Un error de la API pertenece a una de cuatro familias. Cada una tiene su forma de cuerpo, y no todas se reconocen por el status.
| Familia | Status | Cuerpo |
|---|---|---|
| Negocio | Casi siempre 500; también 403, 404 y 429 | Texto plano: CODIGO:mensaje |
| Framework | 400, 404, 405 o 500 | JSON con Message |
| Autenticación | 401 | JSON con Message, o vacío |
| Rate limit | 409 | Texto plano, sin código |
Negocio
Son los errores que produce la propia API: un dato que falta, un rechazo del SII, una falla de comunicación con el SII. El cuerpo es texto plano con una de estas formas:
CODIGO:mensajeCODIGO:SUBCODIGO:mensaje -- excepción- el mensaje solo, sin código. Así llegan el 403 y el 404 de negocio, por ejemplo «No existe una certificación…».
Los rechazos de negocio llegan como HTTP 500, aunque no sean fallas. Un cliente sin saldo prepago que llama a certificaciones_v1_crear recibe un 500 con este cuerpo:
INSUFICIENTE_SALDO:No es posible crear la certificación en estos momentos, por favor verifique su saldo e intente nuevamente.Por eso el status no sirve para decidir qué hacer; el código sí. INSUFICIENTE_SALDO y CERT_REQUERIDO vuelven con el mismo 500 que una falla de comunicación con el SII (SII_ERROR_CXN), y piden cosas opuestas: los dos primeros no se arreglan reintentando, el tercero sí.
Decida por el código, nunca por el texto del mensaje. El mismo código puede llegar con más de un mensaje, y códigos distintos pueden traer el mismo mensaje. En caf_v1_descargar, por ejemplo, AUT_DOCTYPE_NOT_AUTHORIZED y UKN pueden traer exactamente el mismo texto («EL SII no autoriza timbraje…»): el primero no se reintenta nunca y el segundo se reintenta con cuidado. El mensaje sirve para mostrárselo a una persona o para guardarlo en su registro, no para que su sistema decida.
Un caso aparte es CAF_REQUEST_IN_PROGRESS: también es de negocio y trae el código, pero llega con status 429 y la cabecera Retry-After. Está más abajo, en 409 y 429.
Las cabeceras de un error con código
Desde la versión 1.1 del contrato, cada error de negocio con código trae además tres cabeceras:
| Cabecera | Qué dice |
|---|---|
X-Codigo-Error | El código del error, el mismo que abre el cuerpo (CODIGO:…). Viene esté o no el código en el catálogo. |
X-Reintentable | si, no o desconocido: la clasificación del código en el catálogo, y desconocido para un código que no figura ahí. no quiere decir no reintentar, cualquiera sea el status. |
Retry-After | Segundos a esperar antes de reintentar. Viene solo cuando X-Reintentable es si (hoy, 30). |
Solo las traen los errores con código, que llegan con status 500. El 403 y el 404 de negocio, que llegan sin código, no las traen; tampoco los errores del framework, el 401 ni el 409. El 429 de CAF_REQUEST_IN_PROGRESS trae Retry-After, pero todavía no X-Codigo-Error: lea el código del cuerpo.
X-Reintentable es la clasificación del catálogo, no la decisión de la operación. No sabe si la operación se puede repetir sin efectos duplicados. En caf_v1_descargar, por ejemplo, CNX_HTTP_ERROR_500 llega con X-Reintentable: si y Retry-After: 30, pero la operación no es idempotente y lo tiene en manual: un reintento a ciegas podría timbrar folios dos veces. Decida siempre con x-reintentable de la operación, como se explica en Cuándo reintentar, y use la cabecera para lo que la operación no lista.
Framework
Los responde la plataforma web antes de la operación o en su lugar: una ruta que no existe (404), un verbo incorrecto (405), un parámetro de query obligatorio que falta (404), un parámetro numérico de la ruta que no convierte (400) o una excepción no controlada (500). Desde la versión 1.1, una excepción de un tipo que la API reconoce, como las de negocio y las del certificado, ya no llega como error del framework: llega como error de negocio, en texto plano y con su código. El cuerpo de un error del framework es JSON:
{ "Message": "The request is invalid." }Message siempre viene. Según la configuración del servidor pueden venir además MessageDetail y, en un 500, ExceptionMessage, ExceptionType y StackTrace. No dependa de esos campos: pueden no estar.
El 404 por un parámetro de query ausente sale antes de validar la credencial, así que llega aunque el request no traiga credenciales o traiga unas inválidas. El 400 por un parámetro que no convierte, en cambio, sale después de autenticar.
Autenticación
Es el 401. Si el request no trae el header Authorization, el cuerpo es JSON: {"Message": "Authorization has been denied for this request."}. Si lo trae con otro esquema que no sea Basic, o con credenciales inválidas, el 401 llega sin cuerpo. En los dos casos viene la cabecera WWW-Authenticate: Basic. Más detalle en Autenticación.
Rate limit
Es el 409, con el cuerpo de texto The allowed number of requests has been exceeded.. No es JSON ni trae código. Se explica completo en Rate limits.
Cómo leer un error
Lea siempre el cuerpo como texto, sin depender del Content-Type: en el 409, que ninguna capa intermedia cambie ese header no está verificado. Después decida por el status y por la forma del cuerpo, en este orden:
- 409: rate limit.
- 401: autenticación. El cuerpo puede estar vacío.
- El cuerpo es un objeto JSON con
Message: framework. - El cuerpo empieza con un código seguido de dos puntos: negocio. El código es lo que va antes del primer
:. - Cualquier otro texto: negocio sin código, como el 403 o el 404 de negocio.
Un ejemplo en JavaScript:
// Clasifica la respuesta de error de la API en su familia y, si lo hay, extrae el código.
async function leerError(respuesta) {
const texto = await respuesta.text();
if (respuesta.status === 409) return { familia: 'rate-limit', texto };
if (respuesta.status === 401) return { familia: 'autenticacion', texto };
// Desde la 1.1, un error de negocio con código lo trae también en la cabecera.
const codigoEnCabecera = respuesta.headers.get('X-Codigo-Error');
if (codigoEnCabecera) {
const mensaje = texto.startsWith(codigoEnCabecera + ':') ? texto.slice(codigoEnCabecera.length + 1) : texto;
return { familia: 'negocio', codigo: codigoEnCabecera, mensaje, reintentable: respuesta.headers.get('X-Reintentable') };
}
if (texto.trimStart().startsWith('{')) {
try {
const json = JSON.parse(texto);
if (typeof json.Message === 'string') {
return { familia: 'framework', mensaje: json.Message };
}
} catch {
// No era JSON: se sigue como texto plano.
}
}
// CODIGO:mensaje o CODIGO:SUBCODIGO:mensaje -- excepción
const conCodigo = /^([A-Z][A-Z0-9_]*):(.*)$/s.exec(texto);
if (conCodigo) {
return { familia: 'negocio', codigo: conCodigo[1], mensaje: conCodigo[2] };
}
return { familia: 'negocio', codigo: null, mensaje: texto };
}Guarde siempre el texto completo junto con la operación, el RUT y la hora: si tiene que contactar a soporte, es lo que se le va a pedir.
Un 200 no siempre es éxito
Algunas consultas responden 200 aunque el resultado sea un error. En caf_v1_anulados y caf_v1_consulta, el resultado viaja en campos de estado de la respuesta (Estado, UltimoEnviadoEstado, UltimoAnuladoEstado). Revise esos campos antes de dar el resultado por bueno: la referencia de cada operación lista sus valores posibles.
Catálogo de códigos
Cada código de negocio está clasificado con uno de tres valores:
- Sí: reintentable. Es una falla pasajera.
- No: reintentar no cambia el resultado. Hay que corregir algo antes: un dato, el certificado, el saldo, una situación de la empresa en el SII.
- Desconocido: puede ser pasajero o no. Antes de repetir, consulte el estado de la operación.
Cada fila tiene un ancla propia: para enlazar un código, use #error- seguido del código, por ejemplo CAF_REQUEST_IN_PROGRESS.
| Código | ¿Reintentable? | Qué hacer |
|---|---|---|
AUTH_ERROR | Sí | No se obtuvo la sesión del SII con el certificado. El propio mensaje pide intentar nuevamente: reintentar con espera y un tope de 3 intentos. |
AUT_COMP_ACTIVITIES_VERIFICATION | No | El SII no verifica actividades económicas positivas para la empresa. Resolverlo en el SII antes de volver a pedir folios. |
AUT_COMP_OR_REP_SITUATION | No | El SII no autoriza el timbraje por una situación de la empresa o de su representante legal. Resolverla en el SII antes de volver a pedir folios. |
AUT_DOCTYPE_NOT_AUTHORIZED | No | El SII no autoriza timbrar este tipo de documento; lo más común es que la empresa ya tenga folios suficientes. Usar los vigentes o anular los sobrantes y volver a pedir. |
CAF_DENIED_SII_EXCEED | No | El SII no autoriza timbrar más folios de este tipo, ni siquiera uno: la API ya bajó la cantidad sola. Pedir menos no cambia la respuesta; usar los folios vigentes o anular los sobrantes. |
CAF_DENIED_SII_NOTENOUGH | No | El SII no autoriza los folios pedidos para este tipo de documento. Usar los vigentes, anular los sobrantes o gestionar con el SII una autorización mayor. |
CAF_REQUEST_IN_PROGRESS | Sí | Otra solicitud de folios para el mismo RUT y tipo de documento sigue en curso; este request no se ejecutó. Esperar los segundos del header Retry-After (hoy 30) y repetir el mismo request. Si el 429 llega al reintentar un caf_v1_descargar propio cuya respuesta no se recibió, la solicitud en curso puede ser esa: antes de repetir, consultar con caf_v1_consulta o recuperar con caf_v1_reobtener si el CAF quedó timbrado. |
CAF_UNKNOWN | Desconocido | El SII no entregó el CAF por un motivo que no se pudo identificar. Antes de pedir folios de nuevo, consultar con caf_v1_consulta o caf_v1_reobtener si el CAF quedó timbrado. |
CERTIFICACION_EXISTE_EN_OTRO_CLIENTE | No | Otro cliente está certificando ese RUT. Contactar a soporte; reintentar no lo cambia. |
CERTIFICADO_DIGITAL_REQUERIDO | No | Cargar el certificado digital con actualizar (campo Certificado) antes de iniciar. |
CERT_AUTH_NOT_CONFIGURED | No | El titular tiene que habilitar el certificado para autenticarse en el sitio del SII. |
CERT_ERROR | Desconocido | No se pudo cargar o validar el certificado. Casi siempre son los datos o la contraseña del PFX: revisarlos antes de repetir. Si el certificado está bien, reintentar una vez. |
CERT_EXPIRADO | No | El certificado está vencido. Renovarlo y volver a mandarlo. |
CERT_NO_CONFIGURADO_AUTH | No | El titular tiene que habilitar el certificado para autenticarse en el sitio del SII. |
CERT_NO_VALIDO | No | El RUT del certificado termina en «k» minúscula y no se puede usar. Revocarlo y generarlo de nuevo, o usar otro certificado. |
CERT_REQUERIDO | No | Mandar el cuerpo con Data (PFX en base64) y Contrasenna. |
CERT_REQUIRED | No | Mandar el cuerpo con Data (PFX en base64) y Contrasenna. |
CERT_REVOCADO | No | El certificado fue revocado por su titular o por la entidad emisora. Emitir uno nuevo y volver a mandarlo. |
CERT_SIN_PERMISO | No | El certificado no tiene permisos en el SII para esa empresa. Usar el certificado de un usuario habilitado, o darle permisos (empresas_v1_permisos con un certificado administrador). |
CNX_HTTP_ERROR_500 | Sí | El SII respondió 500 al pedir el CAF. Reintentar con espera exponencial y un tope de 3 intentos; antes de pedir folios de nuevo, consultar con caf_v1_consulta si el CAF salió igual. |
CNX_HTTP_ERROR_CLOSED | Sí | El SII cerró la conexión. Reintentar con espera exponencial y un tope de 3 intentos; antes de pedir folios de nuevo, consultar con caf_v1_consulta si el CAF salió igual. |
CNX_HTTP_ERROR_REMOTE | Sí | No se pudo conectar con el SII. Reintentar con espera exponencial y un tope de 3 intentos; si persiste, contactar a soporte. |
CNX_HTTP_ERROR_RETRY | Desconocido | El SII devolvió su página genérica «No ha sido posible completar su solicitud», que a veces es una falla pasajera y a veces envuelve un rechazo. Leer el mensaje; reintentar una sola vez y, si se repite, no insistir y contactar a soporte. |
CNX_HTTP_ERROR_SSLTLS | Sí | No se pudo abrir el canal TLS con el SII; suele ser intermitente. Reintentar con espera exponencial y un tope de 3 intentos; si persiste, contactar a soporte. |
CNX_HTTP_ERROR_TIMEOUT | Sí | Venció el tiempo de espera con el SII. Reintentar con espera exponencial y un tope de 3 intentos; antes de pedir folios de nuevo, consultar con caf_v1_consulta si el CAF salió igual. |
CONTRIBUYENTE_SIN_PERMISO | No | El SII no habilita a la empresa para la anulación masiva de folios; reintentar no lo cambia. |
DATOS_REQUERIDOS | No | Mandar el cuerpo de crear con los datos del certificado y los sets. |
EMPRESA_VERIFICACION_ACTIVIDADES_SII | No | El SII no verifica actividades económicas positivas para la empresa. Resolverlo en el SII y recién entonces volver a crear. |
ERROR_ACTUALIZANDO_CASILLAS | Desconocido | El SII rechazó o no completó la actualización de las casillas de intercambio; el detalle viaja en el mensaje. Leerlo antes de repetir. |
ERROR_DECLARANDO_CUMPLIMENTO | Desconocido | El SII rechazó o no completó la declaración de cumplimiento, y la certificación queda marcada con este error. Consultar la certificación y leer el mensaje antes de repetir. |
ERROR_DESCARGANDO_CERTIFICADO | Desconocido | Falló la descarga desde E-Cert. Si el mensaje habla del usuario o la contraseña, corregirlos; si no, reintentar una vez. |
ERROR_GENERAL | Desconocido | Código genérico. Si el mensaje dice que el RUT es nulo o no es válido, corregirlo; si no, leer el mensaje y consultar el estado de la certificación antes de repetir. |
ERROR_MODALIDAD_CLIENTE | No | El SII dice que el contribuyente no está autorizado para operar en esta modalidad (facturación MiPyme del SII). Lo tiene que resolver la empresa con el SII. |
ERROR_SOLICITANDO_CERTIFICADO | Desconocido | Falló la solicitud a E-Cert. Si el mensaje empieza con «Errores en lo datos», corregir los campos que nombra; si no, reintentar una vez. |
INSUFICIENTE_SALDO | No | El cliente no tiene saldo prepago. Cargar saldo en el portal y volver a crear. |
NOT_ENOUGH_FOLIO_FROM_SII | No | El SII no autoriza los folios pedidos para este tipo de documento. Usar los vigentes, anular los sobrantes o gestionar con el SII una autorización mayor. |
NO_CERTIFICATE | No | Mandar el certificado en el cuerpo: la plataforma no tiene uno guardado para usar. |
PRODUCTO_REQUERIDO | No | Cargar al menos un producto con nombre y precio (actualizar) antes de iniciar. |
RANGE_INVALID | No | Al menos un folio del rango ya fue recibido por el SII y no se puede anular. Anular un rango que no incluya folios usados. |
RESP_HTTP_ERROR | Desconocido | Error interno sin código reconocible. Desde la versión 1.1, un rechazo en la validación del certificado llega con su propio código (por ejemplo CERT_REQUERIDO o CERT_EXPIRADO), así que este código ya no corresponde a ese caso. Si aparece, reintentar una vez; si se repite, no insistir y contactar a soporte indicando la hora del request. |
RESP_INVALID | Desconocido | El SII respondió a la anulación algo que no se reconoce; el texto del SII viaja en el mensaje. Leerlo antes de repetir. |
SEC_CERT_NOT_AUTHORIZED | No | El SII rechaza a este certificado para descargar CAF. Usar un certificado con ese permiso: repetir con el mismo no cambia la respuesta. |
SEC_EMP_NOT_AUTHORIZED | No | La empresa no está autorizada para operar en esta modalidad (usa la facturación MiPyme del SII). Lo tiene que resolver la empresa con el SII. |
SEC_USER_BOLSII | No | El contribuyente usa el Sistema de Emisión de Boletas Electrónicas del SII. Lo tiene que resolver la empresa con el SII. |
SEC_USER_NOT_AUTHENTICATED | Desconocido | El certificado no quedó autenticado en el sitio del SII. Puede ser una sesión vencida que la llamada siguiente renueva: reintentar una vez y, si se repite, revisar que el certificado esté habilitado para autenticarse en el SII. |
SERVICIO_REQUERIDO | No | Cargar al menos un servicio con nombre y precio (actualizar) antes de iniciar. |
SET_AMBAS_BOLETAS_JUNTAS | No | Certificar boleta afecta (39) y boleta exenta (41) en certificaciones separadas. |
SET_BASICO_REQUERIDO_SII | No | Reenviar el pedido incluyendo el set básico (33). |
SET_CERTIFICADO | No | Quitar del pedido el set que el mensaje dice que ya está certificado. |
SET_DTE_BOLETA_JUNTOS | No | Certificar los sets de DTE y los de boletas en certificaciones separadas. |
SET_REQUERIDO | No | Indicar al menos un set a certificar en Sets. |
SII_CALL_ERROR | Desconocido | Falló una llamada de negocio al facade de anulación masiva del SII. Volver a listar los folios antes de repetir la anulación, para no actuar sobre un estado viejo. |
SII_ERROR_CXN | Sí | Falla de comunicación con el SII. Reintentar con espera exponencial y un tope de 3 intentos; si persiste, contactar a soporte con el RUT. |
SII_RESPUESTA_INESPERADA | No | El SII devolvió algo que no se pudo interpretar. No reintentar; contactar a soporte con el RUT. |
SITUACION_SII_EMPRESA_REP_LEGAL | No | La empresa o su representante legal tiene una situación pendiente en el SII. Resolverla allá y recién entonces volver a crear. |
SOLICITUD_FOLIOS_MAYOR_AUTORIZADOS_SII | No | El SII no autoriza la cantidad pedida, ni siquiera un folio. Usar los folios vigentes o anular los sobrantes antes de volver a pedir. |
UKN | Desconocido | Error no clasificado: puede ser pasajero (una falla TLS, por ejemplo) o no. Consultar el estado de la operación antes de repetirla y, si se repite, contactar a soporte con el RUT y la hora. |
UNKNOWN_ERROR_CAF | Desconocido | Error no clasificado al reobtener o descargar el CAF; el motivo viaja en el mensaje. Leerlo y, antes de pedir folios nuevos, consultar con caf_v1_consulta si el CAF quedó timbrado. |
UNK_ERROR | Desconocido | El SII no respondió a la anulación. Repetirla con el mismo rango es seguro: si ya estaba anulado, el SII lo acepta como hecho. |
VALOR_REQUERIDO | No | Mandar en el cuerpo al menos un campo a actualizar. |
Cuándo reintentar
Saber si un código es reintentable no alcanza: también importa si la operación se puede repetir sin efectos duplicados. El contrato OpenAPI declara las dos cosas en cada operación, con dos extensiones. Las dos se ven en el bloque «Reintentos e idempotencia» de cada página de la referencia, y el contrato completo se descarga en /openapi.json.
x-idempotente
Dice si repetir la operación con los mismos datos deja todo igual que una sola llamada:
true: repetirla no duplica nada. Las consultas, por ejemplo.false: cada llamada tiene efecto propio.caf_v1_descargartimbra folios nuevos en cada llamada;certificaciones_v1_crearcrea una certificación.desconocido: no está establecido. Trátela comofalse.
x-reintentable
Lista qué hacer con cada código del catálogo de esa operación, y con algunos status:
automatico: su sistema puede reintentar solo, con espera.manual: antes de repetir hay que consultar el estado, o que decida una persona.nunca: no se repite; hay que corregir la causa.
Por ejemplo, en caf_v1_descargar la lista automatico tiene 409 y 429, y CNX_HTTP_ERROR_500 está en manual. En el catálogo, CNX_HTTP_ERROR_500 es reintentable, pero caf_v1_descargar no es idempotente: un reintento a ciegas podría timbrar folios dos veces. Por eso la operación lo baja a manual. Antes de volver a pedir, consulte con caf_v1_consulta, o recupere con caf_v1_reobtener, si el CAF quedó timbrado.
La regla de respaldo
x-reintentable no es completa: los códigos que la API arma en el momento no figuran en ninguna operación. Si recibe un código que no está en x-reintentable de la operación, búsquelo en el catálogo y combine su clasificación con x-idempotente:
| Catálogo | x-idempotente | Qué hacer |
|---|---|---|
| Sí | true | Automático |
| Sí | false o desconocido | Manual |
| Desconocido | cualquiera | Manual |
| No | cualquiera | Nunca |
Hay dos casos que el contrato no clasifica, y que conviene tratar como manuales: un código que no está en el catálogo, y un 500 del framework, que no trae código.
Cómo reintentar
Para lo automático, espere entre intentos, con espera exponencial y un tope. Es lo que pide SII_ERROR_CXN, una falla de comunicación con el SII, en las operaciones que lo tienen en automatico, como caf_v1_consulta: espera exponencial y un tope de 3 intentos. Si sigue fallando, pase el caso a manual y contacte a soporte con el RUT y la hora. En otra operación, el mismo código puede estar en manual: siempre manda la lista de la operación.
409 y 429: el request no se ejecutó
Los dos status dicen que la API rechazó este request sin ejecutarlo, así que repetirlo no duplica nada por sí mismo. Por eso los dos aparecen en automatico. Con el 429 hay que mirar además qué otra solicitud está en curso: ver abajo.
-
409, rate limit. Se superó el límite de llamadas. No trae
Retry-After. Espere al menos 60 segundos antes de reintentar. El detalle está en Rate limits. -
429,
CAF_REQUEST_IN_PROGRESS. Ya hay otra solicitud de folios en curso para el mismo RUT y tipo de documento. Puede pasar encaf_v1_descargar,caf_v1_reobtenerycaf_v1_anular, y solo si su cuenta tiene habilitado el control de solicitudes concurrentes de CAF. La API espera hasta 60 segundos (por omisión) a que la otra solicitud termine; si no termina en ese plazo, responde 429. Este request no se ejecutó. El cuerpo es de negocio:CAF_REQUEST_IN_PROGRESS:Ya existe una solicitud de folios en curso para este RUT y tipo de documento. Reintente en 30 segundos.La cabecera
Retry-Afterdice cuántos segundos esperar (hoy, 30). Espere ese tiempo y repita el mismo request.Cuidado con
caf_v1_descargar. Si el 429 llega al reintentar una descarga propia cuya respuesta no recibió, la solicitud en curso puede ser esa misma: su intento original, que sigue timbrando. Repetir a ciegas puede terminar en folios timbrados dos veces. Antes de repetir, consulte concaf_v1_consultao recupere concaf_v1_reobtenersi el CAF quedó timbrado, igual que después de cualquier error dudoso (ver Qué no reintentar nunca).
// Cuántos segundos esperar antes de repetir un 409 o un 429.
function segundosDeEspera(respuesta) {
if (respuesta.status === 429) {
const pedido = Number(respuesta.headers.get('Retry-After'));
return Number.isFinite(pedido) && pedido > 0 ? pedido : 30;
}
if (respuesta.status === 409) return 60; // sin Retry-After: la ventana del rate limit es de 60 s
return null; // no es un rechazo sin ejecutar
}Qué no reintentar nunca
- Un código que la operación lista en
nunca, o que el catálogo marca con «No»: repetir da la misma respuesta. Corrija la causa que indica la columna «Qué hacer». - Un 401: las credenciales no van a cambiar solas. Revíselas antes de volver a llamar.
- Un 400 o un 404 del framework: el request está mal armado (una ruta, un verbo, un parámetro). Repetirlo igual da el mismo error.
- Una operación con
x-idempotenteenfalseodesconocido, después de un error dudoso o de una respuesta que no llegó: puede haberse ejecutado. Consulte el estado primero. Concaf_v1_descargar, eso escaf_v1_consultaocaf_v1_reobtenerantes de pedir folios otra vez.