---
title: "Preparación de la integración"
description: ""
type: "academy"
category: "module"
tags: []
authors: [Anonymous]
date: "2026-11-05"
last_update: "2026-11-05"
time_minutes: 20
draft: false
unlisted: false
url: "https://www.apigateway.cl/academy/emision-de-dte/preparacion"
---

# Preparación de la integración




---

## Cómo funciona la API de LibreDTE

La forma de las URL, del cuerpo y de las respuestas de los recursos /api/v2/libredte/, la regla del base64 y los errores.

# Cómo funciona la API de LibreDTE

La emisión de documentos en API Gateway V2 se hace con los recursos que empiezan con `/api/v2/libredte/`. Todos siguen las mismas reglas, así que si entiendes esta lección vas a poder usar cualquiera de ellos.

## La URL

Cada recurso es una **operación** de la biblioteca de LibreDTE, identificada por cuatro partes:

```
POST https://app.apigateway.cl/api/v2/libredte/{paquete}/{componente}/{worker}/{operación}
```

Por ejemplo, la operación que construye un documento es:

```
POST https://app.apigateway.cl/api/v2/libredte/billing/document/builder/build
                                               ──┬──── ───┬──── ───┬─── ──┬──
                                              paquete componente worker operación
```

| Parte | Significado | Valores que usarás en este curso |
|-------|-------------|----------------------------------|
| `paquete` | Área de la biblioteca | `billing` (facturación), `system` (certificado) |
| `componente` | Tema dentro del área | `document`, `identifier` (folios), `integration` (SII), ... |
| `worker` | Quién hace el trabajo | `builder`, `validator`, `dispatcher`, `renderer`, `sii_dte`, ... |
| `operación` | Qué se hace | `build`, `validateSchema`, `create`, `render`, ... |

La operación se escribe en camelCase, igual que el método de la biblioteca: `validateSchema`, `sendXmlDocument`. El paquete, el componente y el worker se escriben tal como los nombra la biblioteca, por ejemplo `sii_dte`.

Todas las operaciones usan el método **POST**.

## El cuerpo de la solicitud

El cuerpo siempre es un objeto JSON con un único atributo, `parameters`, que contiene los parámetros de la operación con el nombre que declara la documentación:

```json
{
    &quot;parameters&quot;: {
        &quot;nombre_del_parametro&quot;: &quot;valor&quot;
    }
}
```

Por ejemplo, la operación que construye un documento recibe un único parámetro llamado `bag` (la &quot;bolsa&quot; con los datos del documento):

```json
{
    &quot;parameters&quot;: {
        &quot;bag&quot;: {
            &quot;parsedData&quot;: { &quot;...&quot;: &quot;datos del documento&quot; },
            &quot;caf&quot;: &quot;...&quot;,
            &quot;certificate&quot;: { &quot;...&quot;: &quot;certificado digital&quot; }
        }
    }
}
```

## Las cabeceras

```http
Authorization: Token &lt;tu_token&gt;
Content-Type: application/json
```

El token es el de tu conexión de API Gateway. A diferencia de las consultas al SII de otros cursos, aquí **no** hay bloque `auth` con RUT y clave: lo que se necesita para hablar con el SII (el certificado digital) va dentro de los parámetros de cada operación.

## La regla del base64

Los datos que no son JSON viajan codificados en **base64**: los XML (del DTE, del sobre, del CAF), los archivos `.p12` y los PDF. Esto evita problemas de caracteres especiales, porque los XML del SII usan la codificación ISO-8859-1 y no UTF-8.

| Dato | Cómo se envía | Cómo vuelve |
|------|---------------|-------------|
| Datos del documento | JSON | JSON |
| XML de un DTE, de un sobre o de un CAF | base64 | base64 |
| Certificado `.p12`/`.pfx` | base64 (con su contraseña aparte) | (no vuelve) |
| Certificado en formato PEM | texto PEM, **sin** base64 | (no vuelve) |
| PDF | (no se envía) | base64 |

Ejemplos para codificar y decodificar en la terminal:

