Saltar a contenido

Caso de uso: firmar un documento individual (PAdES)

Requisito previo: el dni_firmante debe tener un certificado principal cargado (ver Alta de usuario y certificado) y el dni del token debe ser ese mismo dni_firmante.

A diferencia de sign-by-label, este endpoint recibe el PDF en Base64 dentro de un body JSON (no multipart), y permite elegir explícitamente el nivel PAdES.

Preparar el PDF en Base64

PDF_BASE64=$(base64 -w0 contrato.pdf)

Request: firma con imagen + texto, con sello de tiempo (PAdES-BT)

curl -X POST http://localhost:8080/api/firma/individual \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "dni_firmante": "12345678",
    "nombre": "contrato.pdf",
    "base64": "'"$PDF_BASE64"'",
    "nivel_firma": "PAdES-BT",
    "firma_visual": {
      "type": "TEXTO",
      "ubicacion_x": "40",
      "ubicacion_y": "60",
      "largo": "260",
      "alto": "70",
      "pagina": "-1",
      "motivo": "Aprobación de contrato",
      "ciudad": "Lima",
      "formato_fecha": "dd/MM/yyyy HH:mm",
      "texto": "Firmado digitalmente por: [FIRMANTE]&Empresa: [ORG]&DNI: [DNI]&[MOTIVO]&[FECHA] - [CIUDAD]"
    }
  }' \
  -o respuesta.json

pagina: "-1" coloca la firma en la última página sin tener que saber de antemano cuántas tiene el PDF.

Response (200 OK)

{
  "success": true,
  "mensaje": "Documento firmado",
  "base64": "JVBERi0xLjcNCiXi48/TDQoxIDAgb2Jq..."
}

Extraer el PDF firmado

jq -r '.base64' respuesta.json | base64 -d > contrato-firmado.pdf

Errores frecuentes

Situación Respuesta
dni_firmante no coincide con el dni del token 401 UNAUTHORIZED
nivel_firma no es PAdES-B/PAdES-BT/PAdES-LTA 400 BAD_REQUEST
El dni_firmante no tiene certificado principal, no está vigente, o está revocado 422 UNPROCESSABLE_ENTITY
nombre contiene / o \ 400 BAD_REQUEST
firma_visual.pagina mayor al número de páginas del PDF 400 BAD_REQUEST
nivel_firma requiere TSA y no hay ninguna marcada isDefault en /api/tsa 400 BAD_REQUEST — "No default TSA configuration found"

Variante: solo imagen, sin texto

IMG_BASE64=$(base64 -w0 sello.png)

curl -X POST http://localhost:8080/api/firma/individual \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "dni_firmante": "12345678",
    "nombre": "contrato.pdf",
    "base64": "'"$PDF_BASE64"'",
    "nivel_firma": "PAdES-B",
    "firma_visual": {
      "type": "IMAGEN",
      "img_base64": "'"$IMG_BASE64"'",
      "ubicacion_x": "400",
      "ubicacion_y": "50",
      "largo": "120",
      "alto": "60",
      "pagina": "1"
    }
  }'

Variante: firma invisible

Se puede omitir firma_visual por completo, o enviarlo con "type": "INVISIBLE" (equivalente):

curl -X POST http://localhost:8080/api/firma/individual \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "dni_firmante": "12345678",
    "nombre": "contrato.pdf",
    "base64": "'"$PDF_BASE64"'",
    "nivel_firma": "PAdES-LTA"
  }'

Variante: sello visible en todas las páginas

curl -X POST http://localhost:8080/api/firma/individual \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "dni_firmante": "12345678",
    "nombre": "contrato.pdf",
    "base64": "'"$PDF_BASE64"'",
    "nivel_firma": "PAdES-BT",
    "firma_visual": {
      "type": "TEXTO",
      "ubicacion_x": "20",
      "ubicacion_y": "20",
      "largo": "200",
      "alto": "40",
      "pagina": "0",
      "motivo": "Revisado",
      "texto": "[FIRMANTE]&[FECHA]"
    }
  }'

Con pagina: "0" el sello se dibuja en cada página del documento; la firma criptográfica real sigue siendo una sola, anclada en la última página. Si el PDF mezcla páginas verticales y horizontales, el tamaño/posición del sello se ajusta automáticamente en cada página para no salirse del borde (ver ajuste automático).