API de firma electrónica
Envía documentos para firmar directamente desde tus propios sistemas: intercambia una clave de API por un token, crea sobres a partir de plantillas, gestiona contactos y obtén enlaces de firma mediante una API REST sencilla.
La API de firma electrónica permite que tu aplicación haga lo mismo que tu equipo hace en la app: convertir una plantilla en una solicitud de firma, enviarla y seguirla hasta obtener un PDF firmado y con traza de auditoría, sin que nadie abra BunnyDoc.
Es una API REST pequeña y enfocada. JSON de entrada, JSON de salida, un único token de portador y exactamente los mismos permisos que tu equipo ya tiene en la app.
URL base
Todos los endpoints están bajo https://api2.bunnydoc.com/v1. Todas las rutas de estas páginas
son relativas a esa base.
Cómo funciona la autenticación
El acceso es un flujo de dos pasos y es lo primero que construirás. Tu clave de API de larga duración se envía una sola vez para obtener un token de acceso de corta duración; todas las demás peticiones llevan solo el token, de modo que la clave nunca vuelve a viajar.
Crea una clave de API
En la app, abre Configuración → Claves de API (solo propietario o administrador) y crea una
clave. Tiene el aspecto bd_live_… y se muestra una sola vez, al crearla: cópiala en un lugar
seguro. Después no se puede recuperar, solo rotar. Consulta
Crear y gestionar claves de API para scopes, caducidad y
rotación.
Intercambia la clave por un token de acceso
Envía tu clave a POST /v1/auth/token. Recibirás un
token de portador válido durante una hora.
Llama a la API con el token
Envía Authorization: Bearer <token> en todas las demás peticiones. Guarda el token en caché y
reutilízalo hasta que caduque; no generes uno nuevo por cada llamada.
Mantén tu clave de API en el servidor
Una clave de API actúa en nombre de toda tu empresa. Nunca la incluyas en un navegador, una app móvil ni ningún cliente que no controles. Si una clave queda expuesta, revócala en Configuración → Claves de API y genera una nueva: revocarla invalida sus tokens vigentes de inmediato, mientras que rotarla los deja válidos el resto de su hora.
Constrúyelo en este orden
Una integración completa son cinco llamadas. Hazlas en este orden y te encontrarás con los tropiezos en el sitio más barato posible: un 404 en una plantilla que puedes leer, no un 422 en un envío que pretendías entregar.
Genera una clave e intercámbiala por un token
Crear y gestionar claves de API →
POST /v1/auth/token. Guarda el token en caché toda
su hora.
Encuentra la plantilla que quieres enviar
GET /v1/templates para localizarla y después
GET /v1/templates/{id} para leer sus roles. En la práctica
esta segunda llamada no es opcional: te dice qué roles rellenar y cuáles están bloqueados.
Decide quién lo envía
Omite sender_email para enviar como propietario de la clave, o llama a
GET /v1/users para que tu interfaz permita elegir a un compañero.
Enviar como otra persona usa sus permisos, no los del propietario de la clave.
Envíalo
POST /v1/envelopes/from-template. Crea y envía
en una sola llamada; si el envío falla, no queda nada atrás. Guarda el envelope_id devuelto.
Suscríbete a lo que ocurra después
POST /v1/webhooks: la
API no tiene endpoint de estado de sobre, por diseño. Toma el PDF final de
envelope.document_ready.
Obtener un token de acceso
La primera llamada de toda integración: intercambia tu clave de API por un token de portador.
Enviar desde una plantilla
Crea un sobre a partir de una de tus plantillas y envíalo en una sola llamada.
Endpoints de un vistazo
Cada petición se autoriza tanto por el scope de tu clave como por el permiso del usuario que la posee: una clave nunca puede hacer más de lo que esa persona puede hacer en la app.
| Para hacer esto | Endpoint | Scope |
|---|---|---|
| Intercambiar una clave de API por un token | POST /v1/auth/token | — |
| Listar tus plantillas | GET /v1/templates | templates:read |
| Obtener una plantilla y sus roles | GET /v1/templates/{id} | templates:read |
| Listar contactos | GET /v1/contacts | contacts:read |
| Crear un contacto | POST /v1/contacts | contacts:write |
| Crear un sobre a partir de una plantilla y enviarlo | POST /v1/envelopes/from-template | envelopes:send |
| Obtener los enlaces de firma de un sobre enviado | GET /v1/envelopes/{id}/signing-links | envelopes:send |
| Listar los miembros de la empresa | GET /v1/users | users:read |
| Listar los eventos a los que puedes suscribirte | GET /v1/webhooks/events | webhooks:read |
| Listar tus suscripciones de webhook | GET /v1/webhooks | webhooks:read |
| Suscribir un endpoint a eventos | POST /v1/webhooks | webhooks:write |
| Cancelar la suscripción de un endpoint | DELETE /v1/webhooks/{id} | webhooks:write |
¿Quieres recibir un aviso cuando un documento se firme, se rechace o se anule en lugar de sondear?
Usa webhooks — y toma el PDF final directamente del payload de
envelope.document_ready.
Convenciones
- JSON de entrada, JSON de salida — envía y espera
application/json. - Delimitado a tu empresa — cada recurso pertenece a una empresa y las peticiones nunca cruzan los límites entre empresas.
- Los mismos permisos que la app — una clave solo puede hacer lo que permite el rol de su propietario. Consulta Usuarios y roles.
- Los scopes restringen el acceso — los scopes de una clave (
templates:read,contacts:read,contacts:write,envelopes:send,webhooks:read,webhooks:write,users:read) solo pueden limitar lo que su propietario ya podía hacer, nunca ampliarlo.
Paginación
Los endpoints de listado aceptan page (desde 1) y per_page (hasta 100, por defecto 25), y
devuelven un objeto pagination:
{
"data": [ /* … */ ],
"pagination": { "page": 1, "per_page": 25, "total": 134, "total_pages": 6 }
}Cuotas
Las lecturas no consumen nada de tu plan. Hay dos cosas medidas:
- Enviar consume la asignación independiente de solicitudes de firma por API: una unidad
por sobre, sin importar cuántos destinatarios tenga. No es la misma bolsa que los sobres
enviados desde la app. Cuando se agota, los envíos devuelven
402 quota_exceededy no se entrega nada. - Crear un contacto consume la asignación ordinaria de contactos de tu plan y devuelve
403 quota_exceededcuando está llena. No necesitas crear contactos para enviarles documentos, así que es fácil de evitar.
Consulta ambas en Configuración → Facturación → Recursos.
Límites de frecuencia
Las peticiones se limitan por clave de API (el endpoint del token, por IP). Superar un límite
devuelve 429 rate_limited con una cabecera estándar Retry-After en segundos: espera ese
tiempo y reintenta.
| Límite | Alcance |
|---|---|
| 20 intercambios de token / 15 min | por IP |
| 100 envíos / 15 min | por clave de API |
| 1000 demás peticiones / 15 min | por clave de API |
Contar por clave (y no por IP) implica que una dirección de salida compartida —una plataforma de integración, un NAT— nunca hace que el tráfico de un cliente cuente contra el de otro.
Errores
Todos los errores tienen la misma forma: ramifica según error.code, nunca según el texto del
mensaje. Consulta la referencia de errores completa.
{
"error": {
"code": "unknown_signer_role",
"message": "…",
"details": { },
"reference": "0190f3a2-7b6c-7e21-9a3f-2c9b1d4e5f60"
}
}reference aparece en los errores que registramos en el servidor (5xx y 422). Guárdalo en tus
propios logs: citárnoslo localiza el fallo exacto con una sola consulta.