API de FirmaWeb

Firma masiva y firma desatendida desde tu propio sistema (ERP, remuneraciones, RR.HH.).

Introducción

Con la API tu sistema envía a firmar lotes (muchas personas de una vez, cada una con sus documentos) y hace que el firmante de tu empresa (el gerente, el representante legal) firme todo lo pendiente con un botón, sin salir de tu sistema. Todas las peticiones usan JSON y un token de corta duración.

Dirección base

VersiónURL baseDescripción
V2https://escritorio.firmaweb.app/apifw/v2Firma masiva (lotes) y firma desatendida. Es la que describe esta página.
V1https://escritorio.firmaweb.app/apifw/v1La API anterior: sigue funcionando igual, con las mismas credenciales. Se pueden usar las dos a la vez.

Flujo de integración típico

Paso 1AutenticarPedir un token con tus credenciales de API.
Paso 2Enviar el lotePersonas, documentos y firmantes comunes, en una llamada.
Paso 3Firman las personasCada una recibe su correo y firma con su PIN.
Paso 4Firma desatendidaTu firmante firma todo lo pendiente con un botón en tu sistema.
Paso 5Recibir avisosTu sistema se entera de cada firma y de cada lote terminado.
Paso 6DescargarBajar los PDF firmados y guardarlos en tu sistema.

Antes de empezar (una vez, en la consola)

  1. Administrar → Clave de API → Generar credenciales. Aparecen el APIUSER y la APIKEY. La clave se muestra una sola vez.
  2. Administrar → Firmantes registrados: registra a quienes firmarán por la empresa. Cada uno activa su firma desde su propia consola.
  3. Si quieres recibir avisos: en la misma página de la clave, Generar secreto de avisos.

Autenticación

Todas las llamadas llevan un token en la cabecera:

Authorization: Bearer <token>

El token se pide con el usuario y la clave de API, unidos por dos puntos y en Base64, en POST /apifw/v1/token (el mismo token sirve para las dos versiones):

Authorization: Bearer base64(APIUSER:APIKEY)

El token dura 15 minutos. Cuando venza (HTTP 401), pide otro.

Petición de ejemplo
curl -X POST https://escritorio.firmaweb.app/apifw/v1/token \
  -H "Authorization: Bearer $(printf '%s' 'APIUSER:APIKEY' | base64)"
Respuesta
{
  "Estado": 1, "Mensaje": "Correcto",
  "Token": "eyJhbGciOi...",
  "Token_tipo": "Bearer",
  "Expira_en": 1791234567
}

Firma desatendida Nuevo

El firmante de tu empresa firma todo lo que le toca, de una vez, con un botón en tu propio sistema: sin entrar a FirmaWeb, sin abrir un enlace por documento y sin PIN por correo. Con 200 contratos, es una sola acción.

Modo 1 · por defectoCon código

Junto al botón, tu sistema le pide al firmante el código de 6 dígitos de su aplicación de autenticación (la misma con que entra a la consola) y lo envía en codigo. Un código firma todo lo pendiente: no se pide por documento.

Modo 2 · firma desatendidaCon autorización permanente

El firmante entra una vez a su consola, en Documentos → Sin firmar → Firmar desde el sistema de tu empresa, acepta la autorización permanente y la confirma con un código. Desde entonces tu sistema llama a /firmar sin código, incluso de forma automática. La retira ahí mismo cuando quiera.

Cómo se arma

  1. Inscribir la firma (una vez): un administrador registra al firmante en Administrar → Firmantes registrados, y él la activa en su consola con su RUT y un código de su aplicación.
  2. Ponerlo como firmante: en los lotes, en firmantesComunes; en los procesos de /apifw/v1, agregándolo al final con agregar_firmante, con el mismo RUT y correo de su registro.
  3. Mostrarle lo pendiente: GET /firmas_pendientes.
  4. El botón: POST /firmar.
La clave de API por sí sola nunca firma por una persona: hace falta su código o su autorización permanente, que solo él puede dar. Cada firma queda registrada con la forma en que se autorizó.
Un aviso por lote, no por documento. En los lotes, el firmante común no recibe un correo por cada documento: le llega uno cuando ya tiene documentos listos y otro cuando todo el lote lo espera. El avance (cuántos están listos, cuántos faltan) lo ve en su consola, y tu sistema lo consulta con GET /lotes/{idLote} o GET /firmas_pendientes.

