| Metadato | Valor |
|---|---|
| Versión del perfil / Profile version | 1.1 |
| Estado / Status | Vigente — la 1.1 se publica con la Fase 06.7 (la 1.0 se publicó con la Fase 05.4) |
| Identificador del perfil / Profile URI | https://docs.docuten.com/earchiving/dip-profile/v1 |
| Versión del formato del manifiesto / Manifest format version | 1.1 (campo dipFormatVersion) |
| Tipo de paquete cubierto / Package type covered | DIP solo-PDF (derivado de un AIP conservado): los documentos de usuario son solo PDF; metadata/ lleva además el sidecar de sello, los informes de integridad y el manifiesto |
| Perfil relacionado / Related profile | docs/governance/mets-profile.md (perfil METS del AIP de origen) |
| Endpoint que lo produce / Producing endpoint | GET /api/v1/aip/{aipId}/dip |
| Fecha / Date | 2026-11-02 (v1.1) · 2026-09-21 (v1.0) |
Este documento es la especificación pública del formato del DIP solo-PDF que produce el servicio Docuten eArchiving. Su destinatario es quien recibe un DIP: un cliente, un auditor, o un tercero al que el cliente le ha redistribuido el paquete. Describe qué contiene el ZIP, qué significa cada campo de su manifiesto, y cómo verificar el paquete sin llamar a la plataforma.
Un DIP (Dissemination Information Package) solo-PDF es un derivado de un AIP conservado: una selección de los documentos PDF del paquete, entregada con la evidencia necesaria para acreditar que esos bytes son los que el archivo custodia.
«Solo-PDF» describe los documentos de usuario, no el paquete completo. Desde la 1.1 el ZIP lleva, bajo
metadata/, además del sidecar de sello y del manifiesto, los informes de integridad (§5.6 y §5.7). Siguen sin entrar en el DIP los ficheros de datos que no son PDF y la maquinaria archivística del AIP (§4.1).
This document is the public format specification of the PDF-only DIP produced by the Docuten eArchiving service. Its audience is whoever receives a DIP — a customer, an auditor, or a third party the customer redistributed the package to. It describes what the ZIP contains, what each manifest field means, and how to verify the package without calling the platform.
METS.xml ni la estructura CSIP. Es una decisión de
producto registrada, no una omisión: el AIP de origen sí es E-ARK CSIP v2.2 y su perfil es
docs/governance/mets-profile.md.Estas dos afirmaciones no se contradicen; parecen contradecirse si se lee solo una.
(a) El contenido del manifiesto es un artefacto de producto. Ninguna norma prescribe qué campos lleva. eIDAS 2.0 (Art. 45i/45j del Reg. (UE) 2024/1183) exige demostrar integridad y autenticidad de origen, y eso lo sostiene la cadena sellada que el manifiesto referencia —no el manifiesto en sí—. Los campos de §5 son los que este producto ha decidido emitir.
(b) El estatus del formato sí está regulado: REQ-11-06 de CEN/TS 18170 recae sobre él. Ese requisito exige que el formato, la sintaxis y la semántica del DIP estén especificados o basados en un estándar disponible públicamente. Este documento publicado es lo que satisface ese requisito, sin convertir el DIP en un E-ARK DIP formal.
(a) The manifest's content is a product artifact: no standard prescribes its fields. eIDAS 2.0 Art. 45i/45j requires demonstrating integrity and origin authenticity, and that is carried by the sealed chain the manifest references. (b) The format's status is regulated: CEN/TS 18170 REQ-11-06 requires the DIP format to be specified or based on a publicly available standard — this published profile is what satisfies it, without turning the DIP into a formal E-ARK DIP.
Cada manifiesto declara contra qué especificación debe leerse, igual que el sidecar de sello
declara su merkleProfile. Un auditor que abra un DIP suelto, sin contexto, llega a este documento
desde el propio artefacto.
| Campo del manifiesto | Valor en v1.1 | Semántica |
|---|---|---|
dipProfile |
https://docs.docuten.com/earchiving/dip-profile/v1 |
Identificador estable de este perfil. PRE-07 publica este documento en esa misma dirección; que la URI resuelva lo confirma DevOps (estado en docs/governance/published-uris.md). Ningún consumidor debe depender de que resuelva para verificar un DIP: la verificación offline (§6) no la necesita. |
dipFormatVersion |
"1.1" |
Versión de este perfil, no de la aplicación que lo emite. Un DIP emitido bajo la 1.0 declara "1.0". |
El identificador es estable por diseño. Viaja dentro de artefactos que terceros redistribuyen y
que no se pueden reescribir una vez entregados: cambiarlo o retirarlo dejaría sin referente todos
los DIP ya emitidos. Un cambio incompatible del formato se publica como un identificador y una
versión nuevos (…/dip-profile/v2, dipFormatVersion: "2.0"), nunca reinterpretando este. La 1.1
es aditiva: añade entradas y un campo, no reinterpreta ninguno, y por eso conserva el mismo
identificador.
La 1.1 es compatible hacia atrás: un receptor que solo conoce la 1.0 puede ignorar el array reports
y las entradas nuevas de metadata/ y procesar el resto exactamente como antes. Ningún campo ni
entrada de 1.0 cambia de significado ni desaparece. Lo que cambia es la redacción de seis
cláusulas, que la 1.0 contradice y que se reescriben aquí de forma explícita:
| Dónde | Redacción en 1.0 | Redacción en 1.1 |
|---|---|---|
dipFormatVersion (§3, §5.1) |
"1.0" |
"1.1" |
verificationNote (§5.1) |
La nota de 1.0 | La misma nota, íntegra, con una frase añadida que remite a metadata/integrity-report.xml como puesta por escrito de lo comprobado en la emisión (no sellada y no vigente) |
| Fila «Estado de integridad» de §5.4 | El DIP no lleva ningún estado de integridad | El manifiesto sigue sin llevarlo; ese estado vive solo en metadata/integrity-report.xml (§5.6), fechado con retrievalMoment, y no es una garantía vigente |
| Garantía de §9 | «mismo AIP → mismo ZIP salvo generatedAt» |
«mismo AIP → mismo ZIP salvo generatedAt del manifiesto y las entradas integrity-report.xml y integrity-report.html con sus referencias del manifiesto»; y la nota de generatedAt en §5.1 deja de decir que es el único campo que depende del reloj de la descarga |
| Precisión de §6 y §7.1 | La plataforma no valida la firma del sidecar al emitir | La plataforma sí valida que la firma del sidecar es íntegra y encadena a un ancla configurada, y no entrega si no es así (§7.1); no comprueba revocación ni cualificación, y eso consta como limitación |
| §8 | Sin DIP_EVIDENCE_SIGNATURE_INVALID |
Código nuevo (§8.1) y su lugar en el orden de guardas (§8.2) |
El DIP es un ZIP con una única carpeta raíz que lleva el identificador del AIP de origen —misma convención que el propio AIP y que la recomendación E-ARK para DIPs («the top-most folder carries the unique name of the DIP»).
dip-{aipId}.zip
└── {aipId}/
├── <documento-1>.pdf ← contenido del usuario, en la raíz
├── <documento-2>.pdf
├── …
└── metadata/
├── aip-hash-seal.xml ← copia byte a byte del sidecar de sello del AIP
├── integrity-report.xml ← informe de la emisión (siempre; NO sellado)
├── integrity-report.html ← su versión legible
├── sealed-integrity-report.xml ← (si existe) copia del último informe sellado
├── sealed-integrity-report-timestamp.tst ← (si existe) su token de sello de tiempo
├── sealed-integrity-report.html ← (si existe) versión legible de la copia
└── manifest.json ← SIEMPRE la ÚLTIMA entrada escrita en el ZIP
| Ruta | Obligatoria | Contenido |
|---|---|---|
{aipId}/ |
MUST | Carpeta raíz. {aipId} es el UUID del AIP de origen. |
{aipId}/*.pdf |
MUST (≥ 1) | Los documentos PDF del paquete. Un AIP sin ningún PDF no produce DIP (§8, AIP_HAS_NO_PDF). |
{aipId}/metadata/aip-hash-seal.xml |
MUST | Copia byte a byte del sidecar de sello del AIP de origen. Es la evidencia que permite la verificación offline (§6). |
{aipId}/metadata/integrity-report.xml |
MUST | Informe de integridad de la emisión (§5.6): se genera en cada descarga y no está sellado. |
{aipId}/metadata/integrity-report.html |
MUST | Versión legible del anterior. No es evidencia (§5.6). |
{aipId}/metadata/sealed-integrity-report.xml |
MAY | Copia byte a byte del XAdES del último informe sellado del AIP, si lo hay y está completo (§5.7). |
{aipId}/metadata/sealed-integrity-report-timestamp.tst |
MAY | Copia byte a byte del token de sello de tiempo RFC 3161 de ese informe. Va siempre que va el anterior. |
{aipId}/metadata/sealed-integrity-report.html |
MAY | Versión legible de la copia sellada. No es evidencia. Va siempre que va la copia. |
{aipId}/metadata/manifest.json |
MUST | El manifiesto (§5). Debe ser la última entrada del ZIP. |
Los informes se escriben después de aip-hash-seal.xml y antes de manifest.json. Todos los
nombres de entrada los fija el servidor: ninguno procede de texto de usuario.
La raíz
{aipId}/contiene únicamente los PDF del usuario. Hay un solo directorio auxiliar (metadata/), no dos, para que el receptor distinga sin ambigüedad el contenido de la maquinaria.
{aipId}/representations/*/data/ del AIP cuyos bytes reales
empiezan por la cabecera %PDF-. La señal es el contenido, no la extensión ni un identificador
de formato de base de datos.El nombre con el que se entrega cada PDF se deriva, en este orden de prioridad:
[A-Za-z0-9-_], y la extensión .pdf re-pegada en minúscula);{sequence}.pdf, donde sequence es el índice persistido e inmutable del fichero
dentro del AIP.Colisión de nombres: si dos documentos producen el mismo nombre entregado, el de sequence menor
conserva el nombre limpio y los demás reciben el sufijo -{sequence} (contrato.pdf,
contrato-7.pdf). Como sequence es persistido e inmutable, el sufijo no depende del orden de
recorrido y es el mismo en todas las descargas del mismo AIP.
El nombre entregado NUNCA es evidencia por sí solo. Es un nombre saneado y potencialmente desambiguado. La evidencia es el manifiesto, que correlaciona ese nombre con la ruta real que el sello certifica (§5,
deliveredFilename↔sourcePath).
POST /api/v1/ingest/fileDesde la fase 06.5, los paquetes ingestados por la ruta /file conservan el nombre real y la extensión
real de cada fichero (regla versionada en docs/governance/filename-policy-v1.md: se conserva el
nombre seguro y se deriva solo lo inseguro), y su premis.xml guarda el nombre declarado en
originalName. En consecuencia, el DIP de /file ya entrega el nombre por la fuente (2) de §4.2
—el basename de la entrada del AIP, saneado—: por ejemplo, Factura Ñ ñ.pdf se entrega como
Factura-N-n.pdf, en lugar de {sequence}.pdf. Este cambio no modifica el DIP: ni dipFormatVersion
ni el esquema del manifiesto cambian.
originalName; el nombre declarado
vive en premis.xml y el nombre entregado sale de la entrada del AIP./file ANTES de la fase 06.5 siguen entregando {sequence}.pdf: el
nombre no se conservó en ninguna parte recuperable y el AIP es WORM, de modo que es irreversible.
Un lote de doce facturas ingestado entonces se descarga como 2.pdf … 13.pdf.sourcePath del manifiesto sigue identificando sin
ambigüedad qué entrada sellada del AIP es cada PDF entregado.POST /api/v1/ingest/sip no están afectados.Ubicación: {aipId}/metadata/manifest.json · Codificación: UTF-8 ·
Serialización: JSON canonicalizado según RFC 8785 (JCS).
{
"aipId": "3f2b1c40-9a7e-4d21-8f55-0c1a2b3d4e5f",
"dipFormatVersion": "1.1",
"dipProfile": "https://docs.docuten.com/earchiving/dip-profile/v1",
"fileEntries": [
{
"deliveredFilename": "contrato.pdf",
"representationId": "rep-1",
"sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"sourcePath": "3f2b1c40-9a7e-4d21-8f55-0c1a2b3d4e5f/representations/rep-1/data/contrato.pdf"
}
],
"generatedAt": "2026-09-21T18:42:07.113Z",
"merkleProfile": "https://docs.docuten.com/earchiving/merkle-profile/v2",
"reports": [
{
"path": "3f2b1c40-9a7e-4d21-8f55-0c1a2b3d4e5f/metadata/integrity-report.xml",
"role": "EMISSION_REPORT_XML",
"sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"
},
{
"path": "3f2b1c40-9a7e-4d21-8f55-0c1a2b3d4e5f/metadata/integrity-report.html",
"role": "EMISSION_REPORT_HTML",
"sha256": "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"
}
],
"sealedMerkleRoot": "b1946ac92492d2347c6235b4d2611184…",
"verificationNote": "Verificar hash SHA-256 de cada PDF contra fileEntries del sidecar adjunto en metadata/aip-hash-seal.xml; ver https://docs.docuten.com/earchiving/dip-profile/v1 para el procedimiento completo y la validación de la firma del sello. El informe de integridad de la emisión (metadata/integrity-report.xml) deja por escrito lo que se comprobó al emitir este DIP: no está sellado y no es una garantía vigente.",
"sipId": "7c4e0a11-2b33-4c55-9def-0123456789ab"
}
Nota sobre el orden de las claves del ejemplo. RFC 8785 ordena las claves de cada objeto por su representación UTF-16; el ejemplo de arriba se muestra ordenado por legibilidad. Los bytes reales que se entregan están canonicalizados, no formateados como aquí.
| Campo | Tipo | Obligatorio | Semántica |
|---|---|---|---|
aipId |
string (UUID) |
MUST | Identificador del AIP de origen. Es la referencia de procedencia: este DIP se extrajo de ese AIP. |
sipId |
string (UUID) | null |
MUST (puede ser null) |
Identificador del SIP del que nació el AIP. null significa «no registrado», nunca «no aplica». |
fileEntries |
array |
MUST | Una entrada por PDF entregado (§5.2). Ordenado por sequence ascendente (§9). |
dipProfile |
string |
MUST | Identificador de este perfil (§3). |
dipFormatVersion |
string |
MUST | Versión de este perfil (§3). "1.1" en este perfil. |
verificationNote |
string |
MUST | Instrucción de verificación legible que viaja dentro del artefacto, con puntero a este documento. Es un resumen: el procedimiento normativo es §6. |
reports |
array |
MUST (puede estar vacío) | Nuevo en 1.1. Una entrada por fichero de informe que viaja en el ZIP (§5.5). Un DIP 1.1 lleva siempre al menos las dos del informe de emisión. |
sealedMerkleRoot |
string (hex) |
MUST | Raíz Merkle del AIP completo tal como la declara el sidecar sellado. Es un puntero de conveniencia, no la evidencia (§5.3). |
merkleProfile |
string | null |
MUST (puede ser null) |
Perfil de construcción del árbol Merkle, copiado del sidecar. null = el sidecar no lo declara (formato antiguo); no se infiere un valor, porque «no lo sé» no es «sé que es v2». |
generatedAt |
string (ISO-8601 UTC) |
MUST | Instante de generación de esta emisión concreta. Junto con el informe de emisión (§5.6), es lo que depende del reloj de la descarga (§9). |
fileEntries| Campo | Tipo | Obligatorio | Semántica |
|---|---|---|---|
deliveredFilename |
string |
MUST | Nombre del fichero tal como viaja en este ZIP, sin el prefijo {aipId}/. |
sourcePath |
string |
MUST | Ruta completa dentro del ZIP del AIP de origen. Es la clave que el sidecar sellado certifica, y por tanto la única con valor probatorio. |
sha256 |
string (hex, 64) |
MUST | SHA-256 del fichero, recomputado desde el contenido real mientras se copiaba a este ZIP, y contrastado contra la hoja sellada antes de entregarlo (§7). |
representationId |
string | null |
MUST (puede ser null) |
Identificador de la representación del AIP a la que pertenece el fichero. Se deriva de sourcePath ({aipId}/representations/{repId}/data/…). null = la ruta no sigue ese layout; es un «no lo sé» explícito, nunca un valor inventado. |
El sidecar sellado (
metadata/aip-hash-seal.xml) es la fuente autoritativa. Los campossealedMerkleRootymerkleProfiledel manifiesto son punteros de conveniencia —ambos se leen del sidecar en la misma pasada, así que no pueden divergir por construcción—. Si un receptor detectara divergencia entre manifiesto y sidecar, manda el sidecar.
| No lleva | Razón |
|---|---|
| Identidad del solicitante | Dato personal en un fichero redistribuible. Minimización RGPD: el acto de diseminación con su autor pertenece al audit log de la plataforma, no al paquete que sale de ella. |
| Estado de integridad del AIP | El manifiesto sigue sin llevar estado de integridad: sería un snapshot mutable que el receptor leería como garantía vigente. Ese estado vive solo en metadata/integrity-report.xml, fechado con retrievalMoment, y no es una garantía vigente: dice qué se comprobó al emitir el DIP (§5.6), nada más. La garantía real es la cadena sellada; el estado vivo se consulta en el catálogo. |
| Veredicto PDF/A de la ingesta | Ver §10: la clave con la que se persistió es ambigua entre representaciones, y un campo que mezclase «veredicto», «no validado» y «no atribuible» confundiría más de lo que informa. La señal no se pierde: se consulta donde vive. |
| Firma o sello propios | Por decisión explícita — ver §7.3. |
tenantId |
Es información de aislamiento interno, no de procedencia. |
reports| Campo | Tipo | Obligatorio | Semántica |
|---|---|---|---|
path |
string |
MUST | Ruta de la entrada desde la raíz del ZIP ({aipId}/metadata/…). Nombre fijo generado por el servidor. |
role |
string |
MUST | Rol del fichero, de un vocabulario cerrado: EMISSION_REPORT_XML, EMISSION_REPORT_HTML, SEALED_REPORT_XML, SEALED_REPORT_TIMESTAMP, SEALED_REPORT_HTML. |
sha256 |
string (hex minúsculas, 64) |
MUST | SHA-256 de exactamente los bytes de esa entrada tal como viaja en el ZIP. |
checkId |
string (UUID canónico) |
MUST en SEALED_REPORT_XML, SEALED_REPORT_TIMESTAMP y SEALED_REPORT_HTML, con el mismo valor en las tres; la clave se omite (no se escribe null) en EMISSION_REPORT_* y en todas las entradas cuando el DIP no lleva copia sellada |
Identificador de la comprobación de integridad de la que se copió el informe sellado. Es un identificador operativo: sirve para correlacionar con el histórico de comprobaciones del detalle del AIP y con soporte. No es evidencia: la referencia con fuerza probatoria es sha256, y el XAdES copiado lleva su propio checkId dentro del documento firmado. |
El checkId de las tres entradas selladas es siempre el mismo: identifica la única comprobación de la
que se copió el informe (§5.7). Un receptor que valide el manifiesto debe tratar la clave checkId como
opcional y no inferir nada de su ausencia salvo «este DIP no lleva copia sellada».
El orden del array es el de escritura: informe de emisión (XML, HTML) y, si hay copia sellada, XAdES, token y HTML. El manifiesto no se sella, pero el hash del manifiesto entregado queda anclado en el audit log (§6.1): los informes quedan así anclados de forma indirecta, sin sello propio.
metadata/integrity-report.xmlQué es. La puesta por escrito de lo que el DIP comprobó al emitirse, generada en cada descarga. No está sellado ni firmado y no se presenta como garantía vigente del AIP: es una afirmación fechada de la plataforma sobre un instante, y su valor probatorio es el de las evidencias que referencia por hash.
Formato. XML UTF-8, espacio de nombres https://docs.docuten.com/earchiving/dip-integrity-report/v1,
raíz dipIntegrityReport. Su versión legible es integrity-report.html, generada desde ese XML.
| Elemento | Semántica |
|---|---|
reportId |
UUID aleatorio (v4) de este informe; distinto en cada descarga. Nunca derivado del contenido. |
retrievalMoment |
Instante de la emisión del DIP. |
packageId |
El AIP del que se extrajo el DIP. |
integrityStatus |
VALID. Un DIP entregado solo puede decir VALID: cualquier divergencia de fixity o firma de sidecar inválida impide la entrega (§7), así que no hay DIP con un estado peor. |
scope |
PDF_FILES_DELIVERED: lo comprobado son los PDF entregados, no el AIP completo. |
sealedRoot |
Raíz Merkle declarada por el sidecar sellado, leída de él. |
evidence |
Una entrada por evidencia referenciada por hash (kind, path, sha256): SEALED_SIDECAR siempre y, si hay copia sellada, SEALED_REPORT_XML y SEALED_REPORT_TIMESTAMP. |
originStatus |
SIDECAR_SIGNATURE_VALID: la firma del sidecar es íntegra y encadena a un ancla configurada (§7.1). |
limitations |
Códigos cerrados de lo que no se comprobó o no se pudo copiar (ver abajo). |
Respalda VALID solo con: la firma del sidecar validada y el SHA-256 de cada PDF entregado
contrastado contra el sidecar (§7.1).
Lo que NO dice. No declara ningún root recomputado ni «AIP íntegro»: no se recorre el AIP completo al emitir un DIP. No lleva identidad del solicitante ni ningún dato del actor que descarga (§5.4).
Limitaciones declaradas (limitations):
| Código | Cuándo aparece | Significado |
|---|---|---|
NON_PDF_FILES_NOT_REVERIFIED |
Siempre | Los ficheros del AIP que no son PDF no se contrastan al emitir. |
REVOCATION_AND_QUALIFICATION_NOT_CHECKED |
Siempre | La validación de la firma del sidecar no comprueba revocación ni cualificación; eso es el paso 3 del receptor (§6). |
NO_SEALED_REPORT |
El AIP no tiene ninguna comprobación de integridad terminal | No hay informe sellado que copiar. |
LATEST_SEALED_REPORT_INCOMPLETE |
La custodia muestra que a la última comprobación terminal le falta el XAdES o el token, o que no hay blobs | No se copia ningún informe sellado (§5.7). |
LATEST_SEALED_REPORT_NOT_ATTACHED |
Falló la lectura o la comprobación de la custodia del informe sellado de la última comprobación terminal en la emisión; se desconoce si hay informe custodiado y cuál es su contenido | No se adjunta la copia sellada (§5.7). No afirma nada sobre la existencia ni el contenido de ese informe. Una nueva descarga puede incluirla si el fallo fue transitorio; si se repite, el suscriptor debe comunicarlo a soporte. |
LATEST_SEALED_REPORT_HTML_NOT_RENDERED |
La copia sellada de la última comprobación terminal se leyó de la custodia, pero no se pudo generar su versión legible (HTML) en la emisión | No se adjunta la copia sellada: una copia sellada viaja siempre con su versión legible y no se entrega a medias (§5.7). No afirma nada sobre el contenido de esa copia. Una nueva descarga puede incluirla si el fallo fue transitorio; si se repite, el suscriptor debe comunicarlo a soporte. |
El HTML no es evidencia. integrity-report.html es una vista de conveniencia generada desde el XML.
Su aviso nombra el fichero XML correspondiente y el SHA-256 de ese XML tal como viaja en el ZIP: el
receptor debe contrastar siempre el XML, no el HTML.
El archivo registra comprobaciones de integridad del AIP y sella el informe de cada una (XAdES más token de sello de tiempo). Si el AIP tiene una, el DIP lleva una copia byte a byte de la última.
Regla de selección — mecánica, nunca por veredicto:
PASS, FAIL, NOT_ANCHORABLE o ERROR. Las que
siguen en curso no cuentan.limitations
(LATEST_SEALED_REPORT_INCOMPLETE). Si la custodia no se pudo leer o comprobar en la emisión (no se
sabe si hay informe), tampoco se copia ninguno y se declara LATEST_SEALED_REPORT_NOT_ATTACHED. Si la
copia se leyó pero no se pudo generar su versión legible, no se entrega a medias y se declara
LATEST_SEALED_REPORT_HTML_NOT_RENDERED. Si el AIP no tiene ninguna comprobación terminal, declara
NO_SEALED_REPORT. Toda ausencia de copia sellada lleva exactamente uno de esos cuatro códigos;
nunca se omite en silencio.La selección no mira el veredicto y no rescata un informe anterior «mejor»: elegir evidencia por lo
que dice sería presentarle al tercero una historia mejor que la real. El SHA-256 de cada entrada copiada
coincide con el del blob custodiado. La comprobación de la que se copió consta como checkId en las tres
entradas SEALED_REPORT_* de reports (§5.5).
Determinismo y reintento (decisión de la fase 06.7, 2026-11-03). La copia sellada es un complemento
del informe de emisión: si la custodia no se pudo leer o comprobar, o la copia no se pudo presentar en su
versión legible, en la emisión, el DIP se entrega igualmente, sin copia y declarándolo con
LATEST_SEALED_REPORT_NOT_ATTACHED o con LATEST_SEALED_REPORT_HTML_NOT_RENDERED; un fallo del
complemento no bloquea la entrega de los PDF. Por tanto dos descargas consecutivas del mismo AIP pueden
llevar conjuntos de evidencia distintos, y solo cuando la primera lo declara: ningún DIP omite la copia
sellada sin declararlo. Volver a descargar el paquete puede incluir la copia si el fallo fue transitorio;
si el mismo código se repite en descargas sucesivas, el suscriptor debe comunicarlo a soporte.
Esta es la parte normativa para el receptor. Se ejecuta sin conexión con la plataforma, con
herramientas estándar (unzip, sha256sum, jq, y un validador de firmas eIDAS).
Calcular el SHA-256 del documento entregado y comprobar que coincide con el campo sha256 de su
entrada en fileEntries.
unzip -o dip-{aipId}.zip -d dip/
sha256sum "dip/{aipId}/contrato.pdf"
jq -r '.fileEntries[] | select(.deliveredFilename=="contrato.pdf") | .sha256' \
"dip/{aipId}/metadata/manifest.json"
Qué prueba: que el fichero que tienes es el que el manifiesto describe. Qué no prueba todavía: nada sobre el archivo — un manifiesto y unos bytes fabricados a la vez serían igual de auto-consistentes. Por eso hay un paso 2.
Comprobar que ese mismo SHA-256 aparece, asociado a la ruta sourcePath correspondiente, en la lista
de hojas de {aipId}/metadata/aip-hash-seal.xml. El sidecar es una copia byte a byte del
documento que el archivo selló; el manifiesto no puede influir en él.
Qué prueba: que el contenido entregado es exactamente el que el archivo selló, identificado por su ruta real dentro del AIP (no por el nombre de entrega).
Validar la firma electrónica del sidecar contra las trust lists de la UE (EUTL / LOTL), con un
validador conforme a eIDAS —por ejemplo DSS de la Comisión Europea—, comprobando además que el
sealedMerkleRoot que el sidecar declara es el que se ha firmado.
Qué prueba: la autenticidad de origen — que quien selló es el prestador cualificado que dice ser, y que el sello no se ha alterado desde entonces.
Abrir metadata/integrity-report.xml (§5.6) para saber qué comprobó la plataforma al emitir, con qué
evidencias y con qué limitaciones; y, si el DIP lleva sealed-integrity-report.xml (§5.7), validar su
firma y su token de sello de tiempo con el mismo tipo de validador del paso 3. Contrastar con sha256sum
cada entrada contra su referencia en el array reports del manifiesto.
# Las rutas de `reports` parten de la raíz del ZIP: se ejecuta desde la carpeta donde se descomprimió.
cd dip/ && jq -r '.reports[] | "\(.sha256) \(.path)"' "{aipId}/metadata/manifest.json" | sha256sum -c -
Qué prueba: que los informes que tienes son los que el manifiesto referencia. Qué no prueba: el
informe de emisión no está sellado y no es una garantía vigente; y los ficheros .html son una vista
de conveniencia, no evidencia.
Precisión importante sobre el reparto de responsabilidades. La plataforma, al emitir el DIP, verifica la fixity de cada documento contra las hojas selladas y valida la firma del sidecar contra las anclas de confianza que tiene configuradas (§7.1), y no entrega el paquete si algo no cuadra. Lo que la plataforma no hace en el momento de la descarga es comprobar la revocación ni la cualificación de esa firma contra las trust lists de la UE: ese es el paso 3, y es del receptor (por eso consta como limitación
REVOCATION_AND_QUALIFICATION_NOT_CHECKED). La independencia es deliberada — una verificación que dependiera de la plataforma no probaría nada ante un tercero.
Hay una comprobación que solo la plataforma puede hacer, y por eso se documenta aquí: confirmar
que un DIP presentado por un tercero fue realmente emitido por el archivo. Cada emisión registra en
su audit log encadenado el SHA-256 de los bytes exactos del manifest.json entregado. Presentado
un DIP, la plataforma recalcula ese hash y lo cruza contra su cadena de auditoría.
Como el manifiesto lleva generatedAt y las huellas del informe de emisión (§5.5), cada descarga
produce un hash distinto: es correcto e intencionado — identifica esa emisión concreta, no «un DIP
de ese AIP». Es también lo que ancla, de forma indirecta, los informes del DIP (§5.5).
Hay dos condiciones de entrega, y las dos se comprueban en cada descarga:
DIP_EVIDENCE_SIGNATURE_INVALID, §8.1), se audita DIP_SIDECAR_SIGNATURE_INVALID y
se encola una verificación de integridad del AIP.Ambas son condición de entrega, no un diagnóstico posterior: cada descarga de un DIP es una verificación de integridad incidental.
Evidencia y configuración no son lo mismo. Un motivo de evidencia (sin firma, firma no íntegra,
cadena sin anclar, sidecar ilegible) acusa de verdad: es DIP_EVIDENCE_SIGNATURE_INVALID. Un fallo de
configuración de la plataforma (anclas no configuradas o no disponibles, error del validador) no
es una acusación de manipulación: responde DIP_ERROR, sin auditar como incidente ni despachar
verificación, porque tratarlo como manipulación negaría el DIP de todo AIP legítimo.
Si el contenido no coincide con la evidencia sellada —o si el sidecar no declara esa ruta en absoluto—, la entrega se aborta, el hecho se registra en el audit log con ambos hashes y se encola una verificación de integridad del AIP.
El archivo no entrega contenido que contradice su propio sello. La alternativa —entregarlo declarando la alteración en el manifiesto— produciría un paquete redistribuible que lleva dentro la afirmación de que su contenido está alterado: evidencia envenenada.
El aborto tiene dos formas, y las dos son detectables por el receptor:
| Momento | Qué recibe el receptor |
|---|---|
| Antes del primer byte | Error HTTP con errorCode (§8). No hay ZIP. |
| A mitad de la transferencia | Un ZIP sin manifest.json y sin directorio central: inválido por definición (§7.4). |
El manifest.json es un índice de procedencia en claro. No lleva firma ni sello propios, por
decisión explícita: sellarlo acoplaría cada descarga a la disponibilidad del prestador de
servicios de confianza. La evidencia sigue siendo el AIP sellado, al que el manifiesto apunta, y el
hash del manifiesto entregado queda anclado en la cadena de auditoría (§6.1).
Tampoco se sella el informe de emisión (integrity-report.xml): se genera en cada descarga y su hash
queda anclado solo de forma indirecta, por el del manifiesto que lo referencia (§5.5). La copia del
último informe sellado (§5.7), en cambio, ya viene sellada de origen (XAdES y token); el DIP la copia
sin tocarla ni volver a sellarla.
manifest.json es un DIP inválido{aipId}/metadata/manifest.json se escribe siempre en último lugar, después de todos los informes.
Su presencia es, por tanto, la señal de que la emisión se completó, informes incluidos.
Un receptor que abra un DIP y no encuentre
metadata/manifest.jsondebe descartarlo por completo. No es un paquete «parcial» ni «sin índice»: es una emisión abortada. No se debe confiar en ninguno de sus ficheros, aunque abran correctamente.
GET /api/v1/aip/{aipId}/dip responde, ante cualquier condición de error, un cuerpo JSON con un
campo errorCode estable —el valor contractual— y un message legible —que no lo es y puede
cambiar sin previo aviso.
{ "errorCode": "AIP_HAS_NO_PDF", "message": "The AIP contains no PDF documents for aipId: …" }
| HTTP | errorCode |
Significado |
|---|---|---|
403 |
DIP_FORBIDDEN |
El actor está autenticado pero su rol no incluye la descarga de DIP. Se comprueba antes que nada: un actor sin permiso no puede ni siquiera sondear si el AIP existe. |
404 |
AIP_NOT_FOUND |
No existe ningún AIP con ese identificador. |
403 |
FORBIDDEN |
El AIP existe pero pertenece a otro tenant. |
409 |
AIP_HAS_NO_PDF |
El AIP existe y es accesible, pero no contiene ningún PDF. No es un error del cliente ni un 404: es el resultado legítimo para toda una clase de paquetes (p. ej. facturación en XML). |
409 |
DIP_EVIDENCE_UNAVAILABLE |
El AIP no tiene sidecar de sello. Sin él, el DIP no puede acreditar autenticidad de origen: no se emite un DIP degradado. No hay régimen de dos clases («DIP verificado» vs «DIP de confianza»). |
409 |
DIP_INDEX_INCOMPLETE |
El AIP está sellado pero su índice de ficheros está ausente o incompleto. Se falla ruidosamente en vez de emitir un DIP calculado sobre un índice parcial. |
500 |
DIP_EVIDENCE_SIGNATURE_INVALID |
La firma del sidecar sellado no es válida (sin firma, no íntegra, cadena sin anclar o ilegible), detectada antes de emitir el primer byte (§7.1). El cuerpo incluye además aipId. Es un hallazgo positivo del archivo, no un fallo de la petición, y es distinto de DIP_ERROR: un fallo de configuración de la comprobación no acusa de manipulación y responde DIP_ERROR. |
500 |
DIP_INTEGRITY_DIVERGENCE |
El contenido del AIP diverge de su evidencia sellada (§7.2), detectado antes de emitir el primer byte. El cuerpo incluye además aipId. Es un hallazgo positivo del archivo, no un fallo de la petición. |
500 |
DIP_ERROR |
Error genérico de emisión. Es el catch-all: un errorCode estable para todo lo que no encaja arriba, para que un cliente nunca reciba un 500 sin código. |
403 |
TENANT_CONTEXT_REQUIRED |
La credencial no lleva contexto de tenant (p. ej. un principal de plataforma sin tenant asignado). |
contexto de tenant → rol → AIP inexistente (404) → AIP de otro tenant (403)
→ sin sidecar (409) → firma del sidecar inválida (500) → sin índice (409) → sin PDF (409)
→ fixity del sondeo (500) → emisión
DIP_EVIDENCE_SIGNATURE_INVALID y DIP_INTEGRITY_DIVERGENCE).Si el fallo ocurre cuando la respuesta 200 ya ha empezado a viajar, el código de estado ya no se
puede cambiar. El contrato en ese caso es el de §7.4: el ZIP llega sin manifest.json y el
receptor debe descartarlo. Esto incluye el caso de que no se pueda armar el informe de la emisión (§5.6):
un DIP 1.1 sin lo que declara no se entrega con manifiesto.
Garantía auditable: mismo AIP → mismo ZIP, byte a byte, salvo el campo
generatedAtdel manifiesto y las entradasintegrity-report.xmlyintegrity-report.htmlcon sus referencias del manifiesto. Dos descargas del mismo AIP producen paquetes confrontables entrada a entrada. Se sostiene porque el AIP de origen es WORM: su contenido y el orden de sus entradas son fijos.
Matiz de la copia sellada. Qué copia sellada lleva el DIP depende de cuál sea la última comprobación
terminal en el momento de la descarga (§5.7): si entre dos descargas se completa una comprobación nueva,
las entradas sealed-integrity-report* y sus referencias del manifiesto cambian. No es una variación del
formato, es el estado del archivo. Lo mismo ocurre si la copia no se pudo leer o presentar en una descarga
y sí en la siguiente: la primera lo declara con LATEST_SEALED_REPORT_NOT_ATTACHED o con
LATEST_SEALED_REPORT_HTML_NOT_RENDERED (§5.7, «Determinismo y reintento»).
Las tres afirmaciones siguientes son normativas y deben leerse juntas, porque cada una acota a las otras:
sequence. El orden físico del AIP y el orden por sequence proceden de dos
criterios distintos —uno sensible a mayúsculas y otro no— y divergen en cuanto dos nombres
mezclan mayúsculas y minúsculas. Coinciden cuando todos comparten caja, que es el caso
mayoritario, pero eso no es una garantía y no debe asumirse.sequence (§4.2), y por tanto son estables y
reproducibles con independencia del orden de recorrido.fileEntries del manifiesto SÍ va ordenado por sequence ascendente. RFC 8785
canonicaliza las claves de los objetos pero preserva el orden de los arrays, de modo que
este orden se impone explícitamente. El auditor conserva la vista ordenada por sequence en el
manifiesto aunque las entradas físicas del ZIP vayan en el orden del AIP.Además:
generatedAt sí cambia en cada emisión; lo mismo el informe de emisión (su retrievalMoment y su
reportId aleatorio) y las huellas de ambos en el manifiesto, y nada más. Es intencionado (§6.1).| Entradas | Método | Razón |
|---|---|---|
Los PDF ({aipId}/*.pdf) |
STORED (sin comprimir) |
Un PDF ya viene comprimido: aplicarle DEFLATE gastaría CPU sobre streams de hasta varios GiB a cambio de ~0 % de ganancia. |
{aipId}/metadata/* |
DEFLATE |
El manifiesto JSON, el sidecar XML y los informes comprimen bien y son pequeños. |
Un receptor no necesita saber esto para abrir el ZIP —cualquier herramienta estándar lo maneja—, pero forma parte del contrato de reproducibilidad: el método de compresión es uno de los bytes que no varían entre dos emisiones del mismo AIP.
El manifiesto del DIP no declara el veredicto PDF/A de ningún documento, por decisión explícita. El veredicto se determinó en la ingesta y se persistió con una clave que es ambigua cuando varias representaciones comparten el nombre base de un fichero; incorporarlo al manifiesto podría atribuir a un PDF el veredicto de otro, es decir, una afirmación falsa dentro de un artefacto de procedencia. Un campo que además mezclara «conforme», «no validado» y «no atribuible por ambigüedad» bajo un mismo valor confundiría más de lo que informa.
La señal no se pierde: se consulta donde vive.
| Dónde | Qué es |
|---|---|
metadata/preservation/premis.xml dentro del AIP |
Los eventos PREMIS de preservación, incluida la validación de formato de la ingesta. Es la fuente archivística, y está cubierta por el sello del AIP. |
GET /api/v1/aip/{aipId}/premis-events |
La misma información, consultable por API para quien tenga acceso al tenant. |
Un PDF con veredicto no conforme o indeterminado se entrega igual en el DIP (§4.1): el archivo entrega lo que custodia. El veredicto informa sobre la conformidad del documento con un estándar de formato; no sobre su integridad ni su autenticidad, que son las que este DIP acredita.
| Versión | Fecha | Cambio |
|---|---|---|
| 1.1 | 2026-11-02 | Fase 06.7. Aditiva: mismo identificador …/dip-profile/v1. El DIP lleva siempre el informe de integridad de la emisión (metadata/integrity-report.xml y .html, no sellado, §5.6) y, si existe, una copia byte a byte del último informe sellado (§5.7); el manifiesto gana el array reports (§5.5, con checkId en las entradas selladas) y dipFormatVersion pasa a "1.1". La plataforma valida la firma del sidecar antes de entregar (§7.1) y gana el código DIP_EVIDENCE_SIGNATURE_INVALID (§8.1, §8.2). Se reescriben de forma explícita la fila «Estado de integridad» de §5.4 y la garantía de §9, y §3.1 enumera qué cambia de redacción respecto a la 1.0. |
| 1.0 | 2026-09-21 | Versión inicial — Fase 05.4 «Descarga DIP Solo-PDF». Publica el formato del DIP solo-PDF: estructura del ZIP, esquema del manifiesto (§5), procedimiento de verificación offline (§6), contrato de errores (§8), contrato de reproducibilidad (§9), limitación de nombres del corpus /file (§4.3) y ubicación de los veredictos PDF/A (§10). Cierra REQ-11-06 de CEN/TS 18170. |