Emisión de DTE

Aprende desde cero a emitir facturas, boletas, notas de crédito, guías de despacho y otros documentos tributarios electrónicos desde tu software con API Gateway V2.

Paso 1: Construir el DTE (obligatorio)

Todo empieza con los datos de la venta. Tu sistema los arma en JSON y la operación builder/build los transforma en el XML oficial del documento. Es la misma operación para todos los documentos: facturas, notas, guías y boletas. En una sola llamada la API:

  1. Normaliza los datos: completa campos por defecto, numera las líneas y calcula los totales.
  2. Timbra el documento con la llave del CAF (genera el timbre electrónico, TED).
  3. Firma el XML con tu certificado digital.

Los datos del documento

El JSON sigue la misma estructura y los mismos nombres de campos que el XML oficial del SII. Por eso los nombres están en español abreviado (RznSoc, NmbItem, PrcItem): son los del SII.

{
    "Encabezado": {
        "IdDoc":    { "...": "qué documento es" },
        "Emisor":   { "...": "quién vende" },
        "Receptor": { "...": "quién compra" },
        "Totales":  { "...": "montos: no los envíes, los calcula la API" }
    },
    "Detalle":      [ { "...": "un objeto por producto o servicio" } ],
    "DscRcgGlobal": [ { "...": "descuentos o recargos globales (opcional)" } ],
    "Referencia":   [ { "...": "documentos relacionados (opcional)" } ]
}

No envíes los totales: la API los calcula. Antes de construir, reserva en tu sistema el folio que vas a usar, para que nunca se repita.

El SII define muchos más campos: formas de pago, descuentos, referencias, datos de transporte, impuestos adicionales y otros. La descripción de cada uno, su largo máximo y en qué documentos es obligatorio están en la documentación oficial del SII:

Documentos tributarios electrónicos (no boletas):

Boletas:

Para ver cómo se usan, revisa los ejemplos de la API con la operación examples/get (ver Tu primera llamada) y los casos prácticos.

La solicitud

POST https://app.apigateway.cl/api/v2/libredte/billing/document/builder/build

La llamada es la misma para todos los documentos, incluidas las boletas; cambian los datos del documento (parsedData) y el CAF.

La “bolsa” (bag) agrupa todo lo que se necesita para construir el documento:

Campo Qué es
parsedData Los datos del documento, en JSON (ver Los datos del documento).
caf El XML del CAF en base64. Debe ser del mismo tipo de documento: de facturas para una factura, de boletas para una boleta.
certificate El certificado digital (ver El certificado digital).

La fecha de emisión va en IdDoc.FchEmis (AAAA-MM-DD). Si no la envías, la API usa la fecha del día. Guárdala junto al documento: la necesitarás para corregirlo con una nota de crédito (FchRef) y para verificarlo en el SII. También la encuentras en la respuesta, en data.document.Encabezado.IdDoc.FchEmis.

Estos son los ejemplos de cada caso:

1.1. Facturas, notas y guías

{
    "parameters": {
        "bag": {
            "parsedData": {
                "Encabezado": {
                    "IdDoc": { "TipoDTE": 33, "Folio": 1, "FmaPago": 1 },
                    "Emisor": {
                        "RUTEmisor": "88888888-8",
                        "RznSoc": "Mi Empresa SpA",
                        "GiroEmis": "Venta de software",
                        "Acteco": 620100,
                        "DirOrigen": "Av. Siempre Viva 742",
                        "CmnaOrigen": "Providencia"
                    },
                    "Receptor": {
                        "RUTRecep": "77777777-7",
                        "RznSocRecep": "Cliente Ejemplo Ltda.",
                        "GiroRecep": "Comercio",
                        "DirRecep": "Calle Falsa 123",
                        "CmnaRecep": "Santiago"
                    }
                },
                "Detalle": [
                    { "NmbItem": "Servicio de desarrollo", "QtyItem": 1, "PrcItem": 100000 }
                ]
            },
            "caf": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iSVNPLTg4NTktMSI/Pgo8QVVU...",
            "certificate": {
                "certificate": "-----BEGIN CERTIFICATE-----\nMIIG...\n-----END CERTIFICATE-----",
                "privateKey": "-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----"
            }
        }
    }
}

El precio (PrcItem) va neto. No hay totales: la API calcula neto $100.000, IVA $19.000 y total $119.000.

1.2. Boletas

