# Artefactos y enlaces públicos (/docs/emision/artefactos)

## Los artefactos autenticados [#los-artefactos-autenticados]

```bash
# PDF — la copia original (tributaria), tamaño carta
curl -L https://api.facturia.cl/v1/documents/doc_01K2R7.../pdf \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" -o factura.pdf

# Copia cedible (facturas: tipo 33 y 34)
curl -L "https://api.facturia.cl/v1/documents/doc_01K2R7.../pdf?copy=cedible" \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" -o factura-cedible.pdf

# XML firmado, exactamente como se envió al SII (ISO-8859-1)
curl -L https://api.facturia.cl/v1/documents/doc_01K2R7.../xml \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" -o dte.xml
```

`copy`: `original` (por defecto) o `cedible`. Cualquier otro valor es `400 invalid_field`. Todos los
PDF son tamaño carta — las reglas de muestras del SII están basadas en carta, no en A4.

Los PDF se renderean cuando el SII acepta el documento; el XML existe desde el momento en que el
documento se firma. Un documento en `queued` todavía no tiene XML → `409 artifact_not_ready`.

**Un documento emitido directamente en el portal del SII nunca tiene XML acá, y nunca lo va a
tener.** Facturia solo captura el XML firmado de los documentos que él mismo hizo avanzar por la
cadena de emisión `emission_channel=sfg`; uno que tu cuenta emitió en el Portal MIPYME antes o al
margen de Facturia — importado a `/v1/documents` por el backfill de historial — nunca estuvo bajo
custodia de Facturia. `GET …/xml` sobre uno de esos responde `409 artifact_not_available`, nunca
`artifact_not_ready`: reintentar no hace nada, porque no viene nada en camino. El error nombra la
única forma de conseguirlo: la descarga manual «Respaldo de DTE y/o IECV» del propio Portal MIPYME,
que exige resolver un reCAPTCHA (en la búsqueda y en la descarga) y tope de 20 documentos por
operación. `GET …/pdf` no se ve afectado: proxea el render del propio SII y responde igual para
cualquiera de los dos orígenes.

**Las dos copias son dos archivos distintos**, generados juntos al aceptarse el documento. La original
no lleva recuadro de acuse de recibo ni leyenda `CEDIBLE`; la cedible lleva ambos. `expand=pdf_base64`
y el correo de §9.7 adjuntan siempre la original: la cedible es un instrumento para ceder el crédito,
no la factura que le mandas a un cliente para que pague.

> **Trampa — Dos parámetros que estaban aquí y ya no están**
>
> **`format` (`carta` | `80mm`) fue retirado.** Ningún handler lo leyó nunca: `?format=80mm` devolvía el
> mismo PDF carta que todo lo demás, así que una integración de POS conectada a él imprimía una hoja
> carta en un rollo térmico sin nada en la respuesta que lo dijera. No existe layout térmico. Lo mismo
> aplica a `pdf: { "format": … }` en la emisión.
>
> **`copy=both` fue retirado.** El Manual de Muestras Impresas del SII permite exactamente una página por
> archivo (p.12), así que las dos copias son dos archivos y una respuesta lleva uno de ellos.
>
> Ambos ahora responden `400 invalid_field` en vez de ignorarse en silencio.

> **Trampa — Documentos rendereados antes del 2026-08-15**
>
> Tienen un solo archivo guardado, y para una factura ese archivo es el cedible — el renderer antiguo
> dibujaba el layout cedible sobre la única copia que hacía. Para esos documentos `copy=cedible` se
> sirve correctamente desde él, y `copy=original` devuelve esos mismos bytes, leyenda incluida, en vez
> de romper una lectura que hoy funciona. Pedir cualquiera de las dos copias encola un re-render, así
> que la segunda llamada obtiene la original verdadera.

La copia cedible es de las **facturas**: tipo 33 y tipo 34. Pedir `copy=cedible` en cualquier otro
tipo devuelve `422 cedible_not_available`.

> **Trampa — La copia cedible no existe en empresas emission_channel=sfg, en ningún tipo**
>
> Para ese canal el SII firma y timbra el documento él mismo — esta API entrega el PDF propio del SII
> (`mipeDisplayPDF.cgi`) en vez de renderear uno, y esos bytes no llevan recuadro de acuse de recibo ni
> leyenda `CEDIBLE` para dibujar encima. Pedir `copy=cedible` ahí devuelve `422
> cedible_not_available_for_channel`, nunca un `original` disfrazado de cedible. `copy=original` (el
> valor por defecto) no cambia: sigue devolviendo la representación impresa del propio SII.

