---
title: "API: BHE"
description: Boleta de Honorarios Electrónica con retención de segunda categoría calculada por ley, listado con filtros por período y anulación dentro del plazo legal
url: https://notta.cl/docs/api/bhe
related:
  - https://notta.cl/docs/bhe
  - https://notta.cl/docs/api/dtes
  - https://notta.cl/docs/errors
---

> Documentación de Notta en markdown. Índice completo: https://notta.cl/llms.txt — corpus entero: https://notta.cl/llms-full.txt

# "API: BHE"

El recurso `/bhe` emite Boletas de Honorarios Electrónicas por el pipeline REST del SII (`loa.sii.cl/cgi_BHE/`). No interviene certificado digital: la autenticación contra el SII usa la clave tributaria custodiada cifrada de tu org, así que **no se manda `X-Cert-Id`**.

Base URL: `https://app.notta.cl/api/v1`. Autenticación: `Authorization: Bearer ntt_cert_…` — ver [Autenticación](/docs/authentication). La emisión exige `Idempotency-Key`.

La retención de segunda categoría la calcula Notta según la tabla de la Ley 21.420 — no se puede sobrescribir desde el input:

| Año de emisión | Tasa |
|---|---|
| Antes de 2023 | 10% |
| 2023 | 12,25% |
| 2024 | 13% |
| 2025 | 14,5% |
| 2026 y 2027 | 17% |

Si el receptor es persona natural sin giro (`persona_natural_sin_giro: true`), la retención es 0 y el líquido es igual al bruto.

## Endpoints

### `POST /bhe`

Emite una BHE: calcula retención y líquido según el año, persiste el documento y encola el envío REST al SII.

| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| `rut_emisor` | string | sí | RUT del emisor persona, p. ej. `12345678-5`. |
| `receptor.rut` | string | sí | RUT del receptor, p. ej. `76123456-0`. |
| `receptor.razon_social` | string | sí | 1–100 caracteres (se recorta whitespace). |
| `receptor.persona_natural_sin_giro` | boolean | sí | `true` → retención 0 (consumidor final). |
| `fecha_emision` | string | sí | `YYYY-MM-DD`. |
| `monto_bruto` | int | sí | CLP enteros, positivo. |
| `descripcion` | string | sí | 1–1000 caracteres. |
| `sii_env` | enum | no | `cert` (default) o `prod`. |

```bash
curl -X POST https://app.notta.cl/api/v1/bhe \
  -H "Authorization: Bearer ntt_cert_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "rut_emisor": "12345678-5",
    "receptor": { "rut": "76123456-0", "razon_social": "Cliente Ejemplo SpA", "persona_natural_sin_giro": false },
    "fecha_emision": "2026-06-09",
    "monto_bruto": 1000000,
    "descripcion": "Asesoría tributaria junio 2026"
  }'
```

Respuesta `202 Accepted` (bruto 1.000.000 en 2026 → retención 17% = 170.000, líquido 830.000):

```json
{
  "id": "01977f5d-4e80-7000-8000-000000000004",
  "status": "queued",
  "sii_status": "queued",
  "tasa_retencion": 0.17,
  "monto_retencion": 170000,
  "monto_liquido": 830000,
  "period_year": 2026,
  "period_month": 6,
  "links": { "self": "/api/v1/bhe/01977f5d-4e80-7000-8000-000000000004" }
}
```

Errores posibles:

| Código | HTTP | `next_action` |
|---|---|---|
| `idempotency_key_missing` | 400 | — |
| `invalid_json` | 400 | — |
| `validation_failed` (incluye `issues[]` de Zod) | 400 | — |
| `unauthorized` · `invalid_api_key` · `api_key_revoked` · `api_key_expired` | 401 | — |
| `billing.free_tier_exceeded` | 402 | `upgrade_plan` |
| `bhe.credential.invalid` (clave tributaria no configurada o rechazada) | 401 | `configure_bhe_credential` |
| `bhe.receptor.tipo_invalid` | 422 | `fix_receptor_and_retry` |
| `bhe.retencion.mismatch` | 422 | `use_calculated_retencion` |

### `GET /bhe`

Lista las BHE de tu organización, con filtros por período tributario y estado.

