BunnyDoc
APIAPI de firma electrónica

Enviar desde una plantilla

Crea un sobre a partir de una de tus plantillas y envíalo en una sola llamada; después obtén los enlaces de firma.

Este es el endpoint en torno al que se construyen la mayoría de las integraciones: toma una de tus plantillas, asigna personas reales a sus roles y envíala para firmar, todo en una sola llamada. En la API no hay paso de borrador.

Crear un sobre a partir de una plantilla y enviarlo

Requiere el scope envelopes:send. La creación y el envío ocurren juntos: si el envío falla por cualquier motivo, el sobre se elimina y se devuelve un error, de modo que nunca queda un borrador a medio crear. Cada envío correcto consume una de las solicitudes de firma por API de tu plan.

Endpoint

POST   https://api2.bunnydoc.com/v1/envelopes/from-template

Cuerpo

CampoTipoObligatorioNotas
template_idstring (uuid)SíLa plantilla a enviar. Obtenla de GET /v1/templates.
recipientsarraySíDe 1 a 50 destinatarios, uno por cada rol desbloqueado de la plantilla.
sender_emailstringNoEnviar como este usuario. Debe ser un usuario activo de tu empresa con un asiento de firma electrónica. Por defecto, el propietario de la clave de API.
titlestringNoTítulo del sobre, hasta 250 caracteres. Por defecto, el nombre de la plantilla.
email_subjectstringNoAsunto de los correos de invitación (y de recordatorio). Hasta 300 caracteres. Admite placeholders. Por defecto, el asunto de la plantilla o New Document for Signature - {title}.
email_messagestringNoMensaje que ven los destinatarios. Hasta 10 000 caracteres. Texto plano o HTML limitado, y admite placeholders. Por defecto, el mensaje de la plantilla o el predeterminado de tu marca activa.

Cada destinatario asigna una persona real a un rol de la plantilla:

Campo del destinatarioTipoObligatorioNotas
rolestringSíDebe coincidir con un rol desbloqueado de GET /v1/templates/{id}. Hasta 25 caracteres.
namestringSíNombre completo del destinatario, hasta 120 caracteres.
emailstringSíCorreo del destinatario, hasta 150 caracteres.
contact_numberstringNoHasta 20 caracteres.

Haz coincidir los roles con exactitud y omite los bloqueados

Cada role debe ser el nombre de un rol desbloqueado de la plantilla, y cada rol puede aparecer una vez. Un rol que no existe, o un rol bloqueado, se rechaza con unknown_signer_role. Llama siempre antes a GET /v1/templates/{id} para leer los roles válidos.

No pongas al remitente en recipients

recipients es para las personas que reciben el documento. El remitente es quien resuelva sender_email, y su parte de la plantilla —el rol Me— se añade y se completa por ti. Nunca pasas un destinatario Me; si lo haces, su nombre y correo se ignoran en favor del remitente real.

Ejemplo de petición

Enviar desde una plantilla
curl -X POST https://api2.bunnydoc.com/v1/envelopes/from-template \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "018f2c3d-4e5f-7a8b-9c0d-1e2f3a4b5c6d",
    "title": "Mutual NDA — Acme Corp",
    "sender_email": "sales@yourco.com",
    "email_subject": "Please sign: Mutual NDA",
    "email_message": "Hi Jane — please review and sign our mutual NDA. Thanks!",
    "recipients": [
      { "role": "Client", "name": "Jane Doe", "email": "jane@acme.com" }
    ]
  }'

Respuesta

201 Created
{
  "envelope_id": "018f9a0b-1c2d-7e3f-8a4b-5c6d7e8f9a0b",
  "status": "sent",
  "title": "Mutual NDA — Acme Corp",
  "sender": { "email": "sales@yourco.com" },
  "recipients": [
    { "role": "Client", "name": "Jane Doe", "email": "jane@acme.com" }
  ],
  "signing_urls": [
    {
      "recipient_id": "018f9a0b-2c3d-7e4f-8a5b-6c7d8e9f0a1b",
      "name": "Jane Doe",
      "email": "jane@acme.com",
      "recipient_type": "need-to-sign",
      "signing_url": "https://sign.bunnydoc.com/s/eyJhbGciOi…"
    }
  ],
  "created_at": "2026-07-28T10:20:00.000Z"
}
CampoTipoDescripción
envelope_idstringEl id del nuevo sobre.
statusstringSiempre sent cuando tiene éxito.
senderobjectEl correo del remitente resuelto.
recipientsarrayLos destinatarios que proporcionaste.
signing_urlsarray | nullPresente solo si el sobre comparte enlaces de firma con el remitente; en caso contrario, null. Ver más abajo.
created_atstringMarca de tiempo ISO 8601.

¿De dónde salen la caducidad, los recordatorios y los campos?

La caducidad, los recordatorios, el orden de firma y la disposición de los campos se heredan de la plantilla. La API establece los destinatarios, el título, el remitente y —cuando los proporcionas— el asunto y el mensaje del correo; la plantilla (y el predeterminado de tu marca activa) aportan el resto.

Personalizar el correo de invitación

email_subject y email_message controlan el correo que recibe cada destinatario (y los recordatorios que le siguen: los recordatorios reutilizan el asunto con el prefijo Reminder:). Si los omites, se usan los valores de la plantilla.

Placeholders

Ambos campos admiten placeholders que se rellenan por destinatario en el momento del envío. Así una sola llamada puede producir un correo personalizado para cada firmante.