**Cuando no mandas `?copy=`, el valor por defecto no siempre es `original`.** Se resuelve en este
orden, y el primero que dice algo gana:

1. **Un `?copy=` explícito** en esta lectura. Siempre gana.
2. **El valor por defecto de este documento** — `pdf.cedible` en la emisión: `true` hace que ESTE
   documento por defecto entregue la copia cedible; `false` lo fija explícitamente en la original
   aunque la empresa (siguiente punto) diga lo contrario.
3. **`branding.cedible_by_default` de la empresa.** Aplica a todo documento futuro que no fije el
   suyo propio.

Ningún valor por defecto puede inventar una copia que el tipo no tiene, ni una que el canal no
produce — un tipo fuera de 33/34, o cualquier tipo en una empresa `emission_channel=sfg`, siempre
resuelve a `original`, en silencio. Solo un `?copy=cedible` **explícito** en el tipo equivocado es
`422 cedible_not_available`, y solo un `?copy=cedible` **explícito** en el canal SFG es `422
cedible_not_available_for_channel`.

Eso es un hecho legal antes que una decisión de producto. La **Ley 19.983 art. 1** exige la copia en
toda operación "en que el vendedor o prestador del servicio esté sujeto a la obligación de emitir
factura": el gatillo es la factura, sin mencionar IVA ni afecta. La **Res. Ex. SII N°14/2005** la
nombra explícitamente para "facturas de ventas y servicios exentos o no afectos", con la leyenda
`FACTURA EXENTA CUADRUPLICADO COBRO EJECUTIVO`. Y el **Manual de Muestras Impresas §1.4** del propio
SII la *exige* para la Factura No Afecta o Exenta Electrónica.

> **Trampa — Dos límites honestos sobre la copia cedible**
>
> **Somos más angostos que la ley.** Los tipos 46 y 52 también son cedibles y todavía no rendereamos su
> layout cedible. Preferimos una restricción de producto dicha en voz alta antes que una afirmación
> sobre un archivo que no producimos.
>
> **La cedibilidad también depende de la forma de pago.** Una factura *al contado* no es cedible. Este
> parámetro mira solo el tipo de documento, así que te va a entregar una copia cedible para una factura
> al contado cuya copia no tiene uso legal. Afinarlo exige un mapeo de `FmaPago` que no hemos
> verificado, y adivinarlo sería peor que decir esto.

## Enlaces públicos [#enlaces-publicos]

Las URL de arriba necesitan tu llave. Para entregarle un artefacto a alguien que no tiene una — el
receptor, su contador, un hilo de WhatsApp — pide un enlace público al emitir. &#x2A;*Los dos artefactos lo
soportan, en los mismos términos:**

```json
"pdf": { "public": true },
"xml": { "public": true }
```

que agregan un objeto `public_links` **a la respuesta de esa emisión, y solo ahí**:

```json
"public_links": {
  "object": "public_links",
  "pdf_public_url": "https://ver.facturia.cl/d/8f2c1a9e4b?k=SkQ2b1F4c0pYb2s5",
  "xml_public_url": "https://ver.facturia.cl/d/3d9f2b8a1c.xml?k=WmY3aE1uUjBkNVRi"
}
```

La llave **no aparece** cuando la emisión no pidió ningún enlace: ausente, no presente en `null`. Y
vive en la respuesta de la emisión, no en el objeto documento — ninguna lectura, listado, expansión
ni webhook trae una URL pública.

Fíjate en la forma: **cada artefacto tiene su propio slug y su propio secreto**, así que rotar el
enlace del PDF no toca el del XML. Una URL sin su `?k=` no es una versión corta del enlace: es un
enlace distinto que no existe, y responde 404.

> **Trampa — Estas URL se muestran una sola vez**
>
> La mitad secreta se guarda hasheada, igual que una llave de API, así que no podemos reconstruir una
> URL funcional después — la misma propiedad que hace que un volcado de la base de datos no sea un
> volcado de documentos.
>
> Por eso **el objeto documento no tiene ningún campo de enlace público**. Volver a leer el documento
> no te dice nada sobre sus enlaces: ya no tenemos la mitad que los hace funcionar. Los campos
> `pdf_public_url` y `xml_public_url` existieron en el objeto documento hasta el ticket #18 y siempre
> devolvieron una URL sin secreto que respondía 404; los retiramos en vez de guardar el secreto de
> forma recuperable, porque una URL que abre un artefacto sin llave no debería quedar en cada log,
> caché y proxy que toca una lectura.
>
> Captura la URL cuando la recibas, o mintea una nueva con `POST …/public_links`.