Firma desatendida

GET /firmas_pendientes

Lo que le toca firmar al firmante registrado

Devuelve los procesos en que el firmante registrado ya puede firmar: aquellos en que firmaron todos los anteriores. Úsala para mostrarle la lista en tu sistema antes del botón, y para saber si hay que pedirle el código.

Requiere Bearer Token

Parámetros (en la dirección)

CampoTipoReq.Descripción
rutFirmantestringREQRUT del firmante registrado de tu cuenta.
idLoteintegerOPCPara ver solo lo pendiente de un lote.

Respuestas

200Lista de procesos pendientes (puede venir vacía)
422Ese RUT no es un firmante registrado y activo de la cuenta
401Token inválido o vencido
Petición de ejemplo
GET https://escritorio.firmaweb.app/apifw/v2/firmas_pendientes?rutFirmante=12.345.678-5
Respuestas

200 — Correcto

{
  "firmante": { "rut": "12345678-5", "nombre": "Ana Pérez Soto", "autorizacionPermanente": false },
  "pideCodigo": true, "total": 2, "documentos": 3,
  "procesos": [
    { "idProceso": 1000345, "referencia": "trabajador-0041", "idLote": 1000012, "nombre": "Liquidaciones septiembre 2026 · Jorge Díaz", "documentos": 2 },
    { "idProceso": 1000346, "referencia": "trabajador-0042", "idLote": 1000012, "nombre": "Liquidaciones septiembre 2026 · María Soto", "documentos": 1 }
  ]
}

422 — No registrado

{ "error": "firmante_comun_no_registrado", "mensaje": "Ese RUT no es un firmante registrado y activo de la cuenta. Consulta GET /firmantes_registrados." }

POST /firmar

Firmar todo lo pendiente, de una vez

Aplica la firma del firmante registrado en todo lo que le toca, en una sola llamada: es el botón de tu sistema. Sirve para los lotes y también para los procesos creados con /apifw/v1, siempre que él figure como firmante con el RUT y el correo de su registro.

Si quedan es mayor que cero (lotes muy grandes), repite la llamada. Repetirla nunca firma ni cobra dos veces.

Requiere Bearer Token

Cuerpo de la petición (JSON)

CampoTipoReq.Descripción
rutFirmantestringREQRUT del firmante registrado de tu cuenta.
codigostring (6 dígitos)SEGÚNEl código que muestra en ese momento la aplicación de autenticación del firmante. Cada código sirve una vez y firma todo lo pendiente. No se envía si el firmante dio la autorización permanente.
idLoteintegerOPCPara firmar solo lo de un lote.
procesosarray de integerOPCLista de idProceso, para firmar solo esos.

Respuestas

200Firmado: lista de procesos firmados y, si los hay, los que no
422Falta el código (el firmante no ha dado la autorización permanente)
403Código no válido o ya usado
429Más de 5 intentos de código en 15 minutos
La clave de API por sí sola nunca firma por una persona: hace falta su código o su autorización permanente. Solo se firman procesos de tu propia cuenta, y cada firma queda registrada con la forma en que se autorizó.
Petición de ejemplo
POST https://escritorio.firmaweb.app/apifw/v2/firmar
{
  "rutFirmante": "12.345.678-5",
  "codigo": "492817"
}
Respuestas

200 — Firmado

{
  "firmante": { "rut": "12345678-5", "nombre": "Ana Pérez Soto" },
  "modo": "codigo",
  "firmados": [
    { "idProceso": 1000345, "referencia": "trabajador-0041", "idLote": 1000012, "nombre": "Liquidaciones septiembre 2026 · Jorge Díaz", "documentos": 2 }
  ],
  "noFirmados": [],
  "quedan": 0
}

422 — Falta código

{ "error": "falta_codigo", "mensaje": "Falta `codigo`: el código de 6 dígitos de la aplicación de autenticación del firmante. Solo se omite si el firmante dio la autorización permanente en su consola." }