PlaceholderSe convierte en
{{recipient_name}}El nombre completo del destinatario
{{recipient_first_name}}El nombre de pila del destinatario
{{recipient_email}}El correo del destinatario
{{sender_name}}El nombre completo del remitente
{{sender_first_name}}El nombre de pila del remitente
{{sender_email}}El correo del remitente
{{company_name}}El nombre de tu empresa
{{envelope_title}}El título del sobre
{{expiry_date}}La fecha de caducidad del sobre, formateada según su configuración regional
Una petición, personalizada por destinatario
{
  "template_id": "018f2c3d-4e5f-7a8b-9c0d-1e2f3a4b5c6d",
  "email_subject": "{{recipient_first_name}}, firma {{envelope_title}}",
  "email_message": "<p>Hola {{recipient_first_name}}:</p><p>Revisa y firma. Caduca el {{expiry_date}}.</p><p>Gracias,<br/>{{sender_name}}</p>",
  "recipients": [
    { "role": "Client", "name": "Jane Doe", "email": "jane@acme.com" },
    { "role": "Witness", "name": "Sam Ortiz", "email": "sam@acme.com" }
  ]
}

Un placeholder desconocido se rechaza, no se ignora

Cualquier cosa dentro de {{ … }} que no esté en la lista anterior hace fallar la petición con validation_failed: no enviaremos un correo que contenga un literal {{customer_ref}}. Comprueba la ortografía contra la tabla; los nombres son exactos y en minúsculas.

Deliberadamente no hay placeholder para el enlace de firma ni para el código de acceso. El correo ya lleva el botón de firma, y un código de acceso es un segundo factor que debe llegar al destinatario por otra vía. Usa GET /v1/envelopes/{id}/signing-links si tu propio sistema necesita la URL.

Formato en email_message

Envía texto plano (se conservan los saltos de línea) o un subconjunto pequeño y seguro de HTML:

PermitidoEtiquetas
Párrafos y saltos<p>, <br>
Énfasis<strong>, <b>, <em>, <i>, <u>, <s>
Listas<ul>, <ol>, <li>
Enlaces<a href>: solo https, http, mailto, tel

Todo lo demás se elimina a la entrada, incluidos style, class, id, imágenes, tablas y encabezados. El valor guardado es el ya depurado, así que lo que puedes guardar es exactamente lo que recibe el destinatario.

Se rechazan los enlaces cuyo texto no coincide con su destino

<a href="https://evil.example">https://yourbank.example</a> falla con validation_failed. Si el texto del enlace parece una dirección, debe ser la dirección a la que enlazas. Usa texto descriptivo (<a href="https://acme.example/terms">nuestros términos</a>) y esto nunca te afectará.

El límite de 10 000 caracteres se cuenta después de depurar, así que algo de marcado suelto no te hará superarlo.

Errores

Estadoerror.codeCuándo ocurre
402quota_exceededTu empresa no tiene solicitudes de firma por API restantes en este periodo. No se entregó nada.
404template_not_foundNo existe ninguna plantilla con ese id en tu empresa.
422unknown_signer_roleUn rol de destinatario no coincide con la plantilla, o se proporcionó un rol bloqueado.
422sender_not_foundsender_email no es un usuario activo con asiento de firma electrónica en tu empresa. (Sin sender_email, el propietario de la clave ha perdido su asiento.)
422sender_fields_incompleteEl propio rol de remitente de la plantilla tiene campos obligatorios sin valor, así que el documento no puede salir. Arréglalo en la plantilla: consulta la referencia de errores.
400 422validation_failedEl cuerpo está mal formado: falta un campo, rol duplicado, se supera un límite de longitud, un {{placeholder}} desconocido o un enlace engañoso.
429rate_limitedMás de 100 envíos en 15 minutos para esta clave.
5xxsend_failedSe creó pero no se envió, así que se descartó. No se entregó nada; reintentar crea un sobre nuevo en lugar de duplicar uno.

Obtener los enlaces de firma de un sobre enviado

Los enlaces de firma permiten que el sistema del remitente entregue a cada destinatario un enlace directo en lugar de esperar al correo. Están disponibles en cualquier momento tras el envío y también los devuelve la llamada de envío anterior.

Endpoint

GET   https://api2.bunnydoc.com/v1/envelopes/{id}/signing-links

Ejemplo de petición

Obtener enlaces de firma
curl https://api2.bunnydoc.com/v1/envelopes/018f9a0b-1c2d-7e3f-8a4b-5c6d7e8f9a0b/signing-links \
  -H "Authorization: Bearer <access_token>"

Respuesta

200 OK
{
  "signing_urls": [
    {
      "recipient_id": "018f9a0b-2c3d-7e4f-8a5b-6c7d8e9f0a1b",
      "name": "Jane Doe",
      "email": "jane@acme.com",
      "recipient_type": "need-to-sign",
      "signing_url": "https://sign.bunnydoc.com/s/eyJhbGciOi…"
    }
  ]
}

signing_url es null para los destinatarios que no firman (por ejemplo, uno que "recibe una copia").

Un enlace de firma es una credencial de portador

Cualquiera que tenga un enlace de firma puede firmar como ese destinatario. Entrégalos por canales seguros y trátalos como secretos: no los registres ni los incluyas en URLs que compartas.

Errores

Estadoerror.codeCuándo ocurre
403signing_links_disabledEste sobre no tiene activada la opción de "compartir enlaces de firma con el remitente".
404envelope_not_foundNo existe ningún sobre con ese id en tu empresa.

¿Quieres actualizaciones de estado sin sondear?

La API es de solo escritura para los sobres: no hay endpoint de estado por diseño. Para saber cuándo se ve, se firma o se completa un documento, suscríbete a los webhooks.

En esta página