El enlace del XML no es un gemelo de conveniencia del PDF: es el artefacto que le importa a quien
tiene que *hacer algo* con el documento. El PDF es para que una persona lea; el XML es lo que ingiere
el sistema contable del receptor y lo que su contador va a pedir cuando el PDF no cuadre.

```bash
# Sin header Authorization — ese es el punto
curl -L https://ver.facturia.cl/d/8f2c1a9e4b.xml -o dte.xml

# Encender un enlace después de emitir, o rotarlo (invalida la URL anterior)
curl -X POST https://api.facturia.cl/v1/documents/doc_01K2R7.../public_links \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"artifacts":["pdf","xml"],"expires_in_days":30}'

# Revocar todo lo compartido de este documento
curl -X DELETE https://api.facturia.cl/v1/documents/doc_01K2R7.../public_links \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA"
```

> **Trampa — Un tercer artefacto: cedible**
>
> `{"artifacts":["cedible"]}` mintea un enlace al archivo cedible de verdad —
> `https://ver.facturia.cl/d/{slug}.cedible?k=…`, `cedible_public_url` en la respuesta — no el enlace
> del `pdf` con otro nombre. Es un artefacto real y separado, así que hereda sus mismas reglas: solo
> existe para facturas (tipo 33/34; `422 cedible_not_available` en cualquier otro tipo), y no está en
> el conjunto por defecto — omitir `artifacts` sigue minteando exactamente `pdf` y `xml`. Pídelo
> explícitamente, cada vez. `pdf: { "public": true }` en la emisión tampoco lo mintea: ese atajo sigue
> siendo solo para la copia original. Tampoco existe en empresas `emission_channel=sfg`, en ningún
> tipo, por la misma razón que `?copy=cedible` no existe ahí (arriba): pedir `artifacts: ["cedible"]`
> devuelve `422 cedible_not_available_for_channel` en vez de un enlace `.cedible` que solo podría
> resolver al archivo no cedible.

### Vencimiento [#vencimiento]

Los enlaces son firmados, inadivinables, con vencimiento (90 días por defecto), con alcance de un
artefacto de un documento, y revocables en cualquier momento. `POST …/public_links` y la respuesta de
la emisión son los dos únicos lugares donde aparece una URL funcional.

| Unidad                    | Dónde                                              | Rango                          |
| ------------------------- | -------------------------------------------------- | ------------------------------ |
| `link_expires_in_days`    | en el objeto `pdf` / `xml` de la emisión           | 1–365, o `null` para no vencer |
| `expires_in_days`         | en `POST /v1/documents/{document_id}/public_links` | 1–365                          |
| `link_expires_in_seconds` | en el objeto `pdf` / `xml` de la emisión           | 30 s – 365 días                |
| `expires_in_seconds`      | en `POST /v1/documents/{document_id}/public_links` | 30 s – 365 días                |

**Los segundos ganan cuando mandas ambas unidades.** Los días son la unidad correcta para un enlace
que le entregas a un receptor y la incorrecta para uno que le entregas a una máquina. Usa segundos
para cualquier cosa que deba estar muerta en minutos — una subida a un formulario del SII, una
descarga de una sola vez en un chat.

La respuesta de `POST …/public_links` devuelve ambas unidades, así que un enlace de diez minutos
nunca se reporta como «0 días»:

```json
{ "expires_in_seconds": 600, "expires_in_days": 0.00694 }
```

El `public_links` de una emisión no devuelve vencimiento: ahí `pdf` y `xml` llevan sus propios
`link_expires_in_*`, así que un solo par de campos sería falso cada vez que difieren.

### Qué expone y qué no [#qué-expone-y-qué-no]

Un enlace público expone exactamente **un artefacto de un documento**. Nunca expone los demás
documentos de la empresa, ni su metadata, ni nada de tu cuenta, y no puede escalarse a una credencial
de API.

`xml_public_url` sirve los bytes firmados exactamente como se enviaron al SII, con
`Content-Type: application/xml; charset=ISO-8859-1` — idénticos byte a byte al endpoint autenticado
`/xml`, porque un documento cuyos bytes cambian según la ruta es un documento cuya firma alguien va a
terminar fallando en verificar.