403 — Código inválido

{ "error": "codigo_invalido", "mensaje": "El código no es válido o ya se usó. Pide al firmante uno nuevo de su aplicación." }

Lotes (firma masiva)

POST /lotes

Crear un lote (y enviarlo en la misma llamada)

Envía a firmar muchas personas de una vez, cada una con sus documentos. Con "enviar": true el lote sale en esta misma llamada. Todo o nada: si una fila tiene un error, no se crea ni se cobra nada, y la respuesta dice qué corregir en cada fila.

Sin personas ni enviar, el lote queda en borrador para llenarlo por tandas (lotes de más de 30 MB).

Requiere Bearer Token

Cuerpo de la petición (JSON)

CampoTipoReq.Descripción
nombrestring ≤80REQNombre del lote. Lo ven tus usuarios en la consola.
referenciastring ≤100OPCTu identificador del lote. Si repites la llamada con la misma referencia, no se crea ni se cobra otro lote: recibes el que ya existe, con "repetido": true. Úsala siempre.
firmantesComunesarray de stringOPCRUT de los firmantes registrados que firman todos los procesos, en el orden en que deben firmar.
urlNotificastring (URL)OPCDirección de tu sistema que recibirá los avisos.
idEmpresaintegerOPCSi tu cuenta tiene varias empresas, a cuál corresponde.
enviarbooleanOPCtrue para enviarlo ahora. Sin él queda en borrador.
personas[].referenciastring ≤100OPCTu identificador de la persona (id de trabajador, de contrato…). Vuelve en las respuestas y en los avisos.
personas[].nombresstringREQNombres de quien firma.
personas[].apellidoPaternostringREQApellido paterno. apellidoMaterno es opcional.
personas[].rutstringREQRUT con dígito verificador (se valida). Con o sin puntos.
personas[].emailstringREQCorreo donde recibe el enlace y el PIN.
personas[].documentos[]arrayREQDe 1 a 10 documentos: nombre y pdf (el PDF en Base64, hasta 10 MB cada uno).

Respuestas

201Lote creado (y enviado, si se pidió)
200Ya existía un lote con esa referencia: se devuelve, con "repetido": true
422Hay filas con errores, o un firmante común no está registrado: no se creó nada
402No alcanzan las firmas: no se creó nada
413Más de 30 MB: usa el borrador y agrega las personas por tandas
Petición de ejemplo
POST https://escritorio.firmaweb.app/apifw/v2/lotes
{
  "nombre": "Liquidaciones septiembre 2026",
  "referencia": "liq-2026-09",
  "firmantesComunes": ["12.345.678-5"],
  "urlNotifica": "https://tu-sistema.cl/firmaweb/avisos",
  "enviar": true,
  "personas": [
    {
      "referencia": "trabajador-0041",
      "nombres": "Jorge",
      "apellidoPaterno": "Díaz",
      "apellidoMaterno": "Rojas",
      "rut": "11.111.111-1",
      "email": "jorge@correo.cl",
      "documentos": [
        { "nombre": "Liquidación septiembre.pdf", "pdf": "JVBERi0xLjcK... (Base64)" },
        { "nombre": "Anexo de contrato.pdf", "pdf": "JVBERi0xLjcK... (Base64)" }
      ]
    }
  ]
}
Respuestas

201 — Creado

{
  "idLote": 1000012, "nombre": "Liquidaciones septiembre 2026", "referencia": "liq-2026-09",
  "estado": "en_firma",
  "firmantesComunes": [{ "rut": "12345678-5", "nombre": "Ana Pérez Soto" }],
  "resumen": { "personas": 1, "documentos": 2, "enFirma": 1, "faltaPersona": 1, "faltaFirmanteComun": 0, "completados": 0, "anulados": 0 },
  "personas": [{
    "referencia": "trabajador-0041", "idProceso": 1000345, "estado": "en_firma",
    "rut": "11.111.111-1", "nombre": "Jorge Díaz Rojas", "email": "jorge@correo.cl",
    "firmantes": [
      { "orden": 1, "rut": "11.111.111-1", "nombre": "Jorge Díaz Rojas", "firmo": false },
      { "orden": 2, "rut": "12345678-5", "nombre": "Ana Pérez Soto", "firmo": false }
    ],
    "documentos": [
      { "idDocumento": 1000801, "nombre": "Liquidación septiembre.pdf", "firmado": false },
      { "idDocumento": 1000802, "nombre": "Anexo de contrato.pdf", "firmado": false }
    ]
  }]
}

422 — Filas con errores

{
  "error": "filas_con_errores",
  "mensaje": "No se creó nada: hay 2 fila(s) por corregir.",
  "filas": [
    { "fila": 3, "referencia": "trabajador-0057", "error": "RUT no válido" },
    { "fila": 8, "referencia": "trabajador-0102", "error": "\"Liquidación.pdf\" no es un PDF en Base64" }
  ]
}

402 — Sin saldo

{ "error": "saldo_insuficiente", "mensaje": "No se envió nada: el lote necesita 400 firmas y la cuenta tiene 380.", "necesarias": 400, "disponibles": 380 }

POST /lotes/{idLote}/personas

Agregar personas a un borrador

Para lotes grandes: agrega las personas por tandas (por ejemplo, de 20 en 20), las veces que haga falta. Cada tanda es todo o nada: si una persona tiene un error, no se agrega ninguna de esa tanda. Nada se cobra ni se envía todavía.

Requiere Bearer Token

Cuerpo de la petición (JSON)

CampoTipoReq.Descripción
personas[].referenciastring ≤100OPCTu identificador de la persona (id de trabajador, de contrato…). Vuelve en las respuestas y en los avisos.
personas[].nombresstringREQNombres de quien firma.
personas[].apellidoPaternostringREQApellido paterno. apellidoMaterno es opcional.
personas[].rutstringREQRUT con dígito verificador (se valida). Con o sin puntos.
personas[].emailstringREQCorreo donde recibe el enlace y el PIN.
personas[].documentos[]arrayREQDe 1 a 10 documentos: nombre y pdf (el PDF en Base64, hasta 10 MB cada uno).

Respuestas

200Personas agregadas: devuelve el lote al día
422Hay filas con errores: no se agregó ninguna de la tanda
409El lote ya se envió: no admite cambios
Petición de ejemplo
POST https://escritorio.firmaweb.app/apifw/v2/lotes/1000012/personas
{
  "personas": [
    {
      "referencia": "trabajador-0042",
      "nombres": "María", "apellidoPaterno": "Soto",
      "rut": "22.222.222-2", "email": "maria@correo.cl",
      "documentos": [{ "nombre": "Liquidación septiembre.pdf", "pdf": "JVBERi0xLjcK... (Base64)" }]
    }
  ]
}
Respuestas

200 — Agregadas

{ "idLote": 1000012, "estado": "borrador", "resumen": { "personas": 2, "documentos": 3, "enFirma": 0, "completados": 0, "anulados": 0 }, "personas": [ "..." ] }

422 — Filas con errores

{
  "error": "filas_con_errores",
  "mensaje": "No se agregó nada: hay 1 fila(s) por corregir.",
  "filas": [{ "fila": 2, "referencia": "trabajador-0041", "error": "esta persona ya está en el lote" }]
}

POST /lotes/{idLote}/enviar

Enviar un borrador

Revisa el saldo, descuenta las firmas y envía los correos a las personas. Si no alcanza el saldo, el lote sigue en borrador: carga firmas y vuelve a enviarlo. No lleva cuerpo.

Requiere Bearer Token

Respuestas

200Lote enviado
402No alcanzan las firmas: el lote sigue en borrador
422El lote no tiene personas, o un firmante común ya no está disponible
409El lote ya se había enviado
Petición de ejemplo
POST https://escritorio.firmaweb.app/apifw/v2/lotes/1000012/enviar
Respuestas

200 — Enviado

{ "idLote": 1000012, "estado": "en_firma", "resumen": { "personas": 200, "documentos": 200, "enFirma": 200, "completados": 0, "anulados": 0 }, "personas": [ "..." ] }

GET /lotes/{idLote}

Consultar el avance de un lote

