Dazr Sign API: documentación para desarrolladores
Prepara y envía documentos para firmar desde tu propio software, en nombre de las personas que lo usan. Quienes firman lo hacen como siempre con Dazr Sign: con sesión iniciada en Dazr Identity, en su turno y una sola vez.
- Inicio rápido
- Etiquetas de texto
- Ventanas emergentes
- Firmas cualificadas
- Webhooks
- Referencia
- Errores y límites
- Transferencias
Inicio rápido
- Activa la Dazr Sign API. En el portal de Sign, abre Desarrolladores y elige Activar Dazr Sign API para tu app. Cada app de tu organización aparece allí y en la consola de Dazr Identity, con el mismo ID de cliente y el mismo secreto; cada API se activa por separado. Allí también puedes registrar una app nueva.
- Pide el scope
sign. Lleva a las personas por el flujo habitual de Iniciar sesión con Dazr Identity conscope=openid sign(añadeoffline_accesspara un token de actualización). La pantalla de consentimiento indica que tu app puede preparar y enviar documentos para firmar en su nombre y ver su estado. Basta con la Dazr Sign API; para pedir también datos de las personas (profile,emaily los demás) hace falta activar también la Dazr Identity API. - Llama a la API con el token de acceso. La dirección base es
https://sign.dazr.eu/api/sign/v1. EnvíaAuthorization: Bearer <access token>y JSON. - Crea y envía un documento. Sube un PDF con etiquetas de texto y una lista de destinatarios y envíalo, o abre la ventana de preparación para que la persona coloque los campos.
// Node 18+: create a document from a PDF with text tags, then send it
import fs from 'node:fs';
const api = 'https://sign.dazr.eu/api/sign/v1';
const headers = { Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json' };
let res = await fetch(api + '/documents', {
method: 'POST',
headers: { ...headers, 'Idempotency-Key': 'order-1042' },
body: JSON.stringify({
title: 'Service agreement',
file: fs.readFileSync('agreement.pdf').toString('base64'),
recipients: [
{ name: 'Alex Example', email: 'alex@example.eu' },
{ name: 'Sam Client', email: 'sam@client.example' },
],
}),
});
const { document } = await res.json();
res = await fetch(api + '/documents/' + document.id + '/send', { method: 'POST', headers });
console.log((await res.json()).document.status); // "sent"
Etiquetas de texto
Escribe los campos en el PDF como texto. Cada etiqueta se sustituye por un campo del mismo tamaño o mayor, y el texto de la etiqueta se cubre, así quienes firman nunca lo ven.
| Etiqueta | Campo |
|---|---|
{{signature:1}} | Firma del primer destinatario |
{{initials:2}} | Iniciales del segundo destinatario |
{{name:1}} {{date:1}} | Nombre y fecha de la firma, rellenados por Dazr Sign |
{{text:2:Company}} | Un campo de texto con la etiqueta Company |
{{checkbox:2:Terms:optional}} | Una casilla opcional |
{{company:1}} | Nombre de la empresa (se rellena cuando la persona firma en nombre de una organización) |
El número es la posición del destinatario en recipients, empezando por 1. Una etiqueta para un destinatario que no indicaste añade un destinatario vacío, que se completa en la ventana de preparación. Envía "text_tags": false para ignorar las etiquetas. También puedes enviar fields con posiciones en puntos (1/72 de pulgada) desde la esquina superior izquierda de la página: { "recipient": 1, "type": "signature", "page": 1, "x": 72, "y": 600, "width": 180, "height": 48 }. Un value en un campo de texto, empresa o casilla lo fija: quien firma lo ve y no puede cambiarlo.
Ventanas: preparar y firmar
Crea un borrador con "prepare": { "origin": "https://app.example.eu" } y obtendrás una prepare_url. Ábrela en una ventana emergente: la persona coloca destinatarios y campos en un editor compacto y luego pulsa Enviar o Guardar como plantilla. Para quien firma y está en su turno, POST /documents/{id}/recipients/{recipient_id}/signing_url devuelve una ventana de firma. Ambos enlaces valen de 10 a 15 minutos y funcionan una sola vez. Si hace falta, la persona inicia sesión en Dazr Identity dentro de la ventana, con la dirección a la que se envió el documento.
Al terminar, la ventana envía { type: 'dazr-sign', event, document_id, template_id, recipient_id, state } con postMessage a la página que la abrió, solo si esa página está en uno de los orígenes de ventana de tu app (por defecto, los orígenes de tus URI de redirección), y se cierra. event es sent, saved, cancelled, signed o declined. Con redirect_uri (una de tus URI de redirección registradas) y state, una ventana que ha perdido su página de origen vuelve allí con los mismos valores como parámetros de consulta.
<script src="https://sign.dazr.eu/sdk.js"></script>
<script>
document.querySelector('#sign').addEventListener('click', async () => {
// Ask your server for the URL after the click: the popup opens at once.
const url = fetch('/my-server/prepare-url').then(r => r.json()).then(j => j.prepare_url);
const result = await DazrSign.open(url);
if (result.event === 'sent') showSent(result.document_id);
// 'closed': the window was closed; check the status with the API or a webhook
});
</script>
Si tu página envía Cross-Origin-Opener-Policy: same-origin, usa same-origin-allow-popups en su lugar o la ventana no podrá devolver el resultado.
Firmas cualificadas
Cada firmante tiene un level: "advanced" (por defecto: la dirección de correo se confirma al iniciar sesión con Dazr Identity) o "qualified". Quien firma con firma cualificada descarga el PDF en Dazr Sign, lo firma con su propia firma electrónica cualificada (un DNI electrónico, una app de firma como itsme, un certificado cualificado en Adobe Acrobat Reader) y sube el archivo firmado. Dazr Sign lo comprueba con las listas de confianza de la UE y solo lo acepta si es una firma cualificada exactamente sobre el archivo entregado. Dazr no emite firmas cualificadas.
Define el nivel por destinatario: { "name": "Mario Rossi", "email": "mario@example.eu", "level": "qualified" }. Quien firma con firma cualificada no tiene campos de iniciales. name_rule en el documento indica qué ocurre si el nombre del certificado no coincide con el del destinatario: "warn" (por defecto: se acepta, con name_matches en false) o "block" (se rechaza). Las plantillas guardan el nivel de cada rol, y from_template puede subir un rol a "qualified".
Todas las firmas siguen siendo válidas: las firmas posteriores y el sello final de Dazr se añaden como actualizaciones incrementales, y el registro de auditoría de estos documentos es un PDF sellado aparte en GET /documents/{id}/audit.pdf. Los destinatarios en documentos y webhooks tienen level y, tras la firma cualificada, certificate: subject (common_name, given_name, surname, serial_number, country, organization, organization_identifier), issuer, serial, sha256, trust_service_provider, trusted_list_country, signing_time, trusted_timestamp, format (PAdES o CAdES) y name_matches. Cualquier otro level devuelve 400 invalid_level.
Webhooks
Configura una URL de webhook para tu app en el portal de Sign, en Desarrolladores. Verás su secreto de firma una sola vez. Dazr Sign envía sign.document.sent, viewed, signed, completed, declined, voided y expired para los documentos que creó tu app, con el estado del documento y de sus destinatarios, nunca su contenido. Los envíos fallidos se reintentan tras 5 minutos, 30 minutos, 2, 6, 12 y 24 horas; el registro de envíos muestra cada intento y permite reenviar uno.
// Node: check the Dazr-Signature header (t=<unix time>,v1=<HMAC-SHA256 hex>)
import crypto from 'node:crypto';
export function verify(rawBody, header, secret) {
const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header || '');
if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
const want = crypto.createHmac('sha256', secret).update(m[1] + '.' + rawBody).digest();
return crypto.timingSafeEqual(want, Buffer.from(m[2], 'hex'));
}
// The body: { id, type: 'sign.document.completed', created, data: { document: { id, status, recipients: [...] } } }
Referencia
Todas las rutas empiezan por https://sign.dazr.eu/api/sign/v1. Las horas están en ISO 8601, en UTC.
| Solicitud | Qué hace |
|---|---|
POST /documents | Crea un borrador a partir de un PDF: file en base64, una subida multipart (file más data como JSON) o un upload_id. Opcional: title, message, recipients, fields, signing_order, deadline_days, reminder_days, send, prepare. |
POST /documents/from_template | Crea un borrador a partir de una plantilla: template_id, recipients como { role, name, email }, values por ID o etiqueta del campo. |
GET /documents | Lista los documentos de tu app para esta persona, del más reciente al más antiguo: limit (hasta 100), cursor, status. |
GET /documents/{id} | El documento con su estado, destinatarios y campos. |
POST /documents/{id}/send | Envía un borrador. |
POST /documents/{id}/remind | Recuerda a quienes deben firmar en su turno (como máximo una vez por hora). |
POST /documents/{id}/void | Cancela un documento pendiente de firma, con un reason opcional. |
DELETE /documents/{id} | Elimina un borrador o un documento cerrado. |
POST /documents/{id}/prepare_url | Una nueva ventana de preparación para un borrador: origin, redirect_uri, state. |
POST /documents/{id}/recipients/{recipient_id}/signing_url | Una ventana de firma para quien firma y está en su turno: origin, redirect_uri, state. |
GET /documents/{id}/original.pdf | El PDF tal como se envió. |
GET /documents/{id}/signed.pdf | La copia sellada, cuando todos han firmado. |
GET /documents/{id}/audit.json | El registro de auditoría: eventos, hashes y firmantes. |
GET /documents/{id}/audit.pdf | El registro de auditoría aparte y sellado de un documento con firmas cualificadas, cuando todos han firmado. |
POST /uploads | Inicia una subida por partes para PDF de más de 4 MB: size. Después PUT /uploads/{upload_id}/parts/{n} con los bytes de cada parte. |
GET /templates | Las plantillas de la persona, con sus roles y campos. |
GET /templates/{id} | Una plantilla. |
POST /templates | Guarda como plantilla uno de los documentos de tu app: document_id, name. |
DELETE /templates/{id} | Elimina una plantilla. |
Envía una cabecera Idempotency-Key al crear un documento: la misma clave y el mismo cuerpo en 24 horas devuelven el mismo documento (cabecera Idempotent-Replayed: true) en lugar de uno nuevo.
Errores y límites
Los errores tienen un estado HTTP y un cuerpo como { "error": { "code": "not_found", "message": "..." } }, a veces con detalles como index.
| Estado | Códigos |
|---|---|
400 | invalid_field, invalid_recipients, invalid_email, not_pdf, pdf_unreadable, pdf_encrypted, invalid_origin, invalid_redirect_uri, unknown_role, unknown_field |
401 | unauthenticated, invalid_token (caducado o revocado, o la persona quitó tu app) |
403 | insufficient_scope, sign_api_disabled |
404 | not_found (también para documentos que tu app no creó), template_not_found |
409 | not_draft, not_sent, not_your_turn, not_signable, signer_without_fields, no_signers, void_first, idempotency_in_progress |
413 | pdf_too_large, too_large, quota |
422 | idempotency_key_reused |
429 | rate_limited, con una cabecera Retry-After |
- PDF de hasta 25 MB y 200 páginas, sin contraseña. Solicitudes de hasta 4 MB; los PDF más grandes van por
/uploads. - Hasta 20 destinatarios y 400 campos por documento, 100 plantillas por persona. Los documentos y las plantillas cuentan en el almacenamiento de Dazr de la persona.
- 120 solicitudes por minuto por persona y app, 30 documentos nuevos cada 10 minutos y 30 envíos por hora.
- Los tokens de acceso duran 10 minutos. Usa el token de actualización (
offline_access) para obtener uno nuevo.
Transferir una app
Una app puede pasar a otra organización registrada en Dazr, con Transferir app en sus ajustes. Con la API de Dazr Sign activada, solo puede pasar a una organización verificada, y quien la posee o la administra debe aceptar en 14 días. La documentación para desarrolladores de Dazr Identity describe cada paso.
- Los documentos que tu app creó antes de la transferencia siguen siendo de las personas a las que pertenecen. La app ya no los ve a través de la API y no se envían webhooks por ellos.
- La URL del webhook y los orígenes de las ventanas emergentes se mantienen. El secreto de firma del webhook se renueva y se muestra una vez a quien acepta.
- Los tokens de acceso y de actualización emitidos antes de la transferencia dejan de funcionar, y las personas vuelven a aprobar la app en su próximo inicio de sesión. Las plantillas son de las personas y no cambian.
- Los recuentos de documentos en el portal de Sign empiezan de nuevo con la transferencia.