Boletas de Honorarios Electrónicas (BHE)
Las Boletas de Honorarios Electrónicas son documentos tributarios que emiten las personas naturales por servicios profesionales prestados. Nuestra API permite emitir BHE con diferentes modos de emisión, gestionar PDFs y recibir notificaciones vía webhook.
Requisitos Previos
Sección titulada «Requisitos Previos»Antes de emitir una BHE necesitas:
- Un Emisor Tributario activo con clave tributaria delegada (no certificado digital)
- El
emisorTributarioIdde ese emisor — va en el cuerpo de toda emisión - Una API Key con uno de estos roles:
ADMIN,SUPER-ADMIN,SII-EMISOR-BHE, oFULL-API - Los datos del destinatario (o usar
sinDestinatario: truepara emitir sin destinatario)
Modos de Emisión
Sección titulada «Modos de Emisión»El sistema soporta 3 modos de emisión que permiten balancear entre respuesta inmediata y tolerancia a fallas del SII.
| Modo | Descripción | Respuesta | Recomendado |
|---|---|---|---|
SINC_COMPLETO | Todo síncrono: emitir + PDF interno + PDF SII | BHE completa con ambos PDFs | Cuando necesitas todo inmediato |
SINC_PARCIAL | Emitir + PDF interno síncronos, PDF SII en background | BHE con folio + PDF interno | Default recomendado |
ASINCRONO | Solo valida y encola. Todo en background | ID de intento para consulta | Alta tolerancia a fallas |
Flujo SINC_PARCIAL (Default)
Sección titulada «Flujo SINC_PARCIAL (Default)»Tu App Redcumbre SII │ │ │ │── POST /bhe ─────────────▶│ │ │ (modo: SINC_PARCIAL) │ │ │ │── Emitir BHE ─────────▶│ │ │◀── folioSii ──────────│ │ │ │ │ │── Genera PDF interno │ │ │ │ │◀── Response ──────────────│ │ │ (folioSii + pdfInternoUrl) │ │ (estadoPdfSii: PENDIENTE) │ │ │ │ │ [Background] │ │ │── Descarga PDF SII ───▶│ │ │◀── PDF ───────────────│ │ │ │ │◀── Webhook ───────────────│ │ │ (bhe.emision_terminada) │ │Ventajas:
- Respuesta rápida con folio y PDF personalizado
- PDF SII se descarga en background con reintentos automáticos (hasta 7 días)
- Si el SII tiene problemas, ya tienes el folio y un PDF válido
Flujo ASINCRONO
Sección titulada «Flujo ASINCRONO»Tu App Redcumbre SII │ │ │ │── POST /bhe ─────────────▶│ │ │ (modo: ASINCRONO) │ │ │ │── Valida datos │ │ │── Encola emisión │ │ │ │ │◀── Response ──────────────│ │ │ (intentoId, estado: PENDIENTE) │ │ │ │ │ [Background] │ │ │── Emitir BHE ─────────▶│ │ │◀── folioSii ──────────│ │ │── Genera PDF interno │ │ │ │ │◀── Webhook ───────────────│ │ │ (bhe.emitida) │ │Ventajas:
- Respuesta instantánea (solo valida y encola)
- Reintentos automáticos si el SII falla, durante 18–22,6 horas (10 intentos con espaciado creciente desde 5 min, máximo 6 h entre uno y otro). Ver la curva completa
- Ideal para procesos batch o cuando no necesitas el resultado inmediato
Consultar estado:
GET /{tenantSlug}/bhe/intento/{intentoId}Modos de Destinatario
Sección titulada «Modos de Destinatario»Cuando sinDestinatario=false, existen 4 formas mutuamente excluyentes de especificar el destinatario:
| Modo | Campo | Descripción | Cobra SII Lookup |
|---|---|---|---|
| 1 | destinatarioId | RUT de contribuyente guardado en sistema | No |
| 2 | destinatario | Datos completos on-the-fly | No |
| 3 | siiLookup | Objeto lookup SII ya obtenido | No |
| 4 | lookupRut | Solo RUT, sistema ejecuta lookup al SII | Sí |
Diagrama de Decisión
Sección titulada «Diagrama de Decisión»¿Tienes datos completos del destinatario?├── SÍ → ¿Están guardados en el sistema?│ ├── SÍ → Usar Modo 1 (destinatarioId)│ └── NO → Usar Modo 2 (destinatario)└── NO → ¿Ya hiciste lookup al SII previamente? ├── SÍ → Usar Modo 3 (siiLookup) └── NO → Usar Modo 4 (lookupRut) ⚠️ Cobra SII LookupModo 1: destinatarioId (Contribuyente Guardado)
Sección titulada «Modo 1: destinatarioId (Contribuyente Guardado)»El destinatario ya está guardado en el sistema (ContribuyenteMaestro).
{ "emisorTributarioId": "tu-emisor-tributario-id", "sinDestinatario": false, "destinatarioId": "12345678-9", "prestaciones": [ { "descripcion": "Servicio de consultoría", "valor": "150000" } ], "tipoRetencion": "RETRECEPTOR"}Modo 2: destinatario (Datos On-The-Fly)
Sección titulada «Modo 2: destinatario (Datos On-The-Fly)»Pasas todos los datos manualmente sin necesidad de lookup.
{ "emisorTributarioId": "tu-emisor-tributario-id", "sinDestinatario": false, "destinatario": { "rut": "12345678-9", "nombres": "EMPRESA CLIENTE SA", "direccion": "Av. Providencia 1234, Of. 501", "codigoRegion": "13", "codigoComuna": "13101", "email": "contacto@empresa.cl" }, "prestaciones": [ { "descripcion": "Servicio de consultoría", "valor": "150000" } ], "tipoRetencion": "RETRECEPTOR"}Campos del objeto destinatario:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
rut | string | Sí | RUT del destinatario (formato 12345678-9) |
nombres | string | Sí | Razón social o nombre completo |
direccion | string | Sí | Dirección completa |
codigoRegion | string | Sí | Código de región SII (ej: "13") |
codigoComuna | string | Sí | Código de comuna SII (ej: "13101") |
email | string | No | Email para envío de boleta |
Modo 3: siiLookup (Objeto Lookup Completo)
Sección titulada «Modo 3: siiLookup (Objeto Lookup Completo)»Ya tienes el resultado de un lookup previo al SII.
{ "emisorTributarioId": "tu-emisor-tributario-id", "sinDestinatario": false, "siiLookup": { "rut": "12345678-9", "razonSocial": "EMPRESA CLIENTE SA", "direcciones": [ { "direccion": "AV PROVIDENCIA 1234 OF 501", "codigoComuna": "13101", "comuna": "SANTIAGO" } ], "email": "contacto@empresa.cl" }, "prestaciones": [ { "descripcion": "Servicio de consultoría", "valor": "150000" } ], "tipoRetencion": "RETRECEPTOR"}Modo 4: lookupRut (Ejecutar Lookup)
Sección titulada «Modo 4: lookupRut (Ejecutar Lookup)»Solo pasas el RUT y el sistema ejecuta el lookup al SII.
{ "emisorTributarioId": "tu-emisor-tributario-id", "sinDestinatario": false, "lookupRut": "12345678-9", "prestaciones": [ { "descripcion": "Servicio de consultoría", "valor": "150000" } ], "tipoRetencion": "RETRECEPTOR"}Emitir Boleta
Sección titulada «Emitir Boleta»Request Completo
Sección titulada «Request Completo»POST /{tenantSlug}/bheContent-Type: application/jsonAuthorization: Bearer tu-api-key{ "emisorTributarioId": "tu-emisor-tributario-id", "sinDestinatario": false, "destinatario": { "rut": "12345678-9", "nombres": "EMPRESA CLIENTE SA", "direccion": "Av. Providencia 1234, Of. 501", "codigoRegion": "13", "codigoComuna": "13101", "email": "contacto@empresa.cl" }, "prestaciones": [ { "descripcion": "Servicio de consultoría en sistemas", "valor": "150000" }, { "descripcion": "Desarrollo de software", "valor": "75000" } ], "tipoRetencion": "RETRECEPTOR", "modo": "SINC_PARCIAL", "enviarBoletaPorEmail": true, "correlationId": "mi-referencia-123"}Campos del Request:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
emisorTributarioId | string | Sí | ID del emisor tributario |
sinDestinatario | boolean | Sí | true para emitir sin destinatario |
prestaciones | array | Sí | Lista de servicios (mín 1, máx 4) |
tipoRetencion | enum | Sí | RETRECEPTOR o RETCONTRIBUYENTE. Con sinDestinatario: true solo se acepta RETCONTRIBUYENTE (ver Tipos de Retención) |
validarCatalogo | boolean | No | Forzar validación contra catálogo de productos |
modo | enum | No | SINC_COMPLETO, SINC_PARCIAL (default), ASINCRONO |
enviarBoletaPorEmail | boolean | No | Enviar PDF al email del destinatario |
templateId | string | No | Template con que se representa el PDF interno de esta boleta. Si no lo envías, se usa el de tu empresa (ver Elegir el template del PDF interno) |
correlationId | string | No | ID de correlación para tracking. No es una clave: puedes repetirlo entre boletas distintas |
idempotencyKey | string | No | Clave de idempotencia, máx. 128 caracteres. Protege contra emisiones duplicadas por reintentos (ver Idempotencia) |
fechaEmision | string | No | Fecha de emisión personalizada (ver sección siguiente) |
Idempotencia
Sección titulada «Idempotencia»Si tu sistema puede reintentar una emisión —por timeout, error de red o doble click— usa idempotencyKey para que un reintento no genere una segunda boleta ante el SII.
{ "emisorTributarioId": "cm5abc123", "idempotencyKey": "orden-compra-4471", "prestaciones": [{ "descripcion": "Asesoría contable", "valor": "150000" }], "tipoRetencion": "RETRECEPTOR"}Cómo funciona:
- El alcance de la clave es por emisor tributario: dos emisores pueden usar el mismo valor sin colisionar.
- Si repites la clave y ya hay una boleta emitida con ella, se retorna esa misma boleta —mismo
id, mismofolioSii— sin volver a emitir ante el SII ni consumir un folio nuevo. - En ese caso se vuelve a disparar el webhook
bhe.emitida, porque si repetiste la clave lo más probable es que no hayas recibido la notificación anterior. - Si la emisión falló, la clave no queda reservada: puedes corregir el dato que el SII rechazó y reenviar con la misma clave.
- Si la boleta se anula, la clave se libera y puede volver a usarse.
- En modo
ASINCRONOla protección cubre también la emisión en vuelo: si reintentas mientras la primera todavía está en la cola o entre reintentos, recibes elintentoIdoriginal en vez de encolar una segunda. Con la ventana de reintentos de 18–22,6 h, esa protección puede estar activa durante horas — usaidempotencyKeysi tu sistema reintenta por su cuenta.
Fecha de Emisión Personalizada
Sección titulada «Fecha de Emisión Personalizada»Por defecto, las boletas se emiten con la fecha actual del servidor. Sin embargo, en casos excepcionales puedes especificar una fecha anterior usando el campo fechaEmision.
Formato
Sección titulada «Formato»El campo acepta formato ISO YYYY-MM-DD:
{ "emisorTributarioId": "tu-emisor-tributario-id", "sinDestinatario": false, "destinatarioId": "12345678-9", "prestaciones": [ { "descripcion": "Servicio de consultoría", "valor": "150000" } ], "tipoRetencion": "RETRECEPTOR", "fechaEmision": "2025-12-01"}Restricciones
Sección titulada «Restricciones»| Restricción | Descripción |
|---|---|
| No futuras | La fecha no puede ser posterior a hoy |
| Sin validación de plazos | No se valida contra plazos legales del SII |
| Fecha oficial | El SII registra esta fecha como fecha oficial del documento |
Comportamiento en PDFs
Sección titulada «Comportamiento en PDFs»| Campo en PDF | Valor |
|---|---|
| Fecha de Emisión | La fecha especificada (o fecha actual si no se especificó) |
| Fecha de Impresión | Siempre la fecha actual al generar/regenerar el PDF |
Esto permite identificar cuándo se prestó el servicio vs cuándo se generó el documento físico.
Campos de prestaciones[]:
Cada prestación puede especificarse de dos formas mutuamente excluyentes:
| Modo | Campos Permitidos | Campos Prohibidos |
|---|---|---|
| Item libre | descripcion, valor | productoId |
| Producto del catálogo | productoId, cantidad, descuentoPorcentaje | descripcion, valor, precioUnitario, unidadMedida, codigoSku |
Con productoId:
- Solo enviar:
productoId(requerido),cantidad(default: 1),descuentoPorcentaje(opcional, 0-100%) - El sistema calcula automáticamente: precio, descripción, unidad de medida, valor total
- Si envías campos prohibidos, recibirás error 400
Sin productoId (item libre):
- Enviar:
descripcion(requerido, máx 80 chars),valor(requerido, string numérico en CLP) - No hay validación de catálogo
Cuándo se permite precioUnitario con productos del catálogo:
| Condición del Producto | ¿Permite precioUnitario? |
|---|---|
esquemaPrecio: SIN_PRECIO | Sí (obligatorio) |
permisoEdicion: LIBRE | Sí |
permisoEdicion: DENTRO_RANGO_DESCUENTO | Sí (dentro del rango) |
permisoEdicion: NO_PERMITIDA | No |
Emisión con Productos del Catálogo
Sección titulada «Emisión con Productos del Catálogo»El sistema soporta dos modos de especificar prestaciones:
Modo 1: Items Libres (Sin Catálogo)
Sección titulada «Modo 1: Items Libres (Sin Catálogo)»Especifica descripcion y valor directamente. Ideal para servicios únicos o personalizados.
{ "prestaciones": [ { "descripcion": "Servicio de consultoría", "valor": "150000" } ]}Modo 2: Productos del Catálogo
Sección titulada «Modo 2: Productos del Catálogo»Usa productoId para referenciar un producto configurado en el catálogo. El sistema calcula precios, descuentos y cantidades automáticamente.
{ "prestaciones": [ { "productoId": "clxyz123abc", "cantidad": 3, "descuentoPorcentaje": 10 } ]}Validaciones del Catálogo
Sección titulada «Validaciones del Catálogo»Cuando usas productoId, el sistema valida automáticamente:
| Validación | Descripción |
|---|---|
| Existencia | El producto debe existir y pertenecer al tenant |
| Estado | El producto debe estar en estado ACTIVO |
| Tipo | El producto debe ser tipo SERVICIO (no PRODUCTO) |
| ILA | El producto NO debe tener impuesto adicional (ILA) |
| Visibilidad | El producto debe tener visibleEnBhe: true |
| Descuento | El descuentoPorcentaje no puede exceder el máximo configurado en el producto |
Response: Modo Síncrono (SINC_COMPLETO / SINC_PARCIAL)
Sección titulada «Response: Modo Síncrono (SINC_COMPLETO / SINC_PARCIAL)»{ "success": true, "data": { "modo": "SINC_PARCIAL", "descargas": { "pdfInterno": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123def456/descargar?tipo=interno", "pdfSii": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123def456/descargar?tipo=sii" }, "bhe": { "id": "cm5abc123def456", "folioSii": "12345678", "codigoBarras": "1234567800388FB4702C", "estado": "EMITIDA", "estadoPdfSii": "PENDIENTE", "modoEmision": "SINC_PARCIAL", "pdfInternoUrl": "https://app.redcumbre.cl/p/boleta/eyJhbGciOiJIUzI1NiJ9...", "montoBruto": 210000, "montoLiquido": 177975 }, "correlationId": "mi-referencia-123", "mensaje": "BHE emitida. PDF SII en proceso de descarga (se notificará via webhook)", "pdfInternoUrl": "https://app.redcumbre.cl/p/boleta/eyJhbGciOiJIUzI1NiJ9..." }}SINC_COMPLETO responde lo mismo, con cuatro diferencias: modo y bhe.modoEmision valen
SINC_COMPLETO; mensaje es "BHE emitida exitosamente" en vez del de más arriba; y si el
respaldo del SII alcanzó a descargarse dentro del request aparece data.pdfSiiUrl (también en
data.bhe.pdfSiiUrl) con bhe.estadoPdfSii: "DISPONIBLE". Si no alcanzó, queda en PENDIENTE y
se descarga en background, igual que en SINC_PARCIAL.
Response: Modo ASINCRONO
Sección titulada «Response: Modo ASINCRONO»{ "success": true, "data": { "modo": "ASINCRONO", "intentoId": "cm5xyz789abc123", "correlationId": "mi-referencia-123", "estado": "PENDIENTE", "mensaje": "Emisión encolada para procesamiento. Consulte el estado con GET /bhe/intento/{intentoId}" }}El bloque descargas no viene en esta respuesta: todavía no existe el id de la boleta, y las URLs se calculan a partir de él. Llega en GET /bhe/intento/{intentoId} una vez emitida, y en el webhook bhe.emitida.
Response: el SII rechaza la emisión
Sección titulada «Response: el SII rechaza la emisión»Cuando el SII no acepta la boleta, la BHE igual se persiste en estado ERROR con su motivo, para que quede consultable y auditable. Lo que cambia es cómo te lo comunicamos, y eso depende de quién llama:
| Quien emite | Qué recibe |
|---|---|
| La aplicación web de Redcumbre (sesión de usuario) | 201 con success: false — el formulario conserva lo escrito y muestra el motivo |
| Tu integración (API key) | Un status de error HTTP según la causa: 422, 502 o 503 |
Tu integración nunca recibe un 2xx por una boleta rechazada. No tienes que inspeccionar success para saber si se emitió: si la respuesta es 2xx, se emitió.
{ "statusCode": 422, "message": "El contribuyente no registra actividades de segunda categoría en el SII…", "error": "Unprocessable Entity", "errorCode": "SII_SIN_SEGUNDA_CATEGORIA", "boletaId": "cm5abc123def456"}| Campo | Para qué sirve |
|---|---|
errorCode | Lo único que conviene programar: es estable y clasifica la causa |
message | Texto legible, apto para mostrarle a tu usuario |
boletaId | El id de la fila que sí se persistió: GET /{tenantSlug}/bhe/{boletaId} responde 200 con la boleta en ERROR |
Qué hacer con cada status
Sección titulada «Qué hacer con cada status»| Status | Significa | Qué hacer |
|---|---|---|
422 | El SII entendió la solicitud y la rechazó por su contenido o por el estado del contribuyente | No reintentar sin corregir. Reintentar produce el mismo rechazo |
502 | El SII respondió algo que no se puede usar (error interno suyo, sesión caída, servicio degradado) | Reintentar con backoff exponencial |
503 | El emisor tiene demasiadas emisiones en curso ante el SII y hay que esperar turno | Reintentar después de los segundos que indica el header Retry-After |
500 | Un defecto nuestro. Dos formas, según el errorCode | Ver abajo. No es un problema de tu request |
El 500 tiene dos formas, y una de ellas no se reintenta
Sección titulada «El 500 tiene dos formas, y una de ellas no se reintenta»errorCode | Qué pasó | Qué hacer |
|---|---|---|
| (ausente) | La emisión falló con un motivo que la plataforma no tiene clasificado. La boleta quedó persistida en ERROR | Reportarlo con el boletaId |
BHE_EMITIDA_NO_PERSISTIDA | La boleta SÍ se emitió ante el SII y la plataforma no pudo guardarla. El cuerpo trae folioSii en vez de boletaId | No reintentar: emitirías una segunda boleta real. Reportar el folioSii a soporte |
Es el único caso en que un error no significa “no se emitió”.
Consultar Estado Asíncrono
Sección titulada «Consultar Estado Asíncrono»Para el modo ASINCRONO, consulta el estado del intento:
GET /{tenantSlug}/bhe/intento/{intentoId}Authorization: Bearer tu-api-keyResponse
Sección titulada «Response»{ "success": true, "data": { "id": "cm5xyz789abc123", "estado": "EMITIDA", "bhe": { "id": "cm5abc123xyz", "folioSii": "123456789", "codigoBarras": "ABC123...", "estado": "EMITIDA", "estadoPdfSii": "DISPONIBLE", "pdfInternoUrl": "https://...", "pdfSiiUrl": "https://...", "descargas": { "pdfInterno": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123xyz/descargar?tipo=interno", "pdfSii": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123xyz/descargar?tipo=sii" } }, "intentos": 1, "ultimoIntento": "2025-12-08T15:30:00Z", "correlationId": "mi-referencia-123", "createdAt": "2025-12-08T15:00:00Z", "updatedAt": "2025-12-08T15:30:00Z" }}Acá el intento va en data y la boleta en data.bhe, igual que en la emisión síncrona. Mientras
el intento no llegue a EMITIDA, data.bhe no viene.
Estados del intento:
| Estado | Descripción |
|---|---|
PENDIENTE | Registrado en cola, pendiente de procesamiento |
PROCESANDO | En proceso de emisión |
EMITIDA | Emitido exitosamente (tiene BHE asociada) |
REINTENTANDO | Un intento falló y el sistema va a volver a intentarlo. No es un desenlace: todavía hay algo que esperar |
FALLIDA | Falló definitivamente: se agotaron los 10 intentos (18–22,6 h) o el error del SII no se recupera reintentando |
Gestión de PDFs
Sección titulada «Gestión de PDFs»El sistema genera dos tipos de PDF:
| Tipo | Descripción | Disponibilidad |
|---|---|---|
| PDF Interno | Generado con template personalizado del tenant | Inmediato (modo síncrono) |
| PDF SII | Respaldo oficial descargado del SII | Depende de disponibilidad del SII |
Elegir el template del PDF interno
Sección titulada «Elegir el template del PDF interno»El PDF interno se representa con un template. Si no eliges ninguno, se usa el que tenga configurado tu empresa y, en su defecto, el estándar de la plataforma — que es lo que ocurre hoy si nunca tocaste esto.
Para elegirlo explícitamente, manda templateId en la emisión:
{ "emisorTributarioId": "cms6b8jtx0001sekpi26f8am7", "prestaciones": [{ "descripcion": "Servicio de consultoría", "valor": "150000" }], "templateId": "tpl_bhe_002"}El identificador queda fijo en la boleta. Eso significa que toda representación posterior de ese documento usa el mismo template, incluido el comprobante con la marca de anulación que se genera después. Un cambio en la configuración de tu empresa NO altera boletas ya emitidas.
Un templateId que no exista, o que pertenezca a otro tipo de documento, responde 400 y la
boleta no se emite. No se resuelve en silencio a otro template.
Templates disponibles:
| Identificador | Formato | Uso típico |
|---|---|---|
tpl_bhe_001 | Carta | Default de la plataforma |
tpl_bhe_002 | Rollo 80 mm | Impresora térmica de mostrador |
tpl_bhe_003 | Rollo 57 mm | Impresora POS |
El template con que se generó cada archivo viene en templateId dentro de
GET /{tenantSlug}/bhe/{id}/archivos. Tu empresa puede tener templates propios además
de estos: los ves en la interfaz web, en el detalle de la boleta.
Estados del PDF SII
Sección titulada «Estados del PDF SII»| Estado | Descripción |
|---|---|
NO_APLICA | Modo SINC_COMPLETO exitoso (ya tiene PDF) o boleta no emitida |
PENDIENTE | En cola para descarga |
DISPONIBLE | Descargado exitosamente |
FALLIDO | Agotó reintentos después de 7 días |
Descargar PDF
Sección titulada «Descargar PDF»# PDF Interno (template personalizado)GET /{tenantSlug}/bhe/{id}/pdf/interno
# PDF SII (respaldo oficial)GET /{tenantSlug}/bhe/{id}/pdf/sii
# Archivo específico del panel de archivosGET /{tenantSlug}/bhe/{id}/archivos/{archivoId}/download
# PDF generado al momento con otro template (no se guarda)GET /{tenantSlug}/bhe/{id}/pdf/custom?templateId=tpl_bhe_002Todos streamean el archivo como application/pdf (Content-Disposition: attachment). No son redirects y nunca entregan una URL de bucket.
Si el documento pedido no existe todavía, responden 404 con el motivo:
{ "success": false, "error": { "code": "PDF_SII_NOT_AVAILABLE", "message": "El PDF SII de esta boleta no está disponible. Estado: PENDIENTE", "estadoPdfSii": "PENDIENTE" }}Usa error.estadoPdfSii para distinguir “todavía se está generando” (PENDIENTE, reintenta más tarde) de “falló definitivamente” (FALLIDO, usa el PDF interno).
Enlaces de descarga para tus usuarios
Sección titulada «Enlaces de descarga para tus usuarios»Si tu sistema tiene una interfaz propia y tus usuarios también son usuarios de Redcumbre, el bloque descargas te da un enlace listo para pintar:
<a href="{{ descargas.pdfInterno }}" target="_blank">Descargar boleta</a><a v-if="estadoPdfSii === 'DISPONIBLE'" :href="descargas.pdfSii" target="_blank">Respaldo SII</a>| Campo | Para qué sirve |
|---|---|
descargas.pdfInterno | Enlace al PDF interno. Descarga directa, sin RUT ni CAPTCHA |
descargas.pdfSii | Ídem para el respaldo SII. Viene siempre, aunque el documento aún no exista |
estadoPdfSii | Semáforo: con DISPONIBLE el respaldo ya está; con PENDIENTE el enlace muestra “se está generando” |
Cómo funcionan:
- Son enlaces de navegación (
<a href>,window.location). No funcionan confetchniaxiosdesde tu dominio: la cookie de sesión de Redcumbre esSameSite=Laxy no viaja en peticiones XHR cross-site. - Requieren un usuario con sesión en Redcumbre y rol del módulo (
SUPER-ADMIN,ADMIN,SII-EMISOR-BHEoFULL-API). Si no hay sesión, el enlace pasa por el login y vuelve solo al documento. - La descarga queda registrada en el historial de actividad de la boleta.
- Son estables: se calculan desde el id y sobreviven a la regeneración del PDF.
Listar Archivos PDF
Sección titulada «Listar Archivos PDF»GET /{tenantSlug}/bhe/{id}/archivosEl campo url de cada archivo es el enlace para el destinatario de la boleta: abre la página
pública de descarga, que le pide su RUT antes de entregar el archivo, y es el mismo enlace que
recibe por correo. No es una URL de bucket. Para descargar el archivo desde tu integración usa
GET /{tenantSlug}/bhe/{id}/archivos/{archivoId}/download.
Response:
{ "success": true, "data": [ { "id": "archivo-001", "tipo": "INTERNO", "templateId": "template-001", "templateName": "Template Carta", "fileName": "bhe_12345678_interno.pdf", "url": "https://...", "sizeBytes": 125000, "createdAt": "2025-12-05T15:30:00Z", "createdBy": "Sistema" }, { "id": "archivo-002", "tipo": "SII", "templateId": null, "templateName": null, "fileName": "bhe_12345678_sii.pdf", "url": "https://...", "sizeBytes": 98000, "createdAt": "2025-12-05T15:35:00Z", "createdBy": "SII" } ]}Listar y Consultar
Sección titulada «Listar y Consultar»Listar Boletas
Sección titulada «Listar Boletas»GET /{tenantSlug}/bhe?fechaDesde=2025-01-01&estado=EMITIDA&limit=50Authorization: Bearer tu-api-keyFiltros disponibles:
| Parámetro | Tipo | Descripción |
|---|---|---|
fechaDesde | ISO 8601 | Fecha de inicio del rango |
fechaHasta | ISO 8601 | Fecha de fin del rango |
emisorTributarioId | string | Filtrar por emisor |
destinatarioRut | string | Filtrar por RUT del destinatario |
estado | enum | EMITIDA, ANULADA, ERROR |
canalEmision | enum | UI, API_SYNC, API_ASYNC |
folioSii | string | Buscar por folio (substring) |
limit | number | Registros por página (default: 50, max: 100) |
offset | number | Registros a saltar (default: 0) |
Response:
{ "data": [ { /* BheResponseDto */ } ], "total": 100, "limit": 50, "offset": 0}Obtener Detalle
Sección titulada «Obtener Detalle»GET /{tenantSlug}/bhe/{id}Authorization: Bearer tu-api-keyEs el documento completo, y es más de lo que devuelve la emisión: emisor, destinatario,
prestaciones con su desglose de descuentos, tipoRetencion, el ppm retenido, fechas,
descargas y el estado de una eventual anulación. Todo eso llega en data (acá sí, plano — la
boleta es el recurso). El listado de campos con sus tipos está en
Swagger.
Webhooks
Sección titulada «Webhooks»El sistema envía webhooks para 4 eventos relacionados con BHE:
| Evento | Descripción | Cuándo se dispara |
|---|---|---|
bhe.emitida | BHE emitida exitosamente | Inmediatamente después de emitir |
bhe.emision_terminada | PDF SII disponible | Cuando se descarga el PDF SII en background |
bhe.pdf_sii_fallido | Descarga PDF SII falló | Después de 7 días de reintentos fallidos |
bhe.emision_reintentando | Un intento falló y va a reintentarse | En cada intento intermedio — informativo, no reemitas |
bhe.emision_fallida | Emisión asíncrona falló definitivamente | Una sola vez: al agotar los 10 intentos, o en el primero si el error es permanente |
Payload: bhe.emitida
Sección titulada «Payload: bhe.emitida»{ "event": "bhe.emitida", "tenantId": "8", "bheId": "cm5abc123", "folioSii": "12345678", "emisor": { "rut": "78012039-8", "razonSocial": "JUAN PÉREZ GONZÁLEZ" }, "destinatario": { "rut": "12345678-9", "nombre": "EMPRESA CLIENTE SA", "sinDestinatario": false }, "montos": { "bruto": 210000, "ppm": 32025, "liquido": 177975 }, "tipoRetencion": "RETRECEPTOR", "canalEmision": "API_SYNC", "correlationId": "mi-referencia-123", "sandbox": false, "estadoPdfSii": "PENDIENTE", "descargas": { "pdfInterno": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123/descargar?tipo=interno", "pdfSii": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123/descargar?tipo=sii" }, "timestamp": "2025-12-05T15:30:00Z"}Payload: bhe.emision_terminada
Sección titulada «Payload: bhe.emision_terminada»Se envía cuando el PDF SII está disponible (solo para modos SINC_PARCIAL y ASINCRONO):
{ "event": "bhe.emision_terminada", "tenantId": "8", "bheId": "cm5abc123", "folioSii": "12345678", "pdfInternoUrl": "https://app.redcumbre.cl/p/boleta/eyJhbGciOiJIUzI1NiJ9...", "pdfSiiUrl": "https://app.redcumbre.cl/p/boleta/eyJhbGciOiJIUzI1NiJ9...", "estadoPdfSii": "DISPONIBLE", "descargas": { "pdfInterno": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123/descargar?tipo=interno", "pdfSii": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123/descargar?tipo=sii" }, "timestamp": "2025-12-05T15:35:00Z"}Payload: bhe.pdf_sii_fallido
Sección titulada «Payload: bhe.pdf_sii_fallido»Se envía después de 7 días de reintentos fallidos:
{ "event": "bhe.pdf_sii_fallido", "tenantId": "8", "bheId": "cm5abc123", "folioSii": "12345678", "intentosRealizados": 30, "primerIntento": "2025-12-01T15:30:00Z", "ultimoIntento": "2025-12-08T15:30:00Z", "ultimoError": "SII_PDF_NO_DISPONIBLE", "descargas": { "pdfInterno": "https://app.redcumbre.cl/acme/tributario/boletas-honorarios/cm5abc123/descargar?tipo=interno" }, "timestamp": "2025-12-08T15:30:00Z"}descargas trae solo pdfInterno: el respaldo SII no llegó a existir.
Payload: bhe.emision_fallida
Sección titulada «Payload: bhe.emision_fallida»Se envía una sola vez, cuando se agotan los 10 intentos (18–22,6 h) o cuando el error del SII no se recupera reintentando. Los intentos intermedios viajan en bhe.emision_reintentando.
{ "event": "bhe.emision_fallida", "tenantId": "8", "correlationId": "mi-referencia-123", "intentosRealizados": 10, "primerIntento": "2025-12-08T10:00:00Z", "ultimoIntento": "2025-12-09T08:36:00Z", "ultimoError": "SII_SERVICE_UNAVAILABLE", "timestamp": "2025-12-09T08:36:00Z"}Cálculo de Montos
Sección titulada «Cálculo de Montos»El sistema calcula automáticamente los montos:
Monto Bruto = Suma de todas las prestacionesPPM = Monto Bruto × tasa de PPM (redondeado al peso)Monto Líquido = Monto Bruto - PPMTipos de Retención
Sección titulada «Tipos de Retención»| Tipo | Descripción |
|---|---|
RETRECEPTOR | El receptor/pagador retiene el PPM (más común) |
RETCONTRIBUYENTE | El emisor retiene su propio PPM |
Códigos de Error
Sección titulada «Códigos de Error»Errores de Validación (400)
Sección titulada «Errores de Validación (400)»A diferencia de los códigos del SII, estos no llegan en un campo errorCode: viajan como
prefijo del message, en la forma CODIGO: detalle.
| Código | Descripción |
|---|---|
MULTIPLE_DESTINATARIO_MODES | Se especificó más de un modo de destinatario |
RETENCION_INVALIDA_SIN_DESTINATARIO | Se envió tipoRetencion: RETRECEPTOR junto con sinDestinatario: true |
DESTINATARIO_REQUIRED | No se especificó ningún modo (y sinDestinatario=false) |
CONTRIBUYENTE_NOT_FOUND | RUT no existe en ContribuyenteMaestro (modo 1) |
INVALID_COMUNA_CODE | codigoComuna no existe en catálogo (modo 2) |
SII_LOOKUP_FAILED | Lookup al SII falló (modo 4) |
Errores del SII
Sección titulada «Errores del SII»El errorCode llega en el cuerpo del error (canal de máquina) y en data.bhe.errorCode (canal web). El status te dice si conviene reintentar sin tener que interpretar el código.
No reintentables — corrige antes de volver a intentar (422)
| Código | Descripción |
|---|---|
SII_CREDENCIAL_INVALIDA | El SII rechazó la clave tributaria del emisor con un motivo explícito (incorrecta, vencida, o cuenta bloqueada). El motivo viene en message |
EMISOR_CREDENCIAL_INVALIDA | La credencial del emisor ya estaba marcada como inválida: la plataforma corta sin llamar al SII. El emisor recibe un correo para actualizarla |
SII_SIN_INICIO_ACTIVIDADES | El contribuyente no registra inicio de actividades |
SII_SIN_SEGUNDA_CATEGORIA | Contribuyente sin actividades de segunda categoría |
SII_PERSONA_JURIDICA | Las BHE solo son para personas naturales |
SII_NO_HABILITADO | Contribuyente no habilitado para emitir BHE |
SII_RUT_INVALIDO | RUT del emisor o destinatario no válido |
SII_DATOS_INVALIDOS | Datos de la boleta incorrectos |
SII_FORM_ERROR | El formulario del SII rechazó los datos enviados |
SII_CERTIFICADO_ERROR | Error con certificado digital |
SII_EMISION_FAILED | El SII rechazó la emisión con un mensaje propio (viene en message) |
Reintentables con backoff — el problema es del SII (502)
| Código | Descripción |
|---|---|
SII_AUTH_FAILED | El SII no devolvió TOKEN y no explicó por qué. Suele ser un problema pasajero de su lado |
SII_ERROR | Error genérico del SII durante la emisión |
SII_RESPUESTA_INESPERADA | El SII respondió algo que no se pudo interpretar |
SII_ERROR_INTERNO | Error interno declarado por el SII (código IMT…) |
SII_SOLICITUD_FALLIDA | ”No ha sido posible completar su solicitud” |
SII_SESION_EXPIRADA | La sesión con el SII expiró durante la operación |
SII_SERVICIO_NO_DISPONIBLE | El servicio del SII no está disponible |
Reintentable con espera — hay turno por delante (503)
| Código | Descripción |
|---|---|
SII_EMISOR_BUSY | Demasiadas emisiones en curso para ese emisor. Respeta el header Retry-After |
Errores de Recurso (404)
Sección titulada «Errores de Recurso (404)»| Código | Descripción |
|---|---|
PDF_NOT_AVAILABLE | No hay PDF disponible para descargar |
PDF_SII_NOT_AVAILABLE | PDF SII no disponible (revisa estadoPdfSii) |
Estados de la Boleta
Sección titulada «Estados de la Boleta»| Estado | Descripción |
|---|---|
EMITIDA | Emitida correctamente en el SII (tiene folio y código de barras) |
ANULADA | Boleta anulada |
ERROR | Error inmediato no reintentable |
Testing (Sandbox)
Sección titulada «Testing (Sandbox)»Utiliza el modo sandbox para probar la integración sin costo:
- API Keys con
isSandbox: trueretornan datos de prueba - No se realizan llamadas reales al SII
- No se genera billing
- Webhooks funcionan normalmente
- No sale ningún correo al destinatario, ni al emitir con
enviarBoletaPorEmail: true, ni al reenviar el PDF manualmente desde la aplicación web. La supresión se decide por el folio de la boleta, así que una boleta emitida en sandbox no despacha correo nunca, tampoco meses después desde el panel. Ver Entornos y modo sandbox.
RUTs de Prueba
Sección titulada «RUTs de Prueba»| RUT | Resultado | Descripción |
|---|---|---|
78012039-8 | ✅ Éxito | Empresa completa (FIRERAISE SPA) |
77425402-1 | ✅ Éxito | Empresa con múltiples direcciones |
13830230-k | ✅ Éxito | Persona natural (PDF SII pendiente) |
99999999-9 | ❌ Error | Destinatario no existe en SII |
Ejemplo en sandbox:
POST /{tenantSlug}/bheAuthorization: Bearer sandbox-api-key
{ "emisorTributarioId": "tu-emisor-tributario-id", "sinDestinatario": false, "lookupRut": "78012039-8", "prestaciones": [ { "descripcion": "Servicio de prueba", "valor": "100000" } ], "tipoRetencion": "RETRECEPTOR"}Response (sandbox):
{ "success": true, "data": { "id": "sandbox-bhe-001", "folioSii": "SANDBOX-12345678", "codigoBarras": "SANDBOX7801203988FB4702C...", "estado": "EMITIDA", ... }, "sandbox": true}API Reference
Sección titulada «API Reference»Para detalles técnicos completos y especificaciones de todos los endpoints:
👉 Ver endpoints de BHE en Swagger
¿Necesitas anular una BHE?
Sección titulada «¿Necesitas anular una BHE?»La anulación ante el SII tiene su propia guía: causas, seguimiento por webhook, comprobante al destinatario y límites de plazo.