Conexión segura · evidencia sellada

API v1

API de Unicus Sign

Crea, envía y sigue solicitudes de firma desde tus sistemas, abre la firma dentro de tu app y recibe webhooks cuando algo cambia. La referencia se genera del mismo código que valida cada petición, así que siempre coincide con lo que acepta el servidor.

URL base: https://…

Descargar OpenAPI 3.1

Puedes importar ese archivo en Postman o Insomnia para probar todas las llamadas.

Primer sobre en 4 pasos

Con una llave de prueba (usk_test_) todo ocurre en el sandbox: no se cobra y los documentos dicen que son de prueba.

  1. Crea una llave en Unicus Sign → Desarrolladores y guárdala como variable de entorno UNICUS_SIGN_KEY.
  2. Crea el sobre con sus destinatarios y pide un formulario de carga para cada documento; súbelo y espera a que el documento quede "ready" (antivirus y procesamiento tardan segundos).
  3. Ubica los campos (fracciones de la página desde la esquina superior izquierda) y envía el sobre.
  4. Sigue el estado con GET o, mejor, con webhooks. Al completarse, descarga los documentos sellados y el certificado.

Referencia: createEnvelope → addDocument → setFields → sendEnvelope → getEnvelope

Autenticación y entornos

Envía la llave en cada petición: Authorization: Bearer <llave>. Cada llave actúa con los permisos del miembro que la creó y solo ve los sobres de su entorno.

Authorization: Bearer usk_test_…
usk_test_…Sandbox en todos los planes: sin cobro, con un límite diario de envíos y documentos marcados como prueba.
usk_live_…Producción: según el plan de la organización (la página Precios dice desde cuál).

Permisos de la llave

envelopes:readLeer sobres, plantillas y archivos.
envelopes:writeCrear, enviar, corregir y anular sobres; abrir la firma embebida.

Errores

Los errores responden JSON con un código estable en error. Las validaciones agregan issues (campo y motivo) y un envío bloqueado agrega problems.

HTTPerrorQué hacer
400invalid_request / invalidRevisa issues: falta un campo o el formato no es válido.
401unauthenticatedLlave ausente, revocada o mal escrita.
402plan_limitEl plan no lo permite (producción, cupo o créditos).
403forbiddenA la llave le falta el permiso o el rol del miembro no lo permite.
404not_foundNo existe o pertenece al otro entorno (prueba o producción).
409conflictEl estado actual no lo permite (por ejemplo, ya enviado).
410expiredEl enlace o el sobre venció.
422send_blockedEl sobre aún no se puede enviar: problems dice por qué.
429rate_limitedDemasiadas peticiones: espera y reintenta con espera creciente.

Ejemplo de 422

HTTP/1.1 422
{
    "error": "send_blocked",
    "problems": ["no_signature:ana@example.com", "exclusion_ack:real_estate_deed"]
}

Límites y paginación

Peticiones1.000 por IP cada 5 minutos en /v1/; por encima se responde 403 desde el firewall.
EnvíosPor hora y por mes según el plan; el sandbox tiene un límite diario propio.
Listaslimit (1–200, 50 por defecto) y offset. Pide la siguiente página mientras recibas limit resultados.
TamañosDocumentos de hasta 25 MB y 100 páginas; cuerpos JSON de hasta 64 KB.

Webhooks

Registra un endpoint HTTPS en Desarrolladores, o desde tu integración con POST /v1/api/webhooks (y DELETE para quitarlo), como hacen Zapier y Make. Enviamos un POST firmado cuando cambia un sobre; el cuerpo solo trae identificadores, así que consulta los detalles por la API. Responde 2xx en menos de 10 segundos.

envelope.sentEl sobre se envió.
recipient.openedUn destinatario abrió su enlace.
recipient.signedUn destinatario firmó.
recipient.approvedUn aprobador aprobó.
recipient.declinedUn destinatario rechazó (el sobre se detiene).
recipient.delegatedUn destinatario delegó en otra persona.
envelope.completedTodos actuaron; empieza el sellado.
envelope.rejectedEl sobre quedó rechazado.
envelope.voidedEl remitente lo anuló.
envelope.expiredVenció sin completarse.
envelope.sealedLos documentos sellados y el certificado ya se pueden descargar.

Cuerpo de cada entrega

POST <your URL>
unicus-sign-event-id: 019a…
unicus-sign-signature: t=1791400000,v1=5f2b…
content-type: application/json

{
    "id": "019a…",
    "type": "envelope.completed",
    "createdAt": "2026-10-09T15:00:00.000Z",
    "livemode": true,
    "data": { "envelopeId": "01a1…" }
}

Verifica la firma sobre el cuerpo tal como llegó (antes de interpretarlo) y rechaza marcas de tiempo de más de 5 minutos.

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody: the request body exactly as received (a string or Buffer, before JSON.parse)
export function verify(rawBody, header, secret) {
    const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
    const t = Number(parts.t);
    if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
    const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
    return expected.length === parts.v1?.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Si tu endpoint falla o tarda, reintentamos a 1 min, 5 min, 30 min, 2 h, 6 h, 12 h y 24 h; después la entrega queda fallida y puedes reenviarla desde Desarrolladores. Usa el id del evento para no procesarlo dos veces.

Firma embebida y flujos

Para firmar dentro de tu app, crea el destinatario con delivery "embedded" y, cuando sea su turno, pide la URL de firma. Ábrela en una pestaña o webview (no en un iframe): sirve una vez y vence en 5 minutos.

Al terminar, rechazar o cerrar, la persona vuelve a tu returnUrl con ?event=signing_complete o declined y el envelopeId. Tu app es responsable de haber identificado a esa persona.

En flujos de verificación (por ejemplo un paso de Unicus), POST /v1/api/flows/sign crea, envía y abre la firma en una sola llamada desde una plantilla.

Referencia