Documentos
Emisión de DTE, lectura, artefactos PDF y XML, enlaces públicos y acciones sobre un documento.
Base: https://api.facturia.cl/v1. Todos los endpoints de este capítulo se autentican con Authorization: Bearer salvo que se diga lo contrario, y el sobre de error es el de Errores.
| Método | Ruta | Qué hace |
|---|---|---|
GET | /documents | Lista los documentos emitidos |
POST | /documents | Emite un DTE |
POST | /documents/previews | Cotiza y valida un documento sin emitirlo |
GET | /documents/previews/{preview_id} | Lee una previsualización guardada |
GET | /documents/{document_id} | Devuelve un documento |
GET | /documents/{document_id}/pdf | Descarga el PDF |
GET | /documents/{document_id}/xml | Descarga el XML firmado, exactamente como se envió al SII |
GET | /documents/{document_id}/events | Eventos del ciclo de vida de un documento |
POST | /documents/{document_id}/retry | Reintenta un documento en failed |
POST | /documents/{document_id}/send | Envía el documento por correo al receptor |
POST | /documents/{document_id}/cesion | Pregúntale al SII si esta factura es cedible |
POST | /documents/{document_id}/cede | Cede esta factura a un factoring, inscribiéndola en el RTC del SII |
POST | /documents/{document_id}/credit_note | Emite una nota de crédito contra este documento |
POST | /documents/{document_id}/public_links | Crea o rota los enlaces públicos de los artefactos de este documento |
DELETE | /documents/{document_id}/public_links | Revoca todos los enlaces públicos de este documento |
GET /documents
Lista los documentos emitidos
Lista los documentos de la empresa, del más nuevo al más antiguo, filtrable por tipo_dte, status y rango de fechas.
curl -sS https://api.facturia.cl/v1/documents \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
limit | query | — | integer | |
cursor | query | — | string | Cursor opaco tomado del next_cursor de una respuesta anterior. |
expand | query | — | string | Separados por coma, aplicados a la página devuelta. En un LISTADO el vocabulario es más angosto que en GET /documents/\{document_id\}: solo events, references y received_document. xml y pdf_base64 incorporan un artefacto completo por fila y aquí son 400 invalid_field — pídelos en el documento individual, o en /pdf y /xml (§5.4). |
status | query | — | queued · sent · accepted · reparo · rejected · failed · annulled | |
tipo_dte | query | — | 33 · 34 · 39 · 41 · 46 · 52 · 56 · 61 | |
folio | query | — | integer | |
receptor_rut | query | — | Rut | |
external_id | query | — | string | |
issue_date[gte] | query | — | string | |
issue_date[lte] | query | — | string | |
created_at[gte] | query | — | string |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
200 | Una lista de documentos. | lista de Document |
400 | Entrada mal formada o incompleta. | ErrorResponse |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
POST /documents
Emite un DTE
Responde 201 con status: queued y folio: null. El folio llega cuando el documento pasa a sent: lo asigna el motor después de que la fila existe, así que ningún 201 puede traerlo. Ese null es una ESPERA, no una falla y no un marcador de posición — obsérvalo con document.sent, o releyendo el documento a la cadencia que te da Facturia-Poll-After.
La ida y vuelta al SII que viene después es una máquina de estados que se mira igual. Todo lo que no mandas se rellena con el perfil de la empresa (bloque emisor, giro, dirección), el registro de receptores y las reglas tributarias del tipo.
curl -sS -X POST https://api.facturia.cl/v1/documents \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"tipo_dte":33,"items":[{"description":"Consultoría","quantity":1,"unit_price":1200000}]}'Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Idempotency-Key | header | — | string | Llave que genera el cliente, única por operación lógica, retenida 24 h y con alcance (cuenta, empresa, endpoint). Un replay devuelve la respuesta original con Facturia-Idempotent-Replay: true. Misma llave y cuerpo distinto → 409. |
Cuerpo
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
preview_id | string | — | Emite una previsualización ya calculada (POST /documents/previews). La solicitud guardada se reproduce por el mismo camino de creación, así que la emisión no difiere en nada de una directa. Solo puedes acompañarla de external_id y metadata — nada que cambie un monto, un receptor o una fecha. Emitir dos veces la misma previsualización devuelve el documento original con 200, no un segundo 201. Ej.: "prev_01K2R9M3D8V5QW7N". |
tipo_dte | 33 · 34 · 39 · 41 · 46 · 52 · 56 · 61 | sí | 33 factura afecta · 34 factura exenta · 39 boleta afecta · 41 boleta exenta · 46 factura de compra · 52 guía de despacho · 56 nota de débito · 61 nota de crédito. Las boletas (39/41) viajan por otro transporte del SII; eso es invisible desde esta API. |
external_id | string | — | Tu propio identificador. Único por empresa; uno duplicado devuelve 409 external_id_exists. |
issue_date | string | — | Por defecto, hoy en America/Santiago. |
prices_include_tax | boolean | — | Por defecto true para 39/41 y false para todo otro tipo. |
receptor | Party | — | A quién se emite el documento. El giro de aquí es el GiroRecep del SII, topado en 40 caracteres — más estrecho que el GiroEmis del propio emisor (80), así que el mismo giro puede ser legal en un lado del documento e ilegal en el otro. legal_name va a 100 y address a 70/20/20. Los valores más largos se rechazan con 400 field_too_long antes de asignar folio, y nunca se truncan: acortar una razón social o un giro cambiaría lo que el documento dice de las partes. address tiene que ser un objeto; un string pelado es 400 invalid_field, porque no hay forma de partirlo en los tres componentes que pide el SII y descartarlo en silencio emitiría un documento sin dirección alguna. Y LA DIRECCIÓN NO ES OPCIONAL en 33, 34, 46, 52, 56 y 61: el SII acepta el SOBRE y después RECHAZA el documento cuyo <Receptor> no lleva GiroRecep/DirRecep/CmnaRecep, con el folio ya gastado. Así que giro, address.street y address.comuna se resuelven desde los documentos anteriores de esta misma empresa al mismo RUT y, si no hay ninguno, se rechazan con 400 receptor_incomplete antes de asignar folio. Tres excepciones: el tipo 52 no necesita giro (su receptor suele ser el propio emisor, cuyo giro pasa de 40 con frecuencia); emission_channel=sfg necesita además address.city, que exige el propio formulario del portal del SII; y 39/41 y un 46 extranjero (foreign: true, o 55555555-5) no necesitan ninguno. |
items | DocumentItem[] | sí | |
global_discounts | object[] | — | El motor emite una sola línea de descuento global — el <DscRcgGlobal> del SII es un solo NroLinDR>1 hard-codeado — así que una segunda entrada se rechaza con 400 invalid_field antes de reservar folio, en vez de descartarse. SOLO EN EL CANAL MERCADO: en emission_channel=sfg se rechaza con 422 global_discount_not_available_for_channel, porque el formulario de emisión del portal del SII no tiene campo de descuento alguno — sus entradas EFXP_PCT_DESC/EFXP_MNT_DESC están comentadas en el formulario capturado, y items[].discount_percent se rechaza ahí por la misma razón. En ese canal, métele el descuento al items[].unit_price. |
references | DocumentReference[] | — | |
dispatch | object | — | Obligatorio para el tipo 52, y sus campos transfer_type / dispatch_type se rechazan en cualquier otro tipo. Los dos canales de emisión emiten guía; lo que cambia es qué campos puede expresar cada uno. destination y dispatch_type se aceptan en emission_channel=mercado (el motor los escribe en el IdDoc/TipoDespacho y en el bloque Transporte del DTE) y se rechazan en emission_channel=sfg con 422 dispatch_not_available_for_channel, porque el formulario de guía del portal del SII no tiene dónde ponerlos: lleva una sola dirección — la del receptor, así que una distinta va en receptor.address — y su único selector de traslado es el de la clase de movimiento, sin ningún campo de TipoDespacho. Los dos canales también se diferencian en los montos: sfg rechaza una guía con cualquier línea a precio 0 o menor, o con total 0, con 422 sfg_guia_zero_amount — el portal valida la guía con las validaciones de la factura, sea cual sea la clase de traslado — mientras que mercado la acepta. |
withholding | object | — | Tipo 46 — tú eres el agente retenedor. |
payment | object | — | |
totals | Totals + any | — | |
pdf | object | — | |
xml | object | — | El artefacto XML comparte el mecanismo de enlace público del PDF en los mismos términos: es el archivo que el sistema contable del receptor realmente ingiere, así que dejarlo tras una llave obligaría a cada integrador a proxear un archivo que ya generamos. |
notes | string | — | |
metadata | object | — | Hasta 20 llaves de ≤500 caracteres cada una. Se guardan y se devuelven intactas; nunca llegan al SII. |
test | object | — | Solo en modo test. Enviarlo con una llave live falla con 400 test_field_in_live_mode. |
| Respuestas |
| Código | Significado | Cuerpo |
|---|---|---|
200 | La previsualización que nombra preview_id YA se emitió, por un intento anterior de esta misma llamada o por una concurrente. Devuelve el documento original, sin cambios: esta llamada no creó nada y no gastó un segundo folio (§10.2). Solo se llega acá con un cuerpo \{"preview_id": "prev_…"\}. | EmittedDocument |
201 | Documento creado y encolado para transmisión. Trae Facturia-Poll-After cuando el documento no es terminal — que en el carril live es siempre el caso del 201, porque responde status: "queued". Hasta el 2026-09-04 lo adjuntaba solo GET /v1/documents/\{document_id\}, así que un agente que seguía «haz poll según Facturia-Poll-After» tenía que hacer una primera lectura solo para descubrir el número con el que le dijeron que hiciera poll (#522). Mismo valor, misma función, las dos puertas. | EmittedDocument |
400 | Entrada mal formada o incompleta. | ErrorResponse |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
402 | subscription_required - este acto real necesita una suscripción activa de la EMPRESA que el request nombra, y esa empresa no la tiene (se aplica de verdad). La suscripción es por empresa: las demás empresas de la misma cuenta no se ven afectadas, y error.details trae empresa, empresa_rut, empresa_name, account_plan, subscription_status, grace_until, blocked_by, un handoff next y un checkout_url que apunta a esa empresa. O bien plan_limit_reached - una cuota de plan agotada (declarado, todavía sin emisor). El modo de prueba nunca se bloquea por ninguno de los dos. LA ELEGIBILIDAD SE EVALÚA PRIMERO (2026-09-04, #475). Este rechazo ahora llega SOLO cuando la empresa por lo demás puede emitir: mientras su checklist está incompleto, su puesta en vivo pendiente o la empresa suspendida, el acto se rechaza con 422 empresa_not_emitting y el handoff del checklist. Así este 402 y Empresa.capabilities.blocked_by ya no pueden nombrar dos acciones siguientes distintas para un mismo estado — que es lo que hacían: el objeto decía «firma el mandato» y la puerta decía «paga». | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
409 | Conflicto de estado: reutilización de idempotencia, external_id duplicado o artefacto no listo. | ErrorResponse |
422 | Bien formado, y rechazado por una regla del dominio. Los códigos que responde esta operación, en el orden en que los revisa la puerta: - empresa_not_emitting — solo en modo real: este endpoint exige onboarding.status = emitting y la empresa todavía no llega. En SANDBOX no se revisa: una empresa de prueba emite desde el primer minuto, que es lo que hace ejercitable toda la superficie antes de que el SII haya emitido nada. error.details es un EmissionRefusalDetails y trae el pending_action —quién tiene que actuar, dónde y con qué palabras—, así que el propio rechazo es el handoff. - empresa_not_active — la empresa está suspended o archived. - tipo_not_available_for_channel — este tipo_dte no se emite por el emission_channel de esta empresa (§6.2). - más las reglas del payload: folios_exhausted, totals_mismatch, receptor_incomplete, reference_required y sus hermanos — ver GET /error_codes. Esta lista nombraba folios_exhausted hasta el 2026-09-04. Ese código no existe ni existió nunca: quedarse sin folios no se rechaza en esta puerta — el rango se consume DESPUÉS de aceptar la petición, así que llega como documento rejected o, en POST /documents/previews, como la advertencia no bloqueante no_folios_available (#496 lo encontró cruzando cada código que estas frases nombran contra el diccionario publicado). | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
POST /documents/previews
Cotiza y valida un documento sin emitirlo
Corre el validador de emisión COMPLETO — los mismos rechazos, con las mismas palabras — y después no emite nada. folio es null porque no se tomó ninguno; folio_preview es el folio que se USARÍA, leído del contador y no reservado.
Se guarda una hora y se lee con GET /documents/previews/\{preview_id\}, que devuelve lo que se calculó en vez de volver a cotizar: que los totales cambien entre que se muestran y que se aprueban es justamente la falla que este flujo existe para evitar.
Para emitirla, manda \{"preview_id": "prev_…"\} a POST /documents. Emitir dos veces la misma previsualización devuelve el documento ORIGINAL con 200 y no gasta un segundo folio — una propiedad garantizada en la base de datos, porque un agente que reintenta una llamada de herramienta es el caso normal aquí y los agentes rara vez mandan Idempotency-Key.
curl -sS -X POST https://api.facturia.cl/v1/documents/previews \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Content-Type: application/json" \
-d '{"tipo_dte":33,"items":[{"description":"Consultoría","quantity":1,"unit_price":1200000}]}'Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Cuerpo
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
preview_id | string | — | Emite una previsualización ya calculada (POST /documents/previews). La solicitud guardada se reproduce por el mismo camino de creación, así que la emisión no difiere en nada de una directa. Solo puedes acompañarla de external_id y metadata — nada que cambie un monto, un receptor o una fecha. Emitir dos veces la misma previsualización devuelve el documento original con 200, no un segundo 201. Ej.: "prev_01K2R9M3D8V5QW7N". |
tipo_dte | 33 · 34 · 39 · 41 · 46 · 52 · 56 · 61 | sí | 33 factura afecta · 34 factura exenta · 39 boleta afecta · 41 boleta exenta · 46 factura de compra · 52 guía de despacho · 56 nota de débito · 61 nota de crédito. Las boletas (39/41) viajan por otro transporte del SII; eso es invisible desde esta API. |
external_id | string | — | Tu propio identificador. Único por empresa; uno duplicado devuelve 409 external_id_exists. |
issue_date | string | — | Por defecto, hoy en America/Santiago. |
prices_include_tax | boolean | — | Por defecto true para 39/41 y false para todo otro tipo. |
receptor | Party | — | A quién se emite el documento. El giro de aquí es el GiroRecep del SII, topado en 40 caracteres — más estrecho que el GiroEmis del propio emisor (80), así que el mismo giro puede ser legal en un lado del documento e ilegal en el otro. legal_name va a 100 y address a 70/20/20. Los valores más largos se rechazan con 400 field_too_long antes de asignar folio, y nunca se truncan: acortar una razón social o un giro cambiaría lo que el documento dice de las partes. address tiene que ser un objeto; un string pelado es 400 invalid_field, porque no hay forma de partirlo en los tres componentes que pide el SII y descartarlo en silencio emitiría un documento sin dirección alguna. Y LA DIRECCIÓN NO ES OPCIONAL en 33, 34, 46, 52, 56 y 61: el SII acepta el SOBRE y después RECHAZA el documento cuyo <Receptor> no lleva GiroRecep/DirRecep/CmnaRecep, con el folio ya gastado. Así que giro, address.street y address.comuna se resuelven desde los documentos anteriores de esta misma empresa al mismo RUT y, si no hay ninguno, se rechazan con 400 receptor_incomplete antes de asignar folio. Tres excepciones: el tipo 52 no necesita giro (su receptor suele ser el propio emisor, cuyo giro pasa de 40 con frecuencia); emission_channel=sfg necesita además address.city, que exige el propio formulario del portal del SII; y 39/41 y un 46 extranjero (foreign: true, o 55555555-5) no necesitan ninguno. |
items | DocumentItem[] | sí | |
global_discounts | object[] | — | El motor emite una sola línea de descuento global — el <DscRcgGlobal> del SII es un solo NroLinDR>1 hard-codeado — así que una segunda entrada se rechaza con 400 invalid_field antes de reservar folio, en vez de descartarse. SOLO EN EL CANAL MERCADO: en emission_channel=sfg se rechaza con 422 global_discount_not_available_for_channel, porque el formulario de emisión del portal del SII no tiene campo de descuento alguno — sus entradas EFXP_PCT_DESC/EFXP_MNT_DESC están comentadas en el formulario capturado, y items[].discount_percent se rechaza ahí por la misma razón. En ese canal, métele el descuento al items[].unit_price. |
references | DocumentReference[] | — | |
dispatch | object | — | Obligatorio para el tipo 52, y sus campos transfer_type / dispatch_type se rechazan en cualquier otro tipo. Los dos canales de emisión emiten guía; lo que cambia es qué campos puede expresar cada uno. destination y dispatch_type se aceptan en emission_channel=mercado (el motor los escribe en el IdDoc/TipoDespacho y en el bloque Transporte del DTE) y se rechazan en emission_channel=sfg con 422 dispatch_not_available_for_channel, porque el formulario de guía del portal del SII no tiene dónde ponerlos: lleva una sola dirección — la del receptor, así que una distinta va en receptor.address — y su único selector de traslado es el de la clase de movimiento, sin ningún campo de TipoDespacho. Los dos canales también se diferencian en los montos: sfg rechaza una guía con cualquier línea a precio 0 o menor, o con total 0, con 422 sfg_guia_zero_amount — el portal valida la guía con las validaciones de la factura, sea cual sea la clase de traslado — mientras que mercado la acepta. |
withholding | object | — | Tipo 46 — tú eres el agente retenedor. |
payment | object | — | |
totals | Totals + any | — | |
pdf | object | — | |
xml | object | — | El artefacto XML comparte el mecanismo de enlace público del PDF en los mismos términos: es el archivo que el sistema contable del receptor realmente ingiere, así que dejarlo tras una llave obligaría a cada integrador a proxear un archivo que ya generamos. |
notes | string | — | |
metadata | object | — | Hasta 20 llaves de ≤500 caracteres cada una. Se guardan y se devuelven intactas; nunca llegan al SII. |
test | object | — | Solo en modo test. Enviarlo con una llave live falla con 400 test_field_in_live_mode. |
| Respuestas |
| Código | Significado | Cuerpo |
|---|---|---|
201 | La previsualización calculada. No se emitió nada ni se reservó folio. | DocumentPreview |
400 | Entrada mal formada o incompleta. | ErrorResponse |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
422 | Bien formado pero viola una regla del dominio: folios agotados, ventana de acuse cerrada. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
GET /documents/previews/{preview_id}
Lee una previsualización guardada
Devuelve lo que se calculó, nunca un recálculo. Una previsualización ya emitida sigue siendo legible con emitted: true y un consumed_at; una sin usar desaparece una hora después de creada y responde 404.
curl -sS https://api.facturia.cl/v1/documents/previews/prev_01K2R9M3D8V5QW7N \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
preview_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
200 | The preview. | DocumentPreview |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
404 | No existe ese objeto bajo esta llave. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
GET /documents/{document_id}
Devuelve un documento
Un documento: su status de ciclo de vida, los totales, public_links si tiene alguno vigente, y rejection_reasons si el SII lo rechazó.
curl -sS https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
expand | query | — | string | Separados por coma. Uno o más de xml, pdf_base64, events, references, received_document. Un valor no reconocido es 400 invalid_field. received_document se puebla cuando este documento se emitió en respuesta al de un proveedor — calzado al emitir por referencia (tipo_dte, folio) más RUT emisor = RUT receptor, dentro de la misma empresa, y solo cuando ese calce es único (§5.4). |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
200 | El documento. | Document |
400 | Entrada mal formada o incompleta. | ErrorResponse |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
404 | No existe ese objeto bajo esta llave. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
GET /documents/{document_id}/pdf
Descarga el PDF
El PDF renderizado del documento (?copy=original o cedible donde la Ley 19.983 da una). 409 artifact_not_ready si el SII aún no acepta el documento — la representación impresa se renderiza al aceptarse, no antes.
curl -sS https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/pdf \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
copy | query | — | original · cedible | Qué copia impresa servir. cedible está disponible para las facturas — tipo_dte 33 y 34 (Ley 19.983 art. 1; Res. Ex. SII N°14/2005 §1°; Manual de Muestras Impresas §1.4). Cualquier otro tipo devuelve 422 cedible_not_available. cedible no existe EN ABSOLUTO en una empresa emission_channel=sfg, en ningún tipo: el SII firma y proxea su propio PDF para ese canal, y sus bytes no llevan recuadro de acuse de recibo ni leyenda CEDIBLE que pueda servir como tal. copy=cedible ahí devuelve 422 cedible_not_available_for_channel; copy=original no se ve afectado. Las dos copias son dos archivos distintos: la original no lleva recuadro de acuse de recibo ni leyenda CEDIBLE, la cedible lleva ambos. both fue retirado en la wave 9 — el manual de muestras permite exactamente una página por archivo (p.12) — y ahora devuelve 400 invalid_field, igual que cualquier otro valor no reconocido. format (carta | 80mm) también fue retirado: no existe layout térmico y nunca se sirvió uno. Enviarlo devuelve 400 invalid_field. Omitirlo no siempre significa original. El valor por defecto se resuelve en este orden: el pdf.cedible propio de este documento (fijado en la emisión, §9.3) si dijo algo; si no, el branding.cedible_by_default de la empresa (§7.6); si no, original — y nunca cedible en el canal SFG, sea cual sea cualquiera de los dos valores por defecto. Envía ?copy= explícitamente para anular cualquiera de los dos en una lectura puntual. |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
200 | El PDF generado. | application/pdf |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
404 | No existe ese objeto bajo esta llave. | ErrorResponse |
409 | Conflicto de estado: reutilización de idempotencia, external_id duplicado o artefacto no listo. | ErrorResponse |
422 | Bien formado pero viola una regla del dominio: folios agotados, ventana de acuse cerrada. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
GET /documents/{document_id}/xml
Descarga el XML firmado, exactamente como se envió al SII
El XML exacto que Facturia envió al SII (o va a enviar), para quien quiere los bytes tal cual en vez del objeto ya interpretado.
curl -sS https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/xml \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
200 | El XML EnvioDTE / EnvioBOLETA firmado (ISO-8859-1). | application/xml |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
404 | No existe ese objeto bajo esta llave. | ErrorResponse |
409 | Conflicto de estado: reutilización de idempotencia, external_id duplicado o artefacto no listo. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
GET /documents/{document_id}/events
Eventos del ciclo de vida de un documento
El historial propio de eventos del documento — cada webhook document.* que Facturia publicó para él, en orden, sin importar si la entrega tuvo éxito.
curl -sS https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/events \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
200 | Los eventos, del más antiguo al más nuevo. | lista de DocumentEvent |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
POST /documents/{document_id}/retry
Reintenta un documento en failed
Reutiliza el folio ya asignado. Nunca crea un segundo documento.
curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/retry \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
200 | El documento, de vuelta en queued. | Document |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
409 | Conflicto de estado: reutilización de idempotencia, external_id duplicado o artefacto no listo. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
POST /documents/{document_id}/send
Envía el documento por correo al receptor
202 cuando ESTA llamada creó el envío; 200 con el MISMO job cuando ya existe uno idéntico (mismo documento, mismas direcciones, mismos adjuntos) — un correo, un id de job, igual que en la §10.2 «emitir dos veces la misma previsualización devuelve el documento original». Los dos estados traen el mismo cuerpo, así que un cliente que solo maneja uno está manejando la mitad del endpoint.
curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/send \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"to":["[email protected]"],"attach":["pdf","xml"]}'Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Idempotency-Key | header | — | string | Llave que genera el cliente, única por operación lógica, retenida 24 h y con alcance (cuenta, empresa, endpoint). Un replay devuelve la respuesta original con Facturia-Idempotent-Replay: true. Misma llave y cuerpo distinto → 409. |
Cuerpo
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
to | string[] | — | |
attach | pdf · xml[] | — | Siempre la copia ORIGINAL del PDF — nunca la cedible, sea cual sea el valor por defecto del documento o de la empresa. §9.6: la copia cedible es un instrumento para ceder la deuda, no la factura que le envías a un cliente para que la pague. Por defecto: ["pdf","xml"]. |
| Respuestas |
| Código | Significado | Cuerpo |
|---|---|---|
200 | Ya existe un envío idéntico. El job ORIGINAL — no hay un segundo correo. | SendJob |
202 | Encolado para envío. | SendJob |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
402 | subscription_required - este acto real necesita una suscripción activa de la EMPRESA que el request nombra, y esa empresa no la tiene (se aplica de verdad). La suscripción es por empresa: las demás empresas de la misma cuenta no se ven afectadas, y error.details trae empresa, empresa_rut, empresa_name, account_plan, subscription_status, grace_until, blocked_by, un handoff next y un checkout_url que apunta a esa empresa. O bien plan_limit_reached - una cuota de plan agotada (declarado, todavía sin emisor). El modo de prueba nunca se bloquea por ninguno de los dos. LA ELEGIBILIDAD SE EVALÚA PRIMERO (2026-09-04, #475). Este rechazo ahora llega SOLO cuando la empresa por lo demás puede emitir: mientras su checklist está incompleto, su puesta en vivo pendiente o la empresa suspendida, el acto se rechaza con 422 empresa_not_emitting y el handoff del checklist. Así este 402 y Empresa.capabilities.blocked_by ya no pueden nombrar dos acciones siguientes distintas para un mismo estado — que es lo que hacían: el objeto decía «firma el mandato» y la puerta decía «paga». | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
409 | Conflicto de estado: reutilización de idempotencia, external_id duplicado o artefacto no listo. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
POST /documents/{document_id}/cesion
Pregúntale al SII si esta factura es cedible
SOLO LECTURA (ticket #47). Encola una consulta al registro del propio SII
(WSREGISTRORECLAMODTE.consultarDocDteCedible) y guarda la respuesta en el objeto
cesion del documento. Acá no se cede nada, no se arma ningún AEC y no se escribe en el
Registro de Cesión de Créditos — esa operación no lleva código de acción y no puede
cambiar el estado en el SII.
Bajo la Ley 19.983 una factura se vuelve cedible cuando el receptor da acuse de recibo, o cuando pasan ocho días corridos sin reclamo; una que el emisor declaró pagada al contado no se vuelve cedible nunca (Circular N°35 de 23.06.2017). Cuál de esas aplica lo sabe solo el SII, así que esto es un reporte, nunca un cálculo nuestro.
202 cuando esta llamada encoló la pregunta, 200 cuando ya hay una idéntica en vuelo.
Consulta GET /documents/\{document_id\} para la respuesta; no hay webhook.
Acepta una llave con documents:read: el integrador que necesita esto es un sistema de
factoring, y no debería tener que cargar con una llave capaz de emitir facturas.
En modo de prueba la respuesta se simula en proceso contra el reloj simulado de la
empresa y no se abre ningún socket al SII — 24 hasta ocho días después de la
aceptación, 25 de ahí en adelante.
curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/cesion \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Idempotency-Key | header | — | string | Llave que genera el cliente, única por operación lógica, retenida 24 h y con alcance (cuenta, empresa, endpoint). Un replay devuelve la respuesta original con Facturia-Idempotent-Replay: true. Misma llave y cuerpo distinto → 409. |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
200 | Ya hay una consulta encolada contra esta misma respuesta (o, en modo de prueba, la respuesta simulada, ya aplicada). El documento, con su cesion actual. | Document |
202 | Encolada. El documento, con cesion mostrando todavía la respuesta conocida antes — todo en null si esta fue la primera consulta. | Document |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
409 | Conflicto de estado: reutilización de idempotencia, external_id duplicado o artefacto no listo. | ErrorResponse |
422 | Bien formado pero viola una regla del dominio: folios agotados, ventana de acuse cerrada. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
POST /documents/{document_id}/cede
Cede esta factura a un factoring, inscribiéndola en el RTC del SII
LA ESCRITURA (ticket #60), a diferencia del POST …/cesion de más arriba (una lectura). Arma un Archivo Electrónico de Cesión — el DTE original firmado por el emisor, más los términos de la transferencia, firmados por el cedente — y lo sube al Registro Electrónico de Transferencia de Crédito del SII. Un acto real e irreversible.
Funciona igual sin importar el canal (ticket #60, resuelto 2026-09-06): el AEC lleva el sobre original firmado tal cual, así que no le importa si el DTE se emitió por emission_channel=sfg o emission_channel=mercado. cesion_channel_unsupported, el código que lanzaba la antigua barrera de canal, está RETIRADO del catálogo.
202 con un job cuando esta llamada encoló un intento NUEVO; 200 con el MISMO job cuando ya hay uno queued/submitted/aec_generated para este documento (un intento en vuelo a la vez). GET /documents/\{document_id\} trae el resultado del intento más nuevo en cesion.status.
UN ACUSE DE RECIBO NO ES UN REGISTRO (ticket #69). Lo más lejos que la subida misma puede llevar un intento es submitted — el SII respondió «Envío recibido OK» y entregó un TrackID. Su validación ocurre después, y un rechazo se avisa por correo al cedente horas más tarde, así que esta API declara confirmed solo cuando la propia consulta del registro, wsRPETCConsulta.getEstEnvio, responde EOK («Envío Aceptado») para ese TrackID. Los webhooks siguen exactamente eso: document.cesion_submitted significa «AEC recibido, anotación pendiente», document.cesion_confirmed es el que sirve para mover plata, y document.cesion_failed cubre un rechazo, una barrera, una respuesta que nadie reconoce y un registro que nunca se pudo confirmar.
409 cesion_attempt_may_have_registered cuando el intento más nuevo de este documento ya había puesto el AEC firmado en el cable al detenerse (ticket #76). Desde aquí no se puede decidir si alcanzó a inscribirse, así que una segunda cesión se rechaza en vez de arriesgar que el mismo crédito quede asignado dos veces. error.details trae la última respuesta que este sistema conoce del registro para ese intento (rtc_estado, rtc_track_id) cuando alguna vez se registró — leerla cuesta una columna, no una nueva llamada al SII; cuando nunca se registró ninguna, los detalles lo dicen así en vez de adivinar.
En modo de prueba esto se resuelve en la misma request (§4.1) — no se abre socket, el intento queda simulated, y se disparan LOS DOS document.cesion_submitted y document.cesion_confirmed, en ese orden, para que el evento sobre el que actúa una integración de factoring sea ejercitable en pruebas.
El envío en vivo sigue bloqueado por el dueño, y desde la resolución 2026-09-06 (R6) también por empresa: el armado del AEC y la subida al registro están construidos y verificados contra el propio esquema del SII — la primera subida en vivo (2026-09-03) fue aceptada por el registro con un TrackID real y luego rechazada en validación por un defecto de firma, ya corregido. Abrirlo exige LAS DOS cosas a la vez: ALLOW_LIVE_CESION_SUBMITS leído desde el propio shell de un operador (nunca de un deploy), Y que la conexión de la empresa cedente haya llegado a onboarding_status=emitting, esté active, en ambiente=palena y no sea una conexión sandbox. Un intento en vivo al que le falte cualquiera de las dos se acepta y se encola como cualquier otro, y termina failed sin reintento, nombrando cuál condición falta.
curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/cede \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"cesionario":{},"ultimo_vencimiento":"…"}'Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Idempotency-Key | header | — | string | Llave que genera el cliente, única por operación lógica, retenida 24 h y con alcance (cuenta, empresa, endpoint). Un replay devuelve la respuesta original con Facturia-Idempotent-Replay: true. Misma llave y cuerpo distinto → 409. |
Cuerpo
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
cesionario | object | sí | |
monto | integer | — | CLP, in [1, total]. Defaults to the document's total. |
ultimo_vencimiento | string | sí | |
otras_condiciones | string | — | |
email_deudor | string | — | |
contacto | object | — | |
| Respuestas |
| Código | Significado | Cuerpo |
|---|---|---|
200 | Ya había un intento de cesión en vuelo para este documento. El mismo job. | CesionJob |
202 | Queued. | CesionJob |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
409 | Conflicto de estado: reutilización de idempotencia, external_id duplicado o artefacto no listo. | ErrorResponse |
422 | Bien formado pero viola una regla del dominio: folios agotados, ventana de acuse cerrada. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
POST /documents/{document_id}/credit_note
Emite una nota de crédito contra este documento
En Chile no existe «borrar una factura». code: 1 anula el documento referenciado,
2 corrige texto y 3 corrige montos (con items para los valores corregidos).
curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/credit_note \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"code":1,"reason":"content"}'Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Idempotency-Key | header | — | string | Llave que genera el cliente, única por operación lógica, retenida 24 h y con alcance (cuenta, empresa, endpoint). Un replay devuelve la respuesta original con Facturia-Idempotent-Replay: true. Misma llave y cuerpo distinto → 409. |
Cuerpo
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
code | 1 · 2 · 3 | sí | |
reason | string | sí | |
items | DocumentItem[] | — | |
| Respuestas |
| Código | Significado | Cuerpo |
|---|---|---|
201 | La nota de crédito (tipo 61). | Document |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
402 | subscription_required - este acto real necesita una suscripción activa de la EMPRESA que el request nombra, y esa empresa no la tiene (se aplica de verdad). La suscripción es por empresa: las demás empresas de la misma cuenta no se ven afectadas, y error.details trae empresa, empresa_rut, empresa_name, account_plan, subscription_status, grace_until, blocked_by, un handoff next y un checkout_url que apunta a esa empresa. O bien plan_limit_reached - una cuota de plan agotada (declarado, todavía sin emisor). El modo de prueba nunca se bloquea por ninguno de los dos. LA ELEGIBILIDAD SE EVALÚA PRIMERO (2026-09-04, #475). Este rechazo ahora llega SOLO cuando la empresa por lo demás puede emitir: mientras su checklist está incompleto, su puesta en vivo pendiente o la empresa suspendida, el acto se rechaza con 422 empresa_not_emitting y el handoff del checklist. Así este 402 y Empresa.capabilities.blocked_by ya no pueden nombrar dos acciones siguientes distintas para un mismo estado — que es lo que hacían: el objeto decía «firma el mandato» y la puerta decía «paga». | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
422 | Bien formado pero viola una regla del dominio: folios agotados, ventana de acuse cerrada. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
POST /documents/{document_id}/public_links
Crea o rota los enlaces públicos de los artefactos de este documento
Activa un link público después del hecho, o rota uno existente (lo que invalida la URL anterior). Un link expone exactamente un artefacto de un documento — nunca los demás documentos de la empresa, nunca datos de la cuenta — y no puede escalarse a una credencial de API.
cedible (ticket #18 wave 10) NO está en el conjunto por defecto: a diferencia de
pdf/xml, no existe para todo documento, así que quien no lo pidió no recibe uno
minteado en silencio — imitando ?copy= en GET …/pdf, que por defecto es original en
vez de adivinar. Pedirlo para un tipo fuera de 33/34 es 422 cedible_not_available; pedirlo
en una empresa emission_channel=sfg, en cualquier tipo, es
422 cedible_not_available_for_channel (#48) — el SII proxea su propio PDF para ese canal
y nunca existe una copia cedible de él, así que esto rechaza el minteo en vez de devolver
un link .cedible que solo podría resolver al archivo no-cedible.
curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/public_links \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"artifacts":["pdf","xml"]}'Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Idempotency-Key | header | — | string | Llave que genera el cliente, única por operación lógica, retenida 24 h y con alcance (cuenta, empresa, endpoint). Un replay devuelve la respuesta original con Facturia-Idempotent-Replay: true. Misma llave y cuerpo distinto → 409. |
Cuerpo
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
artifacts | pdf · xml · cedible[] | sí | Por defecto: ["pdf","xml"]. |
expires_in_days | integer,null | — | Null significa que el enlace no expira. Por defecto: 90. |
expires_in_seconds | integer,null | — | La misma vigencia en segundos, acotada entre 30 s y 365 días. GANA cuando se mandan las dos unidades: los días no pueden expresar el enlace de diez minutos que necesita un agente, y la unidad más corta y específica es la lectura más segura de una solicitud ambigua. |
| Respuestas |
| Código | Significado | Cuerpo |
|---|---|---|
200 | Los enlaces recién creados. NO el documento: la mitad secreta de cada URL se guarda hasheada, así que esta respuesta es el único lugar donde una URL que funciona llega a existir. Guárdala. | PublicLinks |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
409 | Conflicto de estado: reutilización de idempotencia, external_id duplicado o artefacto no listo. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
DELETE /documents/{document_id}/public_links
Revoca todos los enlaces públicos de este documento
Revoca todos los enlaces públicos vigentes acuñados para el documento. Las copias ya guardadas de la URL siguen funcionando hasta vencer; esto solo detiene descargas nuevas.
curl -sS -X DELETE https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/public_links \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parámetros
| Parámetro | En | Requerido | Tipo | Notas |
|---|---|---|---|---|
document_id | path | sí | string | |
Facturia-Empresa | header | — | string | La empresa destino: RUT canónico (77928532-4) o id de empresa (emp_…). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro ?empresa= ni campo empresa en el cuerpo. Omitido donde se requiere → 400 empresa_required; fuera de la lista blanca → 403 empresa_not_allowed. |
Respuestas
| Código | Significado | Cuerpo |
|---|---|---|
204 | Revocados. Las URL existentes dejan de resolver de inmediato. | — |
401 | Llave ausente, mal formada o revocada. | ErrorResponse |
403 | Llave válida pero sin permiso: scope, lista blanca de empresas o modo. | ErrorResponse |
429 | Demasiadas solicitudes. | ErrorResponse |
default | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por error.code, nunca solo por el estado HTTP ni por error.message — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |