Documentos (firma de PDF)¶
Hay tres endpoints de firma. Todos requieren token (Authorization: Bearer <token>) y que el dni indicado tenga un certificado principal cargado (ver Certificados). El archivo enviado en file debe tener Content-Type: application/pdf; cualquier otro tipo responde 400 BAD_REQUEST con "The file must be a PDF".
| Endpoint | Cómo se posiciona la firma | Apariencia | Parámetros de apariencia |
|---|---|---|---|
sign-by-label | Busca un texto (label) en el PDF | Bloque simple: nombre, CQFP, cargo, empresa, motivo, fecha | signatureWidth, signatureHeight, printCqfp, printJobTitle, printCompany, dateFormat, printLabelJobTitle, printLabelCompany, printLabelDate |
sign-by-coord-simple | Coordenadas explícitas (coordX, coordY, page) | La misma apariencia simple que sign-by-label | signatureWidth, signatureHeight, printCqfp, printJobTitle, printCompany, dateFormat, printLabelJobTitle, printLabelCompany, printLabelDate |
sign-by-coord | Coordenadas explícitas (coordX, coordY, page) | Apariencia extendida en tabla (número de documento, ciudad/fecha, imagen opcional) | documentTextNumberSize, signatureTextSpacing, documentTextNumberMultipliedLeading, cityAndDateTextSize, documentNumberTextFirst |
sign-by-coord-simple existe para los casos que necesitan firmar en una posición exacta (sin buscar un texto en el PDF) pero con la apariencia simple de sign-by-label, sin tener que usar los parámetros adicionales de sign-by-coord (pensado para otro caso de uso).
En sign-by-label y sign-by-coord-simple, las líneas CQFP: <matrícula>, cargo y empresa solo se pintan si además de no estar desactivadas (printCqfp, printJobTitle, printCompany, todos true por defecto) el dato correspondiente no está vacío: tuition (ver Autenticación, campo opcional en signup), jobTitle o company del certificado. Si el dato está vacío, la línea se omite automáticamente sin necesidad de pasar el flag en false.
Además, printLabelJobTitle, printLabelCompany y printLabelDate (todos false por defecto) anteponen una etiqueta a esas líneas cuando están en true: "Cargo: ", "Empresa: " y "Fecha y hora: " respectivamente. Con el valor por defecto (false) el texto se pinta igual que antes, sin etiqueta.
Los tres devuelven un SignResponse:
{
"fileBase64Encode": "<PDF firmado, codificado en Base64>",
"status": "SUCCESS",
"message": "Document signed successfully"
}
Ver ejemplos completos, incluyendo cómo decodificar la respuesta, en Casos de uso: firmar un documento por etiqueta, Casos de uso: firmar por coordenadas (apariencia simple) y en Casos de uso: firmar un documento por coordenadas.
POST /api/doc/sign-by-label¶
Busca una etiqueta de texto dentro del PDF (recorriendo todas las páginas) y coloca ahí el bloque de firma.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
file | multipart | Sí | PDF a firmar |
dni | string | Sí | DNI del firmante (dueño del certificado principal a usar) |
label | string | Sí | Texto exacto a buscar en el PDF para posicionar la firma |
reason | string | Sí | Motivo de la firma, se muestra en el sello |
typeSigner | int | Sí | 0 = no aplica, 1 = Suscriptor, 2 = Reemplazo |
hasImageSignature | boolean | Sí | Si true, usa la imagen de firma del usuario (/api/auth/{id}/upload-signature-img); si no hay imagen o es false, usa logo.png |
useTsa | boolean | No | Si true, agrega sello de tiempo (TSA) |
tsaAlias | string | No | Alias de TSA a usar; si se omite y useTsa=true, usa la TSA marcada como isDefault |
signatureWidth | float | No | Ancho del bloque de firma, en puntos (default 180) |
signatureHeight | float | No | Alto del bloque de firma, en puntos (default 100) |
printCqfp | boolean | No | Si false, omite la línea CQFP: <matrícula> del bloque de firma (default true, se pinta) |
printJobTitle | boolean | No | Si false, omite el cargo del firmante (default true, se pinta) |
printCompany | boolean | No | Si false, omite la empresa del firmante (default true, se pinta) |
dateFormat | string | No | Patrón DateTimeFormatter de Java para la fecha del bloque de firma (default yyyy-MM-dd HH:mm:ss, mostrada con sufijo " h"). Si se indica un patrón custom, no se agrega el sufijo " h". Un patrón inválido responde 500 INTERNAL_SERVER_ERROR |
printLabelJobTitle | boolean | No | Si true, antepone "Cargo: " a la línea del cargo (default false) |
printLabelCompany | boolean | No | Si true, antepone "Empresa: " a la línea de la empresa (default false) |
printLabelDate | boolean | No | Si true, antepone "Fecha y hora: " a la línea de la fecha (default false) |
Importante: este endpoint no valida que el
dnidel token coincida con eldnienviado — cualquier usuario autenticado puede firmar en nombre de cualquierdnique tenga certificado principal cargado. Si no se encuentra la etiqueta en el PDF o no existe certificado principal para eldni, la firma falla con500 INTERNAL_SERVER_ERROR.
curl -X POST http://localhost:8080/api/doc/sign-by-label \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
-F "file=@contrato.pdf;type=application/pdf" \
-F "dni=12345678" \
-F "label=FIRMA_AQUI" \
-F "reason=Aprobación de contrato" \
-F "typeSigner=1" \
-F "hasImageSignature=true" \
-F "useTsa=true" \
-F "tsaAlias=tsa-prd" \
-F "signatureWidth=200" \
-F "signatureHeight=110" \
-F "printCqfp=false" \
-F "printJobTitle=false" \
-F "printCompany=false" \
-F "dateFormat=dd/MM/yyyy HH:mm" \
-F "printLabelJobTitle=true" \
-F "printLabelCompany=true" \
-F "printLabelDate=true"
POST /api/doc/sign-by-coord-simple¶
Firma en una posición explícita (x, y, página), igual que sign-by-coord, pero usando la misma apariencia simple de sign-by-label (nombre, CQFP opcional, cargo, empresa, motivo y fecha) en lugar de la apariencia extendida en tabla. Usar este endpoint cuando ya se conoce la posición exacta de la firma y no se necesitan los parámetros adicionales de sign-by-coord (número de documento, ciudad, alineaciones, etc.).
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
file | multipart | Sí | PDF a firmar (application/pdf) |
dni | string | Sí | DNI del firmante (dueño del certificado principal a usar) |
coordX, coordY | string (numérico) | Sí | Coordenadas del bloque de firma en la página |
page | int | Sí | Número de página (1-indexado) |
reason | string | Sí | Motivo de la firma |
typeSigner | int | Sí | 0 = no aplica, 1 = Suscriptor, 2 = Reemplazo |
hasImageSignature | boolean | Sí | Igual que en sign-by-label |
useTsa | boolean | No | Igual que en sign-by-label |
tsaAlias | string | No | Igual que en sign-by-label |
signatureWidth | float | No | Ancho del bloque de firma, en puntos (default 180) |
signatureHeight | float | No | Alto del bloque de firma, en puntos (default 100) |
printCqfp | boolean | No | Si false, omite la línea CQFP: <matrícula> (default true) |
printJobTitle | boolean | No | Si false, omite el cargo del firmante (default true) |
printCompany | boolean | No | Si false, omite la empresa del firmante (default true) |
dateFormat | string | No | Igual que en sign-by-label |
printLabelJobTitle | boolean | No | Igual que en sign-by-label (default false) |
printLabelCompany | boolean | No | Igual que en sign-by-label (default false) |
printLabelDate | boolean | No | Igual que en sign-by-label (default false) |
Al igual que
sign-by-label, este endpoint no valida que eldnidel token coincida con eldnienviado (a diferencia design-by-coord).
curl -X POST http://localhost:8080/api/doc/sign-by-coord-simple \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
-F "file=@contrato.pdf;type=application/pdf" \
-F "dni=12345678" \
-F "coordX=120.5" \
-F "coordY=680.0" \
-F "page=1" \
-F "reason=Aprobación de contrato" \
-F "typeSigner=1" \
-F "hasImageSignature=true" \
-F "useTsa=false"
POST /api/doc/sign-by-coord¶
Firma en una posición explícita (x, y, página), con control fino sobre la apariencia del bloque de texto de la firma.
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
file | multipart | Sí | PDF a firmar (application/pdf) |
dni | string | Sí | DNI del firmante; debe coincidir con el dni del token, si no responde 401 UNAUTHORIZED |
coordX, coordY | string (numérico) | Sí | Coordenadas del bloque de firma en la página |
page | int | Sí | Número de página (1-indexado) |
reason | string | Sí | Motivo de la firma |
documentTextNumber | string | Sí | Texto/código de documento a mostrar junto a la firma |
documentTextNumberAlignment | string | Sí | Alineación del texto anterior |
city | string | No | Ciudad a mostrar junto a la fecha; si se omite, no se pinta ni ciudad ni fecha |
visibleSign | boolean | Sí | Si el bloque de firma es visible en el PDF |
hasImageSignature | boolean | No | Igual que en sign-by-label |
useTsa | boolean | No | Igual que en sign-by-label |
tsaAlias | string | No | Igual que en sign-by-label |
documentTextNumberSize | float | No | Tamaño de fuente del texto de documento (default 10.0) |
signatureTextSpacing | float | No | Espaciado del texto de firma (default 30.0) |
documentTextNumberMultipliedLeading | float | No | Interlineado multiplicado (default 1.1) |
cityAndDateTextSize | float | No | Tamaño de fuente de ciudad/fecha (default 10) |
documentNumberTextFirst | boolean | No | Si el número de documento va antes que otros textos (default true) |
curl -X POST http://localhost:8080/api/doc/sign-by-coord \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
-F "file=@contrato.pdf;type=application/pdf" \
-F "dni=12345678" \
-F "coordX=120.5" \
-F "coordY=680.0" \
-F "page=1" \
-F "reason=Aprobación de contrato" \
-F "documentTextNumber=EXP-2026-001" \
-F "documentTextNumberAlignment=LEFT" \
-F "city=Lima" \
-F "visibleSign=true" \
-F "hasImageSignature=true" \
-F "useTsa=false"
Comportamiento de useTsa / tsaAlias (ambos endpoints)¶
useTsa | tsaAlias | Resultado |
|---|---|---|
false / ausente | (cualquiera) | No se agrega sello de tiempo |
true | vacío/ausente | Usa la TSA activa marcada isDefault = true; si no existe ninguna, 400 BAD_REQUEST (No default TSA configuration found) |
true | <alias> | Usa esa TSA; si el alias no existe o está eliminado, 400 BAD_REQUEST (TSA alias not found: <alias>) |
Códigos de respuesta¶
| Código | Causa |
|---|---|
| 200 OK | Documento firmado correctamente |
| 400 BAD_REQUEST | Falta un campo requerido, archivo no es PDF, o error de negocio (TSA no encontrada, etc.) |
| 401 UNAUTHORIZED | Token inválido/vacío, o (sign-by-coord) el dni del token no coincide con el dni enviado |
| 500 INTERNAL_SERVER_ERROR | Error inesperado (etiqueta no encontrada, sin certificado principal para el dni, error de iText, etc.) |