{
    "parameters": {
        "bag": {
            "parsedData": {
                "Encabezado": {
                    "IdDoc": { "TipoDTE": 39, "Folio": 1 },
                    "Emisor": {
                        "RUTEmisor": "88888888-8",
                        "RznSoc": "Mi Empresa SpA",
                        "GiroEmis": "Venta de artículos de computación",
                        "DirOrigen": "Av. Siempre Viva 742",
                        "CmnaOrigen": "Providencia"
                    },
                    "Receptor": {
                        "RUTRecep": "66666666-6",
                        "RznSocRecep": "Cliente final",
                        "DirRecep": "Santiago",
                        "CmnaRecep": "Santiago"
                    }
                },
                "Detalle": [
                    { "NmbItem": "Mouse inalámbrico", "QtyItem": 2, "PrcItem": 11900 }
                ]
            },
            "caf": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iSVNPLTg4NTktMSI/Pgo8QVVU...",
            "certificate": {
                "certificate": "-----BEGIN CERTIFICATE-----\nMIIG...\n-----END CERTIFICATE-----",
                "privateKey": "-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----"
            }
        }
    }
}

La API calcula un total de $23.800, del que $20.000 es neto y $3.800 es IVA. Lo que cambia respecto de una factura:

Dato En una boleta
TipoDTE 39, o 41 si es una boleta exenta.
PrcItem Con IVA incluido.
Receptor Opcional. Si el cliente no da su RUT, usa 66666666-6.
FmaPago, Acteco, GiroRecep No se usan.
RznSoc, GiroEmis Se envían igual que en una factura. En el XML de la boleta la API los escribe como RznSocEmisor y GiroEmisor, los nombres que usa el SII.
caf Un CAF de boletas (39, o 41 para la exenta).

En una boleta exenta (41), marca cada ítem con IndExe: 1: la API calcula MntExe con el total, sin IVA.

Qué se obtiene según lo que envíes

Envías Obtienes Sirve para
Solo parsedData Un borrador, sin timbre ni firma Previsualizar los totales o el PDF de una cotización
parsedData + caf Un documento timbrado, sin firma (Poco uso práctico)
parsedData + caf + certificate Un documento timbrado y firmado Emitir: es lo que se envía al SII

Para emitir, envía siempre los tres.

La respuesta

Esta es la respuesta para la factura del ejemplo, construida con un CAF del ambiente de certificación. Se muestran los campos que usarás; la tabla de abajo describe todos. Los valores largos (XML en base64, llaves y certificados) están acortados con ...:

{
    "data": {
        "document_id": "88888888-8_T033F000000001",
        "document_xml": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0i...",
        "document": {
            "Encabezado": {
                "IdDoc": {
                    "TipoDTE": 33,
                    "Folio": 1,
                    "FchEmis": "2026-10-29",
                    "TpoTranVenta": 1,
                    "FmaPago": 1
                },
                "Emisor": {
                    "RUTEmisor": "88888888-8",
                    "RznSoc": "Mi Empresa SpA",
                    "GiroEmis": "Venta de software",
                    "Acteco": 620100,
                    "DirOrigen": "Av. Siempre Viva 742",
                    "CmnaOrigen": "Providencia"
                },
                "Receptor": {
                    "RUTRecep": "77777777-7",
                    "RznSocRecep": "Cliente Ejemplo Ltda.",
                    "GiroRecep": "Comercio",
                    "DirRecep": "Calle Falsa 123",
                    "CmnaRecep": "Santiago"
                },
                "Totales": {
                    "MntNeto": 100000,
                    "TasaIVA": 19,
                    "IVA": 19000,
                    "MntTotal": 119000
                }
            },
            "Detalle": [
                {
                    "NroLinDet": 1,
                    "NmbItem": "Servicio de desarrollo",
                    "QtyItem": 1,
                    "PrcItem": 100000,
                    "MontoItem": 100000
                }
            ]
        },
        "document_normalized": {
            "Encabezado": {
                "Totales": {
                    "MntNeto": 100000,
                    "MntExe": null,
                    "TasaIVA": 19,
                    "IVA": 19000,
                    "ImptoReten": null,
                    "CredEC": null,
                    "MntTotal": 119000,
                    "TpoMoneda": null
                }
            },
            "...": "todos los campos del formato"
        },
        "document_type": {
            "codigo": 33,
            "nombre": "Factura electrónica",
            "...": "..."
        },
        "certificate": {
            "id": "11222333-9",
            "name": "Daniel Bot",
            "...": "...",
            "pkey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
        },
        "caf": {
            "id": "CAF33D1H100",
            "...": "...",
            "privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
        },
        "...": "document_parsed, document_stamp, timbre, document_auth, document_extra, emisor, receptor y options"
    }
}
Campo Qué es ¿Guardarlo?
document_xml El XML del DTE timbrado y firmado, en base64. Es el documento con validez tributaria. Sí, siempre
document_id Identificador del documento: emisor, tipo y folio. Sí
document Los datos del documento tal como quedaron en el XML, solo con los campos que tienen valor. Opcional
document_normalized Los mismos datos con todos los campos del formato; los que no se usan vienen en null. Incluye los totales calculados. Opcional
document_parsed Los datos tal como los enviaste en parsedData. No
document_type Datos del tipo de documento: nombre, si es cedible, si es exento, etc. No
document_stamp El timbre electrónico (TED) en XML, en base64. Ya está dentro de document_xml. No
timbre El mismo timbre electrónico, en formato JSON. No
document_auth La resolución del emisor, si la indicaste. No
document_extra Datos adicionales del documento, si los hay. No
emisor, receptor Los datos del emisor y del receptor que usó la API. No
certificate Los datos del certificado usado, incluida su llave privada (pkey). No
caf Los datos del CAF usado, incluida su llave privada (privateKey). No
options Las opciones que usó cada etapa de la construcción. No
Guarda solo lo necesario

