Ir al contenido

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.


Antes de emitir una BHE necesitas:

  1. Un Emisor Tributario activo con clave tributaria delegada (no certificado digital)
  2. El emisorTributarioId de ese emisor — va en el cuerpo de toda emisión
  3. Una API Key con uno de estos roles: ADMIN, SUPER-ADMIN, SII-EMISOR-BHE, o FULL-API
  4. Los datos del destinatario (o usar sinDestinatario: true para emitir sin destinatario)

El sistema soporta 3 modos de emisión que permiten balancear entre respuesta inmediata y tolerancia a fallas del SII.

ModoDescripciónRespuestaRecomendado
SINC_COMPLETOTodo síncrono: emitir + PDF interno + PDF SIIBHE completa con ambos PDFsCuando necesitas todo inmediato
SINC_PARCIALEmitir + PDF interno síncronos, PDF SII en backgroundBHE con folio + PDF internoDefault recomendado
ASINCRONOSolo valida y encola. Todo en backgroundID de intento para consultaAlta tolerancia a fallas

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

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:

Ventana de terminal
GET /{tenantSlug}/bhe/intento/{intentoId}

Cuando sinDestinatario=false, existen 4 formas mutuamente excluyentes de especificar el destinatario:

ModoCampoDescripciónCobra SII Lookup
1destinatarioIdRUT de contribuyente guardado en sistemaNo
2destinatarioDatos completos on-the-flyNo
3siiLookupObjeto lookup SII ya obtenidoNo
4lookupRutSolo RUT, sistema ejecuta lookup al SII

¿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 Lookup

Modo 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"
}

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:

CampoTipoRequeridoDescripción
rutstringRUT del destinatario (formato 12345678-9)
nombresstringRazón social o nombre completo
direccionstringDirección completa
codigoRegionstringCódigo de región SII (ej: "13")
codigoComunastringCódigo de comuna SII (ej: "13101")
emailstringNoEmail para envío de boleta

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"
}

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"
}

Ventana de terminal
POST /{tenantSlug}/bhe
Content-Type: application/json
Authorization: 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:

CampoTipoRequeridoDescripción
emisorTributarioIdstringID del emisor tributario
sinDestinatariobooleantrue para emitir sin destinatario
prestacionesarrayLista de servicios (mín 1, máx 4)
tipoRetencionenumRETRECEPTOR o RETCONTRIBUYENTE. Con sinDestinatario: true solo se acepta RETCONTRIBUYENTE (ver Tipos de Retención)
validarCatalogobooleanNoForzar validación contra catálogo de productos
modoenumNoSINC_COMPLETO, SINC_PARCIAL (default), ASINCRONO
enviarBoletaPorEmailbooleanNoEnviar PDF al email del destinatario
templateIdstringNoTemplate 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)
correlationIdstringNoID de correlación para tracking. No es una clave: puedes repetirlo entre boletas distintas
idempotencyKeystringNoClave de idempotencia, máx. 128 caracteres. Protege contra emisiones duplicadas por reintentos (ver Idempotencia)
fechaEmisionstringNoFecha de emisión personalizada (ver sección siguiente)

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, mismo folioSii— 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 ASINCRONO la 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 el intentoId original en vez de encolar una segunda. Con la ventana de reintentos de 18–22,6 h, esa protección puede estar activa durante horas — usa idempotencyKey si tu sistema reintenta por su cuenta.

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.

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"
}
RestricciónDescripción
No futurasLa fecha no puede ser posterior a hoy
Sin validación de plazosNo se valida contra plazos legales del SII
Fecha oficialEl SII registra esta fecha como fecha oficial del documento
Campo en PDFValor
Fecha de EmisiónLa fecha especificada (o fecha actual si no se especificó)
Fecha de ImpresiónSiempre 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:

ModoCampos PermitidosCampos Prohibidos
Item libredescripcion, valorproductoId
Producto del catálogoproductoId, cantidad, descuentoPorcentajedescripcion, 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_PRECIOSí (obligatorio)
permisoEdicion: LIBRE
permisoEdicion: DENTRO_RANGO_DESCUENTOSí (dentro del rango)
permisoEdicion: NO_PERMITIDANo

El sistema soporta dos modos de especificar prestaciones:

Especifica descripcion y valor directamente. Ideal para servicios únicos o personalizados.

{
"prestaciones": [
{ "descripcion": "Servicio de consultoría", "valor": "150000" }
]
}

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
}
]
}

Cuando usas productoId, el sistema valida automáticamente:

ValidaciónDescripción
ExistenciaEl producto debe existir y pertenecer al tenant
EstadoEl producto debe estar en estado ACTIVO
TipoEl producto debe ser tipo SERVICIO (no PRODUCTO)
ILAEl producto NO debe tener impuesto adicional (ILA)
VisibilidadEl producto debe tener visibleEnBhe: true
DescuentoEl 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.


{
"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.


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 emiteQué 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"
}
CampoPara qué sirve
errorCodeLo único que conviene programar: es estable y clasifica la causa
messageTexto legible, apto para mostrarle a tu usuario
boletaIdEl id de la fila que se persistió: GET /{tenantSlug}/bhe/{boletaId} responde 200 con la boleta en ERROR
StatusSignificaQué hacer
422El SII entendió la solicitud y la rechazó por su contenido o por el estado del contribuyenteNo reintentar sin corregir. Reintentar produce el mismo rechazo
502El SII respondió algo que no se puede usar (error interno suyo, sesión caída, servicio degradado)Reintentar con backoff exponencial
503El emisor tiene demasiadas emisiones en curso ante el SII y hay que esperar turnoReintentar después de los segundos que indica el header Retry-After
500Un defecto nuestro. Dos formas, según el errorCodeVer 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»
errorCodeQué pasóQué hacer
(ausente)La emisión falló con un motivo que la plataforma no tiene clasificado. La boleta quedó persistida en ERRORReportarlo con el boletaId
BHE_EMITIDA_NO_PERSISTIDALa boleta SÍ se emitió ante el SII y la plataforma no pudo guardarla. El cuerpo trae folioSii en vez de boletaIdNo 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ó”.


Para el modo ASINCRONO, consulta el estado del intento:

Ventana de terminal
GET /{tenantSlug}/bhe/intento/{intentoId}
Authorization: Bearer tu-api-key
{
"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:

EstadoDescripción
PENDIENTERegistrado en cola, pendiente de procesamiento
PROCESANDOEn proceso de emisión
EMITIDAEmitido exitosamente (tiene BHE asociada)
REINTENTANDOUn intento falló y el sistema va a volver a intentarlo. No es un desenlace: todavía hay algo que esperar
FALLIDAFalló definitivamente: se agotaron los 10 intentos (18–22,6 h) o el error del SII no se recupera reintentando

El sistema genera dos tipos de PDF:

TipoDescripciónDisponibilidad
PDF InternoGenerado con template personalizado del tenantInmediato (modo síncrono)
PDF SIIRespaldo oficial descargado del SIIDepende de disponibilidad del SII

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:

IdentificadorFormatoUso típico
tpl_bhe_001CartaDefault de la plataforma
tpl_bhe_002Rollo 80 mmImpresora térmica de mostrador
tpl_bhe_003Rollo 57 mmImpresora 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.


EstadoDescripción
NO_APLICAModo SINC_COMPLETO exitoso (ya tiene PDF) o boleta no emitida
PENDIENTEEn cola para descarga
DISPONIBLEDescargado exitosamente
FALLIDOAgotó reintentos después de 7 días

Ventana de terminal
# 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 archivos
GET /{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_002

Todos 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).


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>
CampoPara qué sirve
descargas.pdfInternoEnlace 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
estadoPdfSiiSemá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 con fetch ni axios desde tu dominio: la cookie de sesión de Redcumbre es SameSite=Lax y 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-BHE o FULL-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.

Ventana de terminal
GET /{tenantSlug}/bhe/{id}/archivos

El 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"
}
]
}

Ventana de terminal
GET /{tenantSlug}/bhe?fechaDesde=2025-01-01&estado=EMITIDA&limit=50
Authorization: Bearer tu-api-key

Filtros disponibles:

ParámetroTipoDescripción
fechaDesdeISO 8601Fecha de inicio del rango
fechaHastaISO 8601Fecha de fin del rango
emisorTributarioIdstringFiltrar por emisor
destinatarioRutstringFiltrar por RUT del destinatario
estadoenumEMITIDA, ANULADA, ERROR
canalEmisionenumUI, API_SYNC, API_ASYNC
folioSiistringBuscar por folio (substring)
limitnumberRegistros por página (default: 50, max: 100)
offsetnumberRegistros a saltar (default: 0)

Response:

{
"data": [
{ /* BheResponseDto */ }
],
"total": 100,
"limit": 50,
"offset": 0
}

Ventana de terminal
GET /{tenantSlug}/bhe/{id}
Authorization: Bearer tu-api-key

Es 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.


El sistema envía webhooks para 4 eventos relacionados con BHE:

EventoDescripciónCuándo se dispara
bhe.emitidaBHE emitida exitosamenteInmediatamente después de emitir
bhe.emision_terminadaPDF SII disponibleCuando se descarga el PDF SII en background
bhe.pdf_sii_fallidoDescarga PDF SII fallóDespués de 7 días de reintentos fallidos
bhe.emision_reintentandoUn intento falló y va a reintentarseEn cada intento intermedio — informativo, no reemitas
bhe.emision_fallidaEmisión asíncrona falló definitivamenteUna sola vez: al agotar los 10 intentos, o en el primero si el error es permanente

{
"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"
}

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"
}

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.


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"
}

El sistema calcula automáticamente los montos:

Monto Bruto = Suma de todas las prestaciones
PPM = Monto Bruto × tasa de PPM (redondeado al peso)
Monto Líquido = Monto Bruto - PPM
TipoDescripción
RETRECEPTOREl receptor/pagador retiene el PPM (más común)
RETCONTRIBUYENTEEl emisor retiene su propio PPM

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ódigoDescripción
MULTIPLE_DESTINATARIO_MODESSe especificó más de un modo de destinatario
RETENCION_INVALIDA_SIN_DESTINATARIOSe envió tipoRetencion: RETRECEPTOR junto con sinDestinatario: true
DESTINATARIO_REQUIREDNo se especificó ningún modo (y sinDestinatario=false)
CONTRIBUYENTE_NOT_FOUNDRUT no existe en ContribuyenteMaestro (modo 1)
INVALID_COMUNA_CODEcodigoComuna no existe en catálogo (modo 2)
SII_LOOKUP_FAILEDLookup al SII falló (modo 4)

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ódigoDescripción
SII_CREDENCIAL_INVALIDAEl SII rechazó la clave tributaria del emisor con un motivo explícito (incorrecta, vencida, o cuenta bloqueada). El motivo viene en message
EMISOR_CREDENCIAL_INVALIDALa 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_ACTIVIDADESEl contribuyente no registra inicio de actividades
SII_SIN_SEGUNDA_CATEGORIAContribuyente sin actividades de segunda categoría
SII_PERSONA_JURIDICALas BHE solo son para personas naturales
SII_NO_HABILITADOContribuyente no habilitado para emitir BHE
SII_RUT_INVALIDORUT del emisor o destinatario no válido
SII_DATOS_INVALIDOSDatos de la boleta incorrectos
SII_FORM_ERROREl formulario del SII rechazó los datos enviados
SII_CERTIFICADO_ERRORError con certificado digital
SII_EMISION_FAILEDEl SII rechazó la emisión con un mensaje propio (viene en message)

Reintentables con backoff — el problema es del SII (502)

CódigoDescripción
SII_AUTH_FAILEDEl SII no devolvió TOKEN y no explicó por qué. Suele ser un problema pasajero de su lado
SII_ERRORError genérico del SII durante la emisión
SII_RESPUESTA_INESPERADAEl SII respondió algo que no se pudo interpretar
SII_ERROR_INTERNOError interno declarado por el SII (código IMT…)
SII_SOLICITUD_FALLIDA”No ha sido posible completar su solicitud”
SII_SESION_EXPIRADALa sesión con el SII expiró durante la operación
SII_SERVICIO_NO_DISPONIBLEEl servicio del SII no está disponible

Reintentable con espera — hay turno por delante (503)

CódigoDescripción
SII_EMISOR_BUSYDemasiadas emisiones en curso para ese emisor. Respeta el header Retry-After
CódigoDescripción
PDF_NOT_AVAILABLENo hay PDF disponible para descargar
PDF_SII_NOT_AVAILABLEPDF SII no disponible (revisa estadoPdfSii)

EstadoDescripción
EMITIDAEmitida correctamente en el SII (tiene folio y código de barras)
ANULADABoleta anulada
ERRORError inmediato no reintentable

Utiliza el modo sandbox para probar la integración sin costo:

  • API Keys con isSandbox: true retornan 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.

RUTResultadoDescripción
78012039-8✅ ÉxitoEmpresa completa (FIRERAISE SPA)
77425402-1✅ ÉxitoEmpresa con múltiples direcciones
13830230-k✅ ÉxitoPersona natural (PDF SII pendiente)
99999999-9❌ ErrorDestinatario no existe en SII

Ejemplo en sandbox:

Ventana de terminal
POST /{tenantSlug}/bhe
Authorization: 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
}

Para detalles técnicos completos y especificaciones de todos los endpoints:

👉 Ver endpoints de BHE en Swagger


La anulación ante el SII tiene su propia guía: causas, seguimiento por webhook, comprobante al destinatario y límites de plazo.

👉 Anulación de Boletas