El lote al día: quién firmó (firmo), qué documentos están listos (firmado) y el estado de cada persona. En resumen viene la etapa del lote: faltaPersona (procesos que esperan a la persona), faltaFirmanteComun (ya firmó la persona; esperan al firmante común), completados y anulados.

EstadoSignifica
borradorTodavía no se envía.
en_firmaEnviado; faltan firmas.
completado (persona)Firmaron todos. Sus documentos ya se pueden descargar.
anulado (persona)Pasaron 8 días sin completarse, o alguien lo anuló en la consola. Las firmas que no se usaron vuelven al saldo.
terminado (lote)Ya no queda ninguna persona en firma.
Requiere Bearer Token

Respuestas

200El lote, con el avance por persona, por firmante y por documento
404El lote no existe
Si recibes avisos no necesitas consultar a cada rato. Si no los usas, consulta cada varios minutos, no cada segundo.
Petición de ejemplo
GET https://escritorio.firmaweb.app/apifw/v2/lotes/1000012
Respuestas

200 — Correcto

{
  "idLote": 1000012, "nombre": "Liquidaciones septiembre 2026", "referencia": "liq-2026-09",
  "estado": "en_firma",
  "firmantesComunes": [{ "rut": "12345678-5", "nombre": "Ana Pérez Soto" }],
  "resumen": { "personas": 1, "documentos": 2, "enFirma": 1, "faltaPersona": 1, "faltaFirmanteComun": 0, "completados": 0, "anulados": 0 },
  "personas": [{
    "referencia": "trabajador-0041", "idProceso": 1000345, "estado": "en_firma",
    "rut": "11.111.111-1", "nombre": "Jorge Díaz Rojas", "email": "jorge@correo.cl",
    "firmantes": [
      { "orden": 1, "rut": "11.111.111-1", "nombre": "Jorge Díaz Rojas", "firmo": false },
      { "orden": 2, "rut": "12345678-5", "nombre": "Ana Pérez Soto", "firmo": false }
    ],
    "documentos": [
      { "idDocumento": 1000801, "nombre": "Liquidación septiembre.pdf", "firmado": false },
      { "idDocumento": 1000802, "nombre": "Anexo de contrato.pdf", "firmado": false }
    ]
  }]
}

DELETE /lotes/{idLote}

Descartar un borrador

Borra un lote que todavía no se envía, con sus documentos. Un lote enviado no se borra.

Requiere Bearer Token

Respuestas

204Borrador descartado (sin cuerpo)
409El lote ya se envió
Petición de ejemplo
DELETE https://escritorio.firmaweb.app/apifw/v2/lotes/1000012
Respuestas

409 — Ya enviado

{ "error": "lote_ya_enviado", "mensaje": "El lote ya se envió: no se puede modificar." }

Documentos

GET /documentos/{idDocumento}

Descargar un documento firmado

Devuelve el PDF firmado tal cual (Content-Type: application/pdf), no en Base64. Solo cuando ya firmaron todos. Sirve para cualquier documento de tu cuenta, también los de /apifw/v1.

Requiere Bearer Token

Respuestas

200El PDF firmado
409Al documento todavía le faltan firmas
404El documento no existe
Petición de ejemplo
GET https://escritorio.firmaweb.app/apifw/v2/documentos/1000801
Respuestas

200 — PDF

Content-Type: application/pdf
Content-Disposition: attachment; filename*=UTF-8''Liquidaci%C3%B3n%20septiembre.pdf

%PDF-1.7 ...

409 — Sin firmar

{ "error": "documento_sin_firmar", "mensaje": "Al documento todavía le faltan firmas." }

Cuenta

GET /firmantes_registrados

Firmantes registrados de la cuenta

Quiénes pueden ir como firmantes comunes de un lote y firmar con /firmar: los firmantes registrados y activos de tu cuenta.

Requiere Bearer Token

Respuestas

200Lista de firmantes registrados
Petición de ejemplo
GET https://escritorio.firmaweb.app/apifw/v2/firmantes_registrados
Respuestas

200 — Correcto

{ "firmantes": [{ "rut": "12345678-5", "nombre": "Ana Pérez Soto", "email": "ana@tu-empresa.cl" }] }

GET /saldo

Firmas disponibles