```bash
# Codificar un archivo en base64, en una sola línea
base64 -i caf.xml | tr -d &#039;\n&#039;

# Decodificar el base64 de una respuesta a un archivo
echo &quot;PD94bWwgdmVyc2lvbj0i...&quot; | base64 -d &gt; dte.xml
```

## La respuesta

Si la operación funciona, la respuesta es un JSON con el resultado dentro de `data`:

```json
{
    &quot;data&quot;: {
        &quot;...&quot;: &quot;resultado de la operación&quot;
    }
}
```

Algunas operaciones no entregan nada (por ejemplo, una validación que no encontró problemas). En ese caso la respuesta es `{&quot;data&quot;: null}` con código `200`.

## Los errores

Si algo falla, la respuesta trae el código HTTP y un mensaje en `detail`:

```json
{
    &quot;code&quot;: 422,
    &quot;detail&quot;: &quot;El folio 500 del documento 88888888-8_T033F000000500 no está disponible en el rango del CAF CAF33D1H100.&quot;
}
```

| Código | Qué significa | Qué hacer |
|--------|---------------|-----------|
| `400` | Falta un parámetro o no tiene el tipo esperado. | Revisa los nombres dentro de `parameters`. |
| `401` | Token inválido o ausente. | Revisa la cabecera `Authorization`. |
| `402` | Problema de créditos o de pago de la conexión. | Revisa tu conexión (ver [Manejo de errores](https://www.apigateway.cl/academy/primeros-pasos/punto-de-partida/manejo-de-errores)). |
| `404` | La operación no existe. | Revisa la URL: las cuatro partes deben coincidir con la documentación. |
| `422` | La operación se ejecutó, pero **los datos fueron rechazados**: un RUT inválido, un folio fuera del CAF, un XML mal formado, una firma inválida, etc. | Lee `detail`: explica exactamente qué dato corregir. |
| `500` | Error inesperado. | Reintenta y, si persiste, [abre un ticket](https://www.apigateway.cl/help) con la hora y la operación. |
| `503` | El servicio de LibreDTE no está disponible en ese momento. | Reintenta más tarde. |

&gt; [!TIP] El 422 es tu amigo
&gt;
&gt; Casi todos los errores de una integración nueva son `422`, y el mensaje de `detail` dice qué está mal. Muéstralo en tus logs completo: te ahorrará mucho tiempo.

## Dónde ver cada operación

La [documentación de la API](https://www.apigateway.cl/docs/api) tiene una ficha por operación, agrupadas como **API LibreDTE - billing.document**, **API LibreDTE - billing.identifier**, etc. Cada ficha indica:

- Los parámetros y un ejemplo del cuerpo.
- Qué entrega y por qué puede rechazar los datos.
- El costo en créditos.


    
---

## Tu primera llamada

Una primera llamada sin riesgo: listar y obtener los ejemplos de documentos que incluye la API.

# Tu primera llamada

Antes de construir documentos, haz una llamada sencilla que no necesita certificado ni folios: pedir los **ejemplos de documentos** que trae la biblioteca. Te sirve para confirmar que el token funciona y, además, te entrega documentos de ejemplo listos para adaptar.

## Listar los ejemplos

```bash
curl -X POST https://app.apigateway.cl/api/v2/libredte/billing/document/examples/list \
  -H &quot;Authorization: Token $API_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#039;{&quot;parameters&quot;: {}}&#039;
```

Esta operación no tiene parámetros, por eso `parameters` va vacío. La respuesta es la lista de ejemplos disponibles:

```json
{
    &quot;data&quot;: [
        {
            &quot;id&quot;: &quot;033_factura_afecta/033_001_simple&quot;,
            &quot;category&quot;: &quot;033_factura_afecta&quot;,
            &quot;case&quot;: &quot;033_001_simple&quot;
        },
        {
            &quot;id&quot;: &quot;052_guia_despacho/052_001_constituye_venta&quot;,
            &quot;category&quot;: &quot;052_guia_despacho&quot;,
            &quot;case&quot;: &quot;052_001_constituye_venta&quot;
        }
    ]
}
```

La categoría empieza con el código del tipo de documento: `033` factura, `052` guía de despacho, `061` nota de crédito, etc.

## Obtener un ejemplo

```bash
curl -X POST https://app.apigateway.cl/api/v2/libredte/billing/document/examples/get \
  -H &quot;Authorization: Token $API_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#039;{&quot;parameters&quot;: {&quot;id&quot;: &quot;033_factura_afecta/033_001_simple&quot;}}&#039;
```

Respuesta:

```json
{
    &quot;data&quot;: {
        &quot;id&quot;: &quot;033_factura_afecta/033_001_simple&quot;,
        &quot;example&quot;: {
            &quot;Encabezado&quot;: {
                &quot;IdDoc&quot;: {
                    &quot;TipoDTE&quot;: 33,
                    &quot;Folio&quot;: 1
                },
                &quot;Emisor&quot;: {
                    &quot;RUTEmisor&quot;: &quot;88888888-8&quot;,
                    &quot;RznSoc&quot;: &quot;Mi Empresa SpA&quot;,
                    &quot;GiroEmis&quot;: &quot;Venta de software&quot;,
                    &quot;Acteco&quot;: 620200,
                    &quot;DirOrigen&quot;: &quot;Av. Siempre Viva 742&quot;,
                    &quot;CmnaOrigen&quot;: &quot;Providencia&quot;
                },
                &quot;Receptor&quot;: {
                    &quot;RUTRecep&quot;: &quot;60803000-K&quot;,
                    &quot;RznSocRecep&quot;: &quot;Servicio de Impuestos Internos&quot;,
                    &quot;GiroRecep&quot;: &quot;Gobierno&quot;,
                    &quot;DirRecep&quot;: &quot;Santiago&quot;,
                    &quot;CmnaRecep&quot;: &quot;Santiago&quot;
                }
            },
            &quot;Detalle&quot;: [
                {
                    &quot;NmbItem&quot;: &quot;Conectores RJ45&quot;,
                    &quot;QtyItem&quot;: 450,
                    &quot;PrcItem&quot;: 70
                }
            ]
        },
        &quot;expected&quot;: {
            &quot;Encabezado&quot;: {
                &quot;Totales&quot;: {
                    &quot;MntNeto&quot;: 31500,
                    &quot;IVA&quot;: 5985,
                    &quot;MntTotal&quot;: 37485
                }
            }
        }
    }
}
```

&gt; [!NOTE] Datos de ejemplo
&gt;
&gt; Los ejemplos de la API traen los datos de un emisor de demostración. En este extracto los reemplazamos por datos ficticios. Cuando emitas, usa siempre los datos de tu empresa.

- `example` son los datos del documento, tal como los enviarás para construirlo.
- `expected` son los totales que debería calcular la API. Fíjate que el ejemplo **no trae totales**: la API los calcula (450 × $70 = $31.500 neto, más 19% de IVA = $5.985).

&gt; [!TIP] Usa los ejemplos como plantilla
&gt;
&gt; Cuando tengas que emitir un caso nuevo (una factura con descuento, una guía de devolución, una nota que corrige montos), busca primero si existe un ejemplo parecido. Es la forma más rápida de saber qué campos lleva.

## Qué revisar si falla

| Respuesta | Causa probable |
|-----------|----------------|
| `401` | El token está mal escrito o falta la palabra `Token` antes del token. |
| `402` | La conexión no tiene créditos o tiene un problema de pago. |
| `404` | Hay un error en la URL. |
| `200` con `data` | ¡Todo bien! Sigue con la siguiente lección. |

## En Python

La API es HTTP y JSON, así que funciona con cualquier lenguaje. En Python, con `requests`:

```python
import os
import requests

API_URL = &#039;https://app.apigateway.cl/api/v2/libredte&#039;
HEADERS = {
    &#039;Authorization&#039;: f&#039;Token {os.environ[&quot;API_TOKEN&quot;]}&#039;,
    &#039;Content-Type&#039;: &#039;application/json&#039;,
}

def libredte(operacion: str, parameters: dict) -&gt; dict | list | None:
    &quot;&quot;&quot;Ejecuta una operación de LibreDTE y entrega el contenido de `data`.&quot;&quot;&quot;
    response = requests.post(
        f&#039;{API_URL}/{operacion}&#039;,
        json={&#039;parameters&#039;: parameters},
        headers=HEADERS,
        timeout=120,
    )
    if response.status_code != 200:
        try:
            detalle = response.json().get(&#039;detail&#039;, response.text)
        except ValueError:  # La respuesta de error no viene en JSON.
            detalle = response.text
        raise RuntimeError(f&#039;{operacion}: HTTP {response.status_code}: {detalle}&#039;)
    return response.json()[&#039;data&#039;]

ejemplos = libredte(&#039;billing/document/examples/list&#039;, {})
print(len(ejemplos), &#039;ejemplos disponibles&#039;)
```

Usaremos esta función `libredte()` en el resto del curso.


    
---

## El certificado digital

Qué es el certificado digital, en qué formatos enviarlo a la API, cómo verificarlo y cómo protegerlo.

# El certificado digital

El **certificado digital** (o firma electrónica) es lo que permite firmar los documentos. Pertenece a una **persona**, no a la empresa: es la persona que el SII autorizó para firmar los documentos de la empresa emisora.

Se usa en tres momentos:

1. Para **firmar el DTE** al construirlo.
2. Para **firmar el sobre** que se envía al SII.
3. Para **autenticarse en el SII** al enviar y al consultar el estado.

&gt; [!INFO] El RUT de la firma no es el de la empresa
&gt;
&gt; El certificado tiene el RUT de la persona (por ejemplo `11222333-9`), no el de la empresa (`88888888-8`). En el sobre aparece como `RutEnvia`: quien envía el documento en nombre de la empresa. Esa persona debe estar autorizada en el SII para la empresa emisora.

## Formatos que acepta la API

En las operaciones de LibreDTE el certificado va en un objeto `certificate`, en **una** de estas dos formas. En todos los ejemplos del curso usamos PEM, porque es el mismo formato que usan los recursos de consulta al SII.

### Opción 1: certificado y llave privada en PEM (la que usamos en este curso)

```json
&quot;certificate&quot;: {
    &quot;certificate&quot;: &quot;-----BEGIN CERTIFICATE-----\nMIIEcTCCA1mgAwIBAgIBRTAN...\n-----END CERTIFICATE-----\n&quot;,
    &quot;privateKey&quot;: &quot;-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0B...\n-----END PRIVATE KEY-----\n&quot;
}
```

- `certificate`: el certificado público en formato PEM (texto, **sin** base64).
- `privateKey`: la llave privada en formato PEM (texto, **sin** base64).

Normalmente el certificado se entrega como archivo `.p12` o `.pfx`. Para obtener los PEM a partir de ese archivo, cárgalo con la operación `system/certificate/loader/load`: envía el archivo en base64 y su contraseña, como en la [opción 2](#opción-2-archivo-p12--pfx-en-base64):

```bash
curl -X POST https://app.apigateway.cl/api/v2/libredte/system/certificate/loader/load \
  -H &quot;Authorization: Token $API_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#039;{
    &quot;parameters&quot;: {
        &quot;certificate&quot;: {
            &quot;data&quot;: &quot;MIIKkQIBAzCCClcGCSqGSIb3DQEHAaCCCkgEggpEMIIKQDCCBPcGCSqG...&quot;,
            &quot;password&quot;: &quot;contraseña_del_archivo&quot;
        }
    }
}&#039;
```

La respuesta trae el certificado en `cert` y la llave privada en `pkey`, los dos en PEM:

```json
{
    &quot;data&quot;: {
        &quot;id&quot;: &quot;11222333-9&quot;,
        &quot;name&quot;: &quot;Daniel Bot&quot;,
        &quot;cert&quot;: &quot;-----BEGIN CERTIFICATE-----\nMIIEcTCCA1mgAwIBAgIBRTAN...\n-----END CERTIFICATE-----\n&quot;,
        &quot;pkey&quot;: &quot;-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0B...\n-----END PRIVATE KEY-----\n&quot;,
        &quot;...&quot;: &quot;...&quot;
    }
}
```

Guarda `cert` como `cert.pem` y `pkey` como `key.pem`. Haz esta conversión una sola vez y guarda los PEM como secretos: no la repitas en cada emisión.

&gt; [!TIP] Los saltos de línea
&gt;
&gt; En JSON, los saltos de línea de un PEM se escriben como `\n`. Si armas el JSON con un lenguaje de programación (leyendo el archivo y serializándolo), esto ocurre solo. Si lo pegas a mano, revisa que no quede todo en una línea sin `\n`.

### Opción 2: archivo `.p12` / `.pfx` en base64

```json
&quot;certificate&quot;: {
    &quot;data&quot;: &quot;MIIKkQIBAzCCClcGCSqGSIb3DQEHAaCCCkgEggpEMIIKQDCCBPcGCSqG...&quot;,
    &quot;password&quot;: &quot;contraseña_del_archivo&quot;
}
```

- `data`: el archivo `.p12` o `.pfx` completo, codificado en base64 en una sola línea.
- `password`: la contraseña del archivo.

```bash
base64 -i firma.p12 | tr -d &#039;\n&#039;
```

&gt; [!WARNING] No es el mismo formato que en las consultas al SII
&gt;
&gt; Los recursos de consulta al SII (por ejemplo, los de folios en `/api/v2/sii/dte/caf/...`) reciben el certificado en el bloque `auth.cert` con los campos `cert-data` y `pkey-data` (o `file-data` y `file-pass`). Los recursos de LibreDTE (`/api/v2/libredte/...`) lo reciben en `certificate` con `certificate` y `privateKey` (o `data` y `password`). Son el mismo certificado, con distinto nombre de campos.

| Recurso | Campo | PEM | `.p12` en base64 |
|---------|-------|-----|------------------|
| `/api/v2/libredte/...` | `certificate` | `certificate` + `privateKey` | `data` + `password` |
| `/api/v2/sii/...` | `auth.cert` | `cert-data` + `pkey-data` | `file-data` + `file-pass` |

## Verificar el certificado

Antes de usarlo para firmar, puedes comprobar que la API lo lee bien y cuándo vence:

```bash
curl -X POST https://app.apigateway.cl/api/v2/libredte/system/certificate/loader/load \
  -H &quot;Authorization: Token $API_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#039;{
    &quot;parameters&quot;: {
        &quot;certificate&quot;: {
            &quot;certificate&quot;: &quot;-----BEGIN CERTIFICATE-----\nMIIG...\n-----END CERTIFICATE-----&quot;,
            &quot;privateKey&quot;: &quot;-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----&quot;
        }
    }
}&#039;
```

La respuesta trae, entre otros datos:

```json
{
    &quot;data&quot;: {
        &quot;id&quot;: &quot;11222333-9&quot;,
        &quot;name&quot;: &quot;Daniel Bot&quot;,
        &quot;email&quot;: &quot;daniel.bot@example.com&quot;,
        &quot;from&quot;: &quot;2026-10-29T11:38:23&quot;,
        &quot;to&quot;: &quot;2027-10-29T11:38:23&quot;,
        &quot;expirationDays&quot;: 364,
        &quot;isActive&quot;: true,
        &quot;issuer&quot;: &quot;Derafu Test Certificate Authority&quot;
    }
}
```

| Campo | Qué revisar |
|-------|-------------|
| `id` | El RUT de la persona dueña del certificado. |
| `to` / `expirationDays` | Cuándo vence. Un certificado vencido no puede firmar. |
| `isActive` | Debe ser `true`. |

Si falta un dato, la API responde con un error como:

```json
{
    &quot;code&quot;: 422,
    &quot;detail&quot;: &quot;Se requieren los datos del certificado (data y password) o sus llaves (certificate y privateKey).&quot;
}
```

## Seguridad

El certificado permite firmar documentos tributarios **a nombre de la empresa**. Trátalo como una contraseña:

- Guárdalo cifrado o en un almacén de secretos (variables de entorno del servidor, un vault, el gestor de secretos de tu nube).
- Nunca lo subas a un repositorio ni lo envíes desde el navegador o una app móvil: las llamadas a la API deben salir de **tu servidor**.
- No guardes en tus logs las solicitudes ni las respuestas completas: incluyen el certificado.
- Controla su vencimiento y renuévalo antes de que expire.

## Un certificado de prueba

Mientras sigues el curso puedes construir documentos con un certificado de prueba: la API firmará el XML igual. Lo que no podrás hacer sin un certificado real autorizado es **enviar al SII**, porque el SII rechazará la autenticación.

La API genera uno con esta operación:

```bash
curl -X POST https://app.apigateway.cl/api/v2/libredte/billing/trading_parties/mandatario_manager/createFakeCertificate \
  -H &quot;Authorization: Token $API_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#039;{
    &quot;parameters&quot;: {
        &quot;mandatario&quot;: {
            &quot;run&quot;: &quot;11222333-9&quot;,
            &quot;nombre&quot;: &quot;Daniel Bot&quot;,
            &quot;email&quot;: &quot;daniel.bot@example.com&quot;
        }
    }
}&#039;
```

La respuesta (resumida) trae el certificado y su llave privada en PEM, válidos por un año:

```json
{
    &quot;data&quot;: {
        &quot;id&quot;: &quot;11222333-9&quot;,
        &quot;name&quot;: &quot;Daniel Bot&quot;,
        &quot;email&quot;: &quot;daniel.bot@example.com&quot;,
        &quot;from&quot;: &quot;2026-11-04T14:07:03&quot;,
        &quot;to&quot;: &quot;2027-11-04T14:07:03&quot;,
        &quot;issuer&quot;: &quot;Derafu Test Certificate Authority&quot;,
        &quot;cert&quot;: &quot;-----BEGIN CERTIFICATE-----\nMIIE...\n-----END CERTIFICATE-----\n&quot;,
        &quot;pkey&quot;: &quot;-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----\n&quot;,
        &quot;...&quot;: &quot;...&quot;
    }
}
```

Guarda `cert` como `cert.pem` y `pkey` como `key.pem`, y úsalos como cualquier certificado en PEM: `&quot;certificate&quot;: {&quot;certificate&quot;: &lt;cert&gt;, &quot;privateKey&quot;: &lt;pkey&gt;}`.


    
---

## Folios y CAF

Qué es un CAF, cómo solicitarlo al SII con la API o en el sitio del SII, cómo revisarlo, cómo controlar los folios en tu sistema y cómo practicar con un CAF de prueba.

# Folios y CAF

Cada documento tiene un **folio** (su número). No puedes usar cualquier número: el SII te autoriza **rangos de folios** por tipo de documento, y esa autorización llega en un archivo llamado **CAF** (Código de Autorización de Folios).

Por ejemplo, un CAF puede decir: &quot;la empresa `88888888-8` puede emitir facturas (`33`) con los folios del `1` al `100`&quot;.

## Qué contiene un CAF

Es un XML firmado por el SII:

```xml
&lt;AUTORIZACION&gt;
  &lt;CAF version=&quot;1.0&quot;&gt;
    &lt;DA&gt;
      &lt;RE&gt;88888888-8&lt;/RE&gt;          &lt;!-- RUT del emisor --&gt;
      &lt;RS&gt;Mi Empresa SpA&lt;/RS&gt;      &lt;!-- Razón social --&gt;
      &lt;TD&gt;33&lt;/TD&gt;                  &lt;!-- Tipo de documento --&gt;
      &lt;RNG&gt;&lt;D&gt;1&lt;/D&gt;&lt;H&gt;100&lt;/H&gt;&lt;/RNG&gt;&lt;!-- Rango: desde el 1 hasta el 100 --&gt;
      &lt;FA&gt;2026-10-29&lt;/FA&gt;          &lt;!-- Fecha de autorización --&gt;
      &lt;RSAPK&gt;...&lt;/RSAPK&gt;           &lt;!-- Llave pública --&gt;
      &lt;IDK&gt;100&lt;/IDK&gt;
    &lt;/DA&gt;
    &lt;FRMA algoritmo=&quot;SHA1withRSA&quot;&gt;...&lt;/FRMA&gt;   &lt;!-- Firma del SII --&gt;
  &lt;/CAF&gt;
  &lt;RSASK&gt;...&lt;/RSASK&gt;               &lt;!-- Llave privada para timbrar --&gt;
  &lt;RSAPUBK&gt;...&lt;/RSAPUBK&gt;
&lt;/AUTORIZACION&gt;
```

La llave privada del CAF (`RSASK`) es la que se usa para **timbrar** cada documento. Por eso el CAF también es un dato sensible: guárdalo con el mismo cuidado que el certificado.

&gt; [!INFO] Reglas de los folios
&gt;
&gt; - Un CAF sirve para **un solo tipo de documento** y **un solo emisor**.
&gt; - Un CAF de **certificación** no sirve en **producción**, y al revés.
&gt; - Cada folio se usa **una sola vez**. La excepción es un documento **rechazado** por el SII: se considera no emitido, y su folio se vuelve a usar al emitirlo corregido.
&gt; - Los CAF de facturas, notas de crédito y notas de débito **vencen a los 6 meses** de autorizados: revisa la fecha de vencimiento al cargarlo. Los de boletas, facturas exentas, guías de despacho y documentos de exportación no vencen.

## Obtener el CAF

Los CAF se solicitan al SII con el certificado digital de una persona autorizada por la empresa. Puedes hacerlo de dos formas, y ambas sirven para **cualquier** CAF, incluido el primero de cada tipo de documento:

| Forma | Cuándo conviene |
|-------|-----------------|
| **Con la API** | Para automatizar: tu sistema pide folios cuando se están acabando. |
| **En el sitio del SII** | Para una solicitud puntual, a mano: [ambiente de certificación](https://www.sii.cl/factura_electronica/factura_mercado/menu_certificacion.html) o [ambiente de producción](https://palena.sii.cl/dte/menu.html). |

### Solicitar un CAF con la API

```bash
curl -X POST &quot;https://app.apigateway.cl/api/v2/sii/dte/caf/solicitar/88888888-8/33/100?certificacion=1&quot; \
  -H &quot;Authorization: Token $API_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#039;{
    &quot;auth&quot;: {
        &quot;cert&quot;: {
            &quot;cert-data&quot;: &quot;-----BEGIN CERTIFICATE-----\nMIIG...\n-----END CERTIFICATE-----&quot;,
            &quot;pkey-data&quot;: &quot;-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----&quot;
        }
    }
}&#039;
```

| Parte | Significado |
|-------|-------------|
| `88888888-8` | RUT del emisor |
| `33` | Tipo de documento |
| `100` | Cantidad de folios |
| `certificacion=1` | Ambiente de certificación. Usa `0` (o no lo indiques) para producción. |

La respuesta **no es JSON**: es directamente el XML del CAF, en codificación ISO-8859-1. Guárdalo tal cual como archivo.

&gt; [!WARNING] El SII decide la cantidad
&gt;
&gt; El SII puede autorizar menos folios de los que pides, según el historial de emisión de la empresa. Revisa siempre el rango real del CAF que recibiste.

### Otros recursos de folios

Todos son `POST`, usan el bloque `auth.cert` y el parámetro `certificacion` igual que la solicitud, y sus URL parten en `/api/v2/sii/dte/caf/`:

| Para qué sirve | Recurso |
|----------------|---------|
| Volver a descargar un CAF ya autorizado, por ejemplo si lo perdiste | `xml/{emisor}/{dte}/{desde}/{hasta}/{fecha}` |
| Ver el historial de CAF solicitados | `solicitudes/{emisor}/{dte}` |
| Ver el estado de un folio en el SII | `estado/{emisor}/{dte}/{folio}` |
| Ver qué folios de un rango están recibidos, anulados o pendientes | `estados/{emisor}/{dte}/{desde}/{hasta}/{estado}` |
| Anular folios que nunca vas a usar | `anular/{emisor}/{dte}/{desde}/{hasta}` |

El detalle de cada uno está en la [documentación de la API](https://www.apigateway.cl/docs/api), en **API DTE - Código de Asignación de Folios (CAF)**.

## Revisar un CAF

Antes de guardar un CAF en tu sistema, cárgalo con la API para leer sus datos. El XML va en base64:

```bash
curl -X POST https://app.apigateway.cl/api/v2/libredte/billing/identifier/caf_loader/load \
  -H &quot;Authorization: Token $API_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#039;{&quot;parameters&quot;: {&quot;xml&quot;: &quot;PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iSVNPLTg4NTktMSI/Pgo8QVVU...&quot;}}&#039;
```

Respuesta (resumida):

```json
{
    &quot;data&quot;: {
        &quot;id&quot;: &quot;CAF33D1H100&quot;,
        &quot;emisor&quot;: {
            &quot;rut&quot;: &quot;88888888-8&quot;,
            &quot;razon_social&quot;: &quot;Mi Empresa SpA&quot;
        },
        &quot;tipoDocumento&quot;: 33,
        &quot;folioDesde&quot;: 1,
        &quot;folioHasta&quot;: 100,
        &quot;cantidadFolios&quot;: 100,
        &quot;fechaAutorizacion&quot;: &quot;2026-10-29&quot;,
        &quot;fechaVencimiento&quot;: &quot;2027-04-27&quot;,
        &quot;vigente&quot;: true,
        &quot;vence&quot;: true
    }
}
```

Guarda en tu base de datos al menos: el emisor, el tipo de documento, `folioDesde`, `folioHasta`, `fechaVencimiento`, el ambiente y el XML del CAF.

## Controlar los folios en tu sistema

La API **no** lleva la cuenta de qué folios usaste: eso es responsabilidad de tu sistema. Una forma simple de hacerlo:

**Tabla de CAF**: un registro por cada CAF recibido.

| emisor | tipo | desde | hasta | vence | ambiente |
|--------|------|-------|-------|-------|----------|
| 88888888-8 | 33 | 1 | 100 | 2027-04-27 | certificación |

**Tabla de folios usados**: un registro por cada folio que asignas.

| emisor | tipo | folio | estado |
|--------|------|-------|--------|
| 88888888-8 | 33 | 1 | aceptado |
| 88888888-8 | 33 | 2 | enviado |

Para emitir:

1. Busca un CAF vigente del emisor, tipo de documento y ambiente.
2. Toma el siguiente folio libre de ese CAF y **resérvalo** en tu base de datos dentro de una transacción, para que dos emisiones simultáneas nunca usen el mismo folio.
3. Construye el documento con ese folio y ese CAF.
4. Cuando queden pocos folios (por ejemplo, el 20%), solicita un nuevo CAF.

&gt; [!WARNING] El folio debe estar dentro del CAF
&gt;
&gt; Si el folio no está en el rango del CAF, la API responde con un `422`:
&gt; `El folio 500 del documento 88888888-8_T033F000000500 no está disponible en el rango del CAF CAF33D1H100.`

## Practicar con un CAF de prueba

Mientras aprendes, no necesitas un CAF real. La API puede generar un **CAF ficticio** para cualquier emisor:

```bash
curl -X POST https://app.apigateway.cl/api/v2/libredte/billing/identifier/caf_faker/create \
  -H &quot;Authorization: Token $API_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#039;{
    &quot;parameters&quot;: {
        &quot;emisor&quot;: {&quot;rut&quot;: &quot;88888888-8&quot;, &quot;razon_social&quot;: &quot;Mi Empresa SpA&quot;},
        &quot;codigoDocumento&quot;: 33,
        &quot;folioDesde&quot;: 1,
        &quot;folioHasta&quot;: 100
    }
}&#039;
```

La respuesta tiene el mismo formato que `caf_loader/load` y además el XML del CAF en base64 en el campo `xml`. Ese valor es el que usarás como `caf` al construir documentos.

&gt; [!WARNING] Un CAF de prueba nunca va al SII
&gt;
&gt; Con un CAF ficticio puedes construir, timbrar, firmar, validar y generar el PDF, pero el SII **rechazará** cualquier documento timbrado con él. Úsalo solo para aprender y para tus pruebas automáticas.


    

---
Última actualización el 05/11/2026

