SDK Python (libredte_lib_sdk) que orquesta la API de LibreDTE Lib
(https://core.libredte.cl/api por defecto) para cubrir el ciclo
básico de emisión de un DTE: borrador, documento timbrado y firmado,
envío al SII, consulta de estado por Track ID, y generación de HTML/PDF
— más carga y validación de CAF real, y generación de CAF y certificado
ficticios para poder probar todo lo anterior sin credenciales reales.
Pensado como base de una app de facturación (ej. Django): este SDK concentra la lógica de negocio/orquestación de DTE, para que la app web sea solo vista, autenticación y persistencia.
El paquete Python espeja la organización de la propia API
(paquete.componente.worker::operacion): sdk.billing.<componente>
.<worker>.
pip install libredte-lib-sdkfrom libredte_lib_sdk import Emisor, AutorizacionDte, LibreDTE
sdk = LibreDTE() # base_url y api_token también vía env vars, ver abajo
b = sdk.billing
parsed_data = {
'Encabezado': {
'IdDoc': {'TipoDTE': 33, 'Folio': 1},
'Emisor': {
'RUTEmisor': '76192083-9',
'RznSoc': 'SASCO SpA',
'GiroEmis': 'Servicios',
'DirOrigen': 'Santiago',
'CmnaOrigen': 'Santiago',
},
'Receptor': {
'RUTRecep': '12345678-5',
'RznSocRecep': 'Cliente de prueba',
'GiroRecep': 'Giro',
'DirRecep': 'Santiago',
'CmnaRecep': 'Santiago',
},
},
'Detalle': [{'NmbItem': 'Producto A', 'QtyItem': 1, 'PrcItem': 1000}],
}
# CAF y certificado ficticios, para pruebas/desarrollo:
caf = b.identifier.caf_faker.create(
{'rut': '76192083-9', 'razon_social': 'SASCO SpA'},
codigo_documento=33, folio_desde=1, folio_hasta=100,
)
certificate = b.trading_parties.mandatario_manager.create_fake_certificate(
{'run': '76192083-9', 'nombre': 'SASCO SpA'},
)
# En producción: cargar y validar el CAF real que el SII le entregó
# al emisor, en vez del CAF ficticio de arriba.
# caf = b.identifier.caf_loader.load(xml_base64_del_caf_subido)
# b.identifier.caf_validator.validate(caf.xml_base64)
# 1. Borrador.
borrador = b.document.builder.build_draft(parsed_data)
# 2. Documento real, timbrado y firmado.
documento = b.document.builder.build_signed(
parsed_data, caf_xml=caf.xml_base64, certificate=certificate,
)
# 3. Envío al SII (arma el sobre EnvioDTE y luego lo envía).
emisor = Emisor(
rut='76192083-9',
razon_social='SASCO SpA',
autorizacion_dte=AutorizacionDte(
fecha_resolucion='2014-08-22', numero_resolucion=80,
),
)
sobre = b.document.dispatcher.create(
documento.xml_base64, certificate=certificate, emisor=emisor,
)
envio = b.integration.sii_dte.send(
sobre.xml_base64, certificate=certificate, company_rut='76192083-9',
)
# 4. Estado del envío, por Track ID.
estado = b.integration.sii_dte.check_status(
envio.track_id, certificate=certificate, company_rut='76192083-9',
)
# 5. HTML o PDF — misma forma de respuesta para ambos.
html = b.document.renderer.render(documento.xml_base64, format='html')
pdf = b.document.renderer.render(documento.xml_base64, format='pdf')
pdf_bytes = pdf.first.content_bytes
# Varias copias/presentaciones en una sola llamada (ej. cedible +
# tributaria):
copias = b.document.renderer.render(
documento.xml_base64,
format='pdf',
renderings={'tributaria': 1, 'cedible': 1},
)
cedible_bytes = copias.by_label('cedible')[0].content_bytesCada componente (document, identifier, trading_parties,
integration) agrupa servicios independientes, uno por worker de la
API: cada método hace exactamente una llamada HTTP, sin encadenar red por
detrás. Encadenar los pasos (ej. armar el documento, el sobre, y
enviarlo) es responsabilidad de quien use el SDK.
Por defecto el SDK apunta a https://core.libredte.cl/api. Para usar
otra API (ej. https://pro.libredte.cl/api, o un ambiente propio),
pasar base_url al construir LibreDTE o setear la variable de
entorno LIBREDTE_LIB_SDK_BASE_URL:
sdk = LibreDTE(base_url='https://pro.libredte.cl/api')export LIBREDTE_LIB_SDK_BASE_URL=https://pro.libredte.cl/apicore.libredte.cl y pro.libredte.cl exponen el mismo contrato con
límites de solicitudes distintos; ambos aceptan la variante LibreDTE
(base_url=..., ...) con el resto de los parámetros de configuración
(api_token, timeout, http_client).
LibreDTE(api_token=...) o la variable de entorno
LIBREDTE_LIB_SDK_TOKEN — si está presente, se manda como header
Authorization: Bearer <token>.
render() devuelve un RenderResult con .renderings (una lista
de Rendering, cada uno con .content_bytes/.mime_type/
.filename/.label/.copies/.copy_number). Sin el argumento
renderings, trae un único elemento ('tributaria'), accesible con
.first. Pasando renderings={'tributaria': 1, 'cedible': 1} (o
más de una copia de una misma presentación, ej. {'tributaria': 2})
trae uno por cada copia generada — usar .by_label('cedible') para
filtrar. Una presentación no soportada por el tipo de documento (ej.
'cedible' en una boleta) se omite en silencio si se pidió junto con
otra que sí se pudo generar; si ninguna se pudo generar, o si se pide
una presentación que no existe, la API responde con un
LibreDteApiError claro. Sirve igual para format='html' y
format='pdf'.
Cualquier error de la API (validación, regla de negocio, error interno)
levanta libredte_lib_sdk.LibreDteApiError, con .status_code,
.detail y .php_class (la clase real de la excepción PHP detrás,
si la API la informó — ej. DocumentException, o una excepción de
autenticación del SII). Un 429 de la API levanta
LibreDteRateLimitError (subclase de lo anterior), con
.retry_after/.limit/.remaining. Un problema de red levanta
libredte_lib_sdk.LibreDteConnectionError.
make install-dev
make check # ruff + tests unitarios (offline, sin red)
make test-live # tests de integración reales contra la APILos tests unitarios no hacen red real: mockean la API con respx. Los
de tests/integration/ sí (marker live), y están excluidos por
defecto de pytest/make test/make check.
Este proyecto es software libre y puede ser redistribuido y/o modificado bajo los términos de la Licencia Pública General Affero de GNU (AGPL), versión 3 o (a elección) cualquier versión posterior. Ver COPYING.