Reglas transversales de la API
Estas reglas aplican a más de un módulo. Si ya leíste una guía de dominio, acá está lo que esa guía da por sabido.
Paginación
Sección titulada «Paginación»Los listados usan limit y offset. No hay número de página.
| Parámetro | Tipo | Valor |
|---|---|---|
limit | number | Registros por página. Default 20, máximo 300 |
offset | number | Registros a saltar. Default 0 |
El máximo de 300 es transversal: sale de una constante compartida entre backend y frontend
(PAGINATION_MAX_LIMIT), así que es el mismo tope en todos los listados. Si viste otro número en
alguna guía, este es el que vale.
Un limit por encima del máximo responde 400, no lo recorta en silencio.
La respuesta trae los totales al nivel raíz, no dentro de data:
{ "success": true, "data": [ /* ... */ ], "total": 1247, "limit": 20, "offset": 0}Para recorrer todo: incrementa offset de a limit hasta que offset + data.length >= total.
Cuando cambies un filtro, vuelve offset a 0 — si no, la primera página del nuevo filtro te
sale vacía.
Idempotencia
Sección titulada «Idempotencia»Si tu sistema puede reintentar una operación —por timeout, error de red o doble click— usa
idempotencyKey para que el reintento no genere un segundo documento.
{ "idempotencyKey": "orden-compra-4471", "...": "resto del payload"}| Tipo | string, máximo 128 caracteres |
| Vigencia | Permanente. No expira |
| Comportamiento | Si ya existe un documento emitido con esa combinación, se devuelve el original: no se crea uno nuevo ni se consume folio |
Aplica a la emisión de documentos tributarios (DTE), boletas de honorarios (BHE) y boletas de terceros (BHET). El alcance no es el mismo en los tres:
| Documento | Alcance de la clave |
|---|---|
| DTE | (emisor, ambiente, tipo de documento, idempotencyKey) |
| BHE | (emisor, idempotencyKey) |
| BHET | (emisor, idempotencyKey) |
En DTE el ambiente (certificación o producción) forma parte del alcance: la misma clave puede usarse una vez en cada ambiente. Es lo que hace que, cuando pases tu emisor de certificación a producción, las claves que gastaste probando no te devuelvan documentos de prueba en lugar de emitir los reales. Las boletas de honorarios no llevan ambiente porque el SII no ofrece certificación para ellas.
Forma de los errores
Sección titulada «Forma de los errores»La API no envuelve los errores en el sobre success/data. El formato es el nativo de NestJS:
{ "statusCode": 400, "message": "El precio unitario debe ser al menos 1 en cada línea. 2 línea(s) tienen precio inválido.", "error": "Bad Request"}Cuando falla la validación del payload, message puede ser un array de strings, uno por campo:
{ "statusCode": 400, "message": ["El nombre del item es obligatorio", "La cantidad debe ser mayor a 0"], "error": "Bad Request"}Trata message como string | string[]. Es la causa más común de que un manejador de errores
rompa en el primer 400 de validación.
El campo reportar, sólo en errores del servidor
Sección titulada «El campo reportar, sólo en errores del servidor»Las respuestas con statusCode >= 500 llevan un campo extra con el enlace a la guía del canal de
reporte:
{ "statusCode": 500, "message": "Internal server error", "reportar": "https://docs.redcumbre.cl/guias/reportar-issue/"}Es aditivo: el resto del cuerpo no cambia, y un cliente que ignora el campo no se entera.
Los rechazos de cliente (4xx) NO lo llevan, a propósito. Un 400 es casi siempre un problema
de la petición —un campo obligatorio que falta, un valor fuera del enum—, y ofrecer reportarlo
produciría reportes de defectos que no existen. El campo aparece justo donde el error sí es
nuestro.
Ver Reportar un problema.
Reintentar o no
Sección titulada «Reintentar o no»| Código | Qué pasó | ¿Reintentar? |
|---|---|---|
400 | El payload no pasó validación, o una regla de negocio lo rechazó | No. Reintentar igual da lo mismo. Corregí el payload |
401 | Falta la credencial, o no es válida | No. Revisa el header Authorization |
403 | La credencial es válida pero no alcanza ese endpoint, o el tenantSlug no le corresponde | No. Es un problema de roles o de servicio no habilitado |
404 | El recurso por ID no existe | No |
409 | Conflicto de estado: el documento ya fue emitido o anulado | No. Consulta el estado actual antes de decidir |
429 | Límite de tasa | Sí, respetando la ventana del límite |
5xx | Error del lado de Redcumbre o de un servicio externo | Sí, con backoff exponencial |
Límites de tasa
Sección titulada «Límites de tasa»No hay un límite de tasa global en la API. Los límites son por caso de uso, donde el abuso tiene un costo concreto:
| Dónde | Límite |
|---|---|
SMS con routeType: "otp" | 1 mensaje por número cada 5 minutos. Ver Envío de SMS |
| Verificación PIN-RUT | Límite de intentos fallidos. Ver PIN-RUT |
Que hoy no exista un límite global no es una invitación a paralelizar sin control: las emisiones tributarias dependen del SII, que sí tiene sus propios tiempos. Para volumen alto, la vía es Procesos Batch, no N llamadas concurrentes.
Modo asíncrono
Sección titulada «Modo asíncrono»Varios endpoints de emisión aceptan un modo asíncrono: en vez del documento, devuelven un identificador de intento para consultar el estado después. Es lo que conviene cuando estás emitiendo desde una petición web y no quieres que el usuario espere al SII.
El detalle de los modos está en la guía de cada dominio.
Siguiente paso
Sección titulada «Siguiente paso»- Entornos y sandbox — una sola URL base, y el sandbox como propiedad de la key
- Webhooks — recibir eventos en vez de consultar por polling
- Documentos Tributarios Electrónicos — el dominio principal