Artefactos
El XML firmado, el CDR, el PDF y el QR. Qué produce cada envío y cómo se descarga.
Un comprobante que recorre el camino completo deja archivos: el XML que se firmó, el ZIP que se mandó, el CDR que volvió, y las representaciones imprimibles. La plataforma los guarda y te los sirve.
Los siete tipos
kind | Qué es | Tipo de contenido |
|---|---|---|
signed-xml | El UBL firmado, tal cual se envió | application/xml |
submission-zip | El ZIP que viajó a SUNAT | application/zip |
cdr-zip | El CDR como SUNAT lo devolvió | application/zip |
cdr-xml | El CDR ya extraído del ZIP | application/xml |
pdf-a4 | Representación impresa en A4 | application/pdf |
pdf-ticket | Representación en formato ticket | application/pdf |
qr-png | El QR del comprobante como imagen | image/png |
Cómo se descargan
GET /api/v2/documents/{id}/artifacts # qué hay disponible
GET /api/v2/documents/{id}/artifacts/{kind} # uno concretoLas dos piden el scope artifacts:read, que no está implicado por documents:read. Es
deliberado: leer el estado de un comprobante y descargar su XML firmado son dos permisos distintos, y
hay integraciones que quieren lo primero sin lo segundo.
El listado te dice qué existe antes de que pidas nada, que es lo que quieres si el PDF puede no estar generado todavía.
Los PDF son versionados
El XML firmado y el CDR son inmutables: son lo que ocurrió. Un PDF no — es una representación, y una plantilla puede cambiar, un logo puede actualizarse, un formato puede corregirse.
POST /api/v2/documents/{id}/pdfs # genera una versión
GET /api/v2/documents/{id}/artifacts/versions/{representationId}/{kind} # recupera una concretaPOST .../pdfs pide el scope documents:pdf y exige Idempotency-Key. Cada generación produce una
versión con su identificador, y las anteriores no se borran.
Por eso existe la ruta con versions/: si imprimiste un comprobante en marzo y la plantilla
cambió en junio, puedes recuperar exactamente el PDF que tu cliente recibió, no una
reconstrucción con la plantilla de hoy.
Lo que garantiza el almacenamiento
Cada artefacto se registra primero en PostgreSQL como PENDING, se escribe en R2 con una escritura
condicional, y solo entonces pasa a READY con su ETag, su hash y su tamaño.
Ese orden importa y no es un detalle de implementación:
- PostgreSQL tiene el estado; R2 tiene los bytes. Que exista un objeto en R2 nunca es, por sí solo, estado de negocio. Un archivo a medio escribir no puede parecer un artefacto válido.
- El hash está guardado. Lo que descargas es verificable contra lo que se registró cuando se produjo, no contra lo que hay ahora en el bucket.
- El bucket es privado. No hay URL pública de un artefacto. Se sirve por una ruta autenticada, que comprueba tu credencial y tu empresa antes de leer un solo byte.
Qué existe en cada momento
| Cuándo | Qué hay |
|---|---|
| Recién creado | Nada todavía: el documento aún no se ha firmado |
| Firmado y enviado | signed-xml, submission-zip |
| Con respuesta de SUNAT | cdr-zip, cdr-xml |
| Tras pedir una representación | pdf-a4 o pdf-ticket, y qr-png |
Un comprobante REJECTED también deja artefactos: se firmó, se envió y volvió un CDR que dice que
no. Ese CDR es exactamente la evidencia que querrás para entender por qué.
No construyas la URL de un artefacto a mano a partir del nombre del archivo. La ruta autenticada es el contrato; la organización interna del bucket no lo es y puede cambiar.