El saldo de firmas de la cuenta. fes es firma electrónica simple.

Requiere Bearer Token

Respuestas

200Saldo de la cuenta
Petición de ejemplo
GET https://escritorio.firmaweb.app/apifw/v2/saldo
Respuestas

200 — Correcto

{ "fes": 480, "fao": 0 }

Avisos a tu sistema

POST tu urlNotifica

FirmaWeb le avisa a tu sistema

Si el lote lleva urlNotifica, FirmaWeb hace un POST con JSON a esa dirección cada vez que pasa algo. Todos los avisos traen evento, fecha, idLote y referenciaLote.

Firmado con tu secreto de avisos

Eventos

EventoCuándoDatos
firmaAlguien firmó un documento (cada firmante, cada documento).idProceso, referencia, idDocumento, documento, firmante
proceso_completadoFirmaron todos los de una persona: sus documentos ya se pueden descargar.idProceso, referencia
proceso_anuladoEl proceso de una persona se anuló.idProceso, referencia
lote_completadoYa no queda ninguna persona en firma.completados, anulados

Qué debe hacer tu sistema

2xxResponder en menos de 10 segundos. Con eso el aviso queda entregado.
OtroReintentamos a los 7 y a los 20 minutos; después dejamos de intentar.
Un mismo aviso reintentado lleva el mismo número en la cabecera X-FirmaWeb-Entrega: úsalo para no procesarlo dos veces. La cabecera X-FirmaWeb-Firma: t=…,v1=… trae el HMAC-SHA256, en hexadecimal, del texto t + punto + cuerpo tal como llegó, calculado con tu secreto de avisos (se genera en Administrar → Clave de API). Si no coincide, descarta el aviso.
Aviso de ejemplo
{
  "evento": "proceso_completado",
  "fecha": "2026-10-05T14:03:22.118Z",
  "idLote": 1000012, "referenciaLote": "liq-2026-09",
  "idProceso": 1000345, "referencia": "trabajador-0041"
}
Comprobar que el aviso es nuestro
// Node.js: cuerpoCrudo es el cuerpo recibido, sin modificar
const crypto = require('node:crypto');

function avisoValido(cabecera, cuerpoCrudo, secreto) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(cabecera || '');
  if (!m) return false;
  // más de 5 minutos de diferencia: se descarta
  if (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
  const esperado = crypto.createHmac('sha256', secreto)
    .update(m[1] + '.' + cuerpoCrudo).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(m[2]));
}

Errores

Un error responde con su código HTTP y { "error": "…", "mensaje": "…" }. error es fijo, para tu programa; mensaje es para una persona.

HTTPerrorQué hacer
400solicitud_invalidaEl cuerpo no es un JSON válido.
401no_autorizadoFalta el token, no es válido o venció: pide uno nuevo.
402saldo_insuficienteNo alcanzan las firmas. Trae necesarias y disponibles.
403codigo_invalidoEl código del firmante no es válido o ya se usó: pídele uno nuevo.
404lote_no_existe, documento_no_existeRevisa el número.
409lote_ya_enviadoEl lote ya se envió: no admite cambios.
409documento_sin_firmarTodavía faltan firmas.
413solicitud_muy_grandeMás de 30 MB: crea el lote en borrador y agrega las personas por tandas.
422filas_con_erroresCorrige las filas de filas y reenvía.
422firmante_comun_no_registradoEse RUT no es un firmante registrado y activo de tu cuenta.
422falta_codigoEnvía el código del firmante, o que él dé la autorización permanente.
422falta_secreto_avisosGenera el secreto de avisos en la consola.
422falta_nombre, sin_personas, lote_vacio, demasiadas_personas, empresa_no_existe, url_notifica_invalidaLo explica el mensaje.
429demasiadas_solicitudes, demasiados_codigosEspera: más de 120 solicitudes por minuto, o más de 5 intentos de código en 15 minutos.
500error_internoReintenta. Con referencia, el lote no se duplica.

Límites y cobro

¿Dudas con la integración?

Escríbenos a ayuda@mail.firmaweb.app con la llamada que hiciste y la respuesta que recibiste (sin la clave ni el token).

Todos los derechos reservados | 2026 © FirmaWeb