| Query param | Tipo | Requerido | Descripción |
|---|---|---|---|
| `period_year` | int | no | Año del período tributario. |
| `period_month` | int | no | Mes del período (1–12). |
| `anulada` | boolean | no | `true` / `false`. |
| `sii_status` | string | no | Filtra por estado SII. |
| `limit` | int | no | 1–100, default 50. |
| `sort` | enum | no | `folio` · `period` · `monto_bruto` · `monto_liquido` · `sii_status` · `created_at`. |
| `dir` | enum | no | `asc` · `desc`. |

```bash
curl "https://app.notta.cl/api/v1/bhe?period_year=2026&period_month=6&anulada=false" \
  -H "Authorization: Bearer ntt_cert_..."
```

Respuesta `200 OK`:

```json
{
  "bhes": [
    {
      "id": "01977f5d-4e80-7000-8000-000000000004",
      "folio": 12,
      "period_year": 2026,
      "period_month": 6,
      "rut_emisor": "12345678-5",
      "rut_receptor": "76123456-0",
      "razon_social_receptor": "Cliente Ejemplo SpA",
      "receptor_persona_natural_sin_giro": false,
      "descripcion": "Asesoría tributaria junio 2026",
      "monto_bruto": 1000000,
      "tasa_retencion": "0.1700",
      "monto_retencion": 170000,
      "monto_liquido": 830000,
      "sii_status": "EPR",
      "sii_env": "cert",
      "anulada": false,
      "anulada_at": null,
      "anulada_reason": null,
      "track_id": null,
      "fecha_emision": "2026-06-09",
      "created_at": "2026-06-09T17:10:33.000Z",
      "links": { "self": "/api/v1/bhe/01977f5d-4e80-7000-8000-000000000004" }
    }
  ],
  "next_cursor": null
}
```

El array viene bajo la clave `bhes`. Errores posibles: `401` de autenticación.

Ojo con el tipo de `tasa_retencion`: el `POST /bhe` la devuelve como número (`0.17`), pero los `GET` la devuelven como string (`"0.1700"`), tal cual se serializa la columna numérica.

### `GET /bhe/:id`

Devuelve el detalle de una BHE con montos, estado SII y datos de anulación si aplica (mismo shape que cada elemento del listado).

```bash
curl https://app.notta.cl/api/v1/bhe/01977f5d-4e80-7000-8000-000000000004 \
  -H "Authorization: Bearer ntt_cert_..."
```

Errores posibles:

| Código | HTTP | `next_action` |
|---|---|---|
| `bhe.not_found` | 404 | — |

### `POST /bhe/:id/anular`

Anula una BHE dentro del plazo legal; la marca anulada localmente y la anulación SII corre en el workflow.

| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| `razon` | string | sí | Motivo de anulación, 1–250 caracteres. |

> **Plazo legal de anulación: 3 meses:**
La BHE solo se puede anular dentro de 3 meses calendario desde la emisión. Pasado el plazo la API responde `422 bhe.plazo_anulacion.expired` y el camino que queda es la rectificación manual ante el SII.

```bash
curl -X POST https://app.notta.cl/api/v1/bhe/01977f5d-4e80-7000-8000-000000000004/anular \
  -H "Authorization: Bearer ntt_cert_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "razon": "Servicio no prestado" }'
```

Respuesta `200 OK`:

```json
{ "id": "01977f5d-4e80-7000-8000-000000000004", "anulada": true, "folio": 12 }
```

Errores posibles:

| Código | HTTP | `next_action` |
|---|---|---|
| `invalid_json` | 400 | — |
| `validation_failed` (incluye `issues[]` de Zod) | 400 | — |
| `bhe.not_found` | 404 | — |
| `bhe.plazo_anulacion.expired` | 422 | `consult_sii_or_manual_rectification` |

## Próximos pasos

- **[BHE — guía completa](/docs/bhe)** — onboarding de la clave tributaria, retención año a año y el flujo del freelancer.
- [API: DTEs](/docs/api/dtes) — si además facturas como empresa (33/34/56/61).
- [Catálogo de errores](/docs/errors) — códigos y `next_action` de toda la API.