La respuesta incluye los datos del certificado y del CAF que se usaron, con sus llaves. No guardes la respuesta completa en tu base de datos ni en tus logs: guarda el document_xml, el document_id y, si los necesitas, los totales.

Decodificado, document_xml se ve así (resumido):

<?xml version="1.0" encoding="ISO-8859-1"?>
<DTE xmlns="http://www.sii.cl/SiiDte" version="1.0">
  <Documento ID="LibreDTE_88888888-8_T033F000000000001">
    <Encabezado>
      <IdDoc><TipoDTE>33</TipoDTE><Folio>1</Folio><FchEmis>2026-10-29</FchEmis></IdDoc>
      <Emisor>...</Emisor>
      <Receptor>...</Receptor>
      <Totales><MntNeto>100000</MntNeto><TasaIVA>19</TasaIVA><IVA>19000</IVA><MntTotal>119000</MntTotal></Totales>
    </Encabezado>
    <Detalle>...</Detalle>
    <TED version="1.0">...</TED>            <!-- timbre electrónico -->
    <TmstFirma>2026-10-29T16:57:50</TmstFirma>
  </Documento>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">...</Signature>  <!-- firma -->
</DTE>

En una boleta, la respuesta tiene los mismos campos. document_type trae el código 39 (“Boleta electrónica”) y el encabezado del XML usa los nombres de las boletas:

<IdDoc><TipoDTE>39</TipoDTE><Folio>1</Folio><FchEmis>2026-11-04</FchEmis><IndServicio>3</IndServicio></IdDoc>
<Emisor><RUTEmisor>88888888-8</RUTEmisor><RznSocEmisor>Mi Empresa SpA</RznSocEmisor><GiroEmisor>...</GiroEmisor>...</Emisor>
<Totales><MntNeto>20000</MntNeto><IVA>3800</IVA><MntTotal>23800</MntTotal></Totales>

IndServicio indica el tipo de venta; si no lo envías, la API pone 3 (venta de bienes y servicios).

El XML no se modifica

Una vez firmado, el XML no se puede tocar: cualquier cambio, aunque sea un espacio, invalida la firma. Guarda el base64 tal como llega, o decodifícalo a bytes sin convertir la codificación (es ISO-8859-1, no UTF-8).

Errores frecuentes en este paso

Mensaje (detail) Causa Solución
El XPath "//Encabezado/IdDoc/Folio" ... es obligatorio: no coincidió con ningún nodo. Falta IdDoc.Folio. Asigna el folio desde tu control de folios.
El folio N del documento ... no está disponible en el rango del CAF ... El folio no está dentro del CAF enviado. Usa un folio del rango, o el CAF que corresponde a ese folio.
El CAF ... fue autorizado al emisor ..., pero el documento ... es del emisor ... El CAF es de otra empresa. Usa un CAF solicitado por la empresa que emite el documento.
El CAF ... es del tipo de documento ..., pero el documento ... es del tipo ... El CAF es de otro tipo de documento, por ejemplo uno de facturas (33) para una boleta (39). Usa el CAF del mismo tipo que el documento.
The verification digit of the RUT ... is incorrect. Un RUT tiene mal el dígito verificador. Valida los RUT en tu sistema antes de emitir.
Falta incluir documento de referencia. Es una nota de crédito o débito sin Referencia. Agrega la referencia al documento que corrige.
No se encontró un deserializador capaz de construir una instancia de ...CafInterface ... requiere datos codificados en base64 válido. El caf no viene en base64 válido. Codifica el XML del CAF en base64, en una línea.
Se requieren los datos del certificado ... El certificado viene incompleto. Envía certificate + privateKey (PEM), o data + password (.p12).
Un CAF por emisor y por tipo de documento

El CAF debe ser del mismo emisor y del mismo tipo de documento: una boleta (39) se timbra con un CAF de boletas, no con uno de facturas. Si no coinciden, la API rechaza la construcción con uno de los dos errores de la tabla.

En esta página

Última actualización el 05/11/2026 por Anonymous