Developers
DocuFirma API
Bring advanced electronic signatures with a qualified timestamp into your software: create envelopes, track their status, download the signed documents and get notified by webhook.
Introduction
The API is REST, uses JSON for requests and responses, and is available to accounts with an active Pro plan. It uses your account's signatures and SMS, just like the web app.
Base URL: https://docufirma.es/api/v1
Authentication
Create a key in Settings → API and webhooks. It is shown only once: keep it in your secrets manager. Send it in the Authorization header with every request. You can have up to 5 active keys and revoke them at any time.
curl https://docufirma.es/api/v1/account \
-H "Authorization: Bearer df_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"First envelope in one call
Create the envelope with its signers and a base64 document (up to 3 MB) and send it at once with send: true. The response includes each signer's status and the verification code.
curl https://docufirma.es/api/v1/envelopes \
-H "Authorization: Bearer $DOCUFIRMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Contrato de servicios",
"message": "Hola Lucía, aquí tienes el contrato.",
"locale": "es",
"signers": [
{ "first_name": "Lucía", "last_name": "Gómez", "email": "lucia@example.com" }
],
"documents": [
{ "name": "contrato.pdf", "content_base64": "'"$(base64 -w0 contrato.pdf)"'" }
],
"send": true
}'{
"id": "6c36f47e-86d5-4693-b4f5-c5da17f37621",
"object": "envelope",
"status": "sent",
"title": "Contrato de servicios",
"verification_code": "DF-7K2M-9QXA",
"sent_at": "2026-11-03T10:15:02Z",
"expires_at": "2026-12-03T10:15:02Z",
"signers": [
{ "id": "…", "object": "signer", "email": "lucia@example.com", "status": "sent", … }
],
"documents": [
{ "id": "…", "object": "document", "name": "contrato.pdf", "page_count": 3, "sha256": "…" }
]
}Large documents
For files up to 25 MB, request an upload URL, send the file with PUT and complete the upload. DocuFirma validates the PDF (or converts the image) and computes its SHA-256 fingerprint.
# 1. Upload slot (valid for 2 hours)
curl -X POST https://docufirma.es/api/v1/envelopes/$ENVELOPE_ID/uploads \
-H "Authorization: Bearer $DOCUFIRMA_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "anexo.pdf", "size_bytes": 8421337 }'
# → { "id": "<upload_id>", "upload_url": "https://…", "method": "PUT", … }
# 2. Send the file
curl -X PUT "$UPLOAD_URL" -H "Content-Type: application/pdf" --data-binary @anexo.pdf
# 3. Complete
curl -X POST https://docufirma.es/api/v1/envelopes/$ENVELOPE_ID/uploads/$UPLOAD_ID/complete \
-H "Authorization: Bearer $DOCUFIRMA_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "anexo.pdf" }'
# 4. Send the envelope
curl -X POST https://docufirma.es/api/v1/envelopes/$ENVELOPE_ID/send -H "Authorization: Bearer $DOCUFIRMA_API_KEY"Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /account | Your account: plan, signatures and SMS available. |
| GET | /envelopes | Envelopes, newest first. Filter by status and paginate with limit and starting_after. |
| POST | /envelopes | Creates a draft envelope with optional signers and documents; with send: true it is sent right away. |
| GET | /envelopes/{id} | Envelope detail with signers and documents. |
| PATCH | /envelopes/{id} | Updates a draft. signers replaces the whole list. |
| DELETE | /envelopes/{id} | Deletes a draft and its documents. |
| POST | /envelopes/{id}/documents | Adds a base64 document (up to 3 MB) to a draft. |
| POST | /envelopes/{id}/uploads | Returns a signed URL to upload a large file with PUT. |
| POST | /envelopes/{id}/uploads/{upload_id}/complete | Validates the uploaded file and adds it to the draft. |
| POST | /envelopes/{id}/send | Sends the draft: reserves signatures and notifies the signers. |
| POST | /envelopes/{id}/cancel | Cancels a pending envelope and returns its reserved signatures. |
| POST | /envelopes/{id}/remind | Notifies pending signers again (at most once per hour). |
| GET | /envelopes/{id}/files | Temporary download URLs (5 min): originals and, once completed, signed PDFs, evidence certificate and timestamps. |
| GET | /envelopes/{id}/events | Full timeline of the envelope. |
| POST | /envelopes/{id}/signers/{signer_id}/signing-url | Signing link for an in-person signer. |
Statuses
An envelope goes draft → sent → viewed → completed, or ends as declined, expired or canceled. Each signer goes pending → sent → viewed → signed, or declined. After the last signature, completed arrives within seconds, once the PDFs are signed and timestamped.
Errors
Errors return an HTTP status and an error object with a stable code and a readable message. Validation errors include details with the affected field.
HTTP/1.1 402 Payment Required
{
"error": {
"code": "insufficient_credits",
"message": "Not enough signatures to send this envelope.",
"details": { "needed": 3, "available": 1 }
}
}- 400
- Malformed JSON.
- 401
- Missing, invalid or revoked key.
- 402
- Not enough signatures or SMS (insufficient_credits, sms_no_credits).
- 403
- No active Pro plan (subscription_required) or unconfirmed email.
- 404
- The resource does not exist or is not yours.
- 409
- The current status does not allow the operation (envelope_not_draft, not_cancelable).
- 413
- Document too large for an inline upload.
- 422
- Invalid data or unsupported document.
- 429
- Rate limit exceeded.
Limits and pagination
Each key allows 120 requests per minute; the X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers show your usage and, when exceeded, Retry-After says when to retry. Per envelope: up to 10 documents (25 MB each) and 10 signers. Lists return has_more; request the next page with starting_after set to the last item's id.
Webhooks
Set an HTTPS URL in Settings → API and webhooks to receive a POST on every status change. Reply with any 2xx; on failure we retry twice. Every request carries the DocuFirma-Signature header so you can check it comes from us.
- envelope.sent
- The envelope was sent to the signers.
- envelope.signed
- A signer signed (data.signer_id).
- envelope.completed
- Everyone signed and the PDFs are timestamped and ready.
- envelope.declined
- A signer declined to sign.
- envelope.expired
- The envelope expired before completion.
- envelope.canceled
- You canceled the envelope.
POST /webhooks/docufirma HTTP/1.1
Content-Type: application/json
DocuFirma-Signature: t=1793790902,v1=5f0c4e…
{
"id": "evt_9b1d…",
"object": "event",
"type": "envelope.completed",
"created_at": "2026-11-03T10:42:11Z",
"data": { "envelope": { "id": "6c36f47e-…", "status": "completed", … } }
}Verify the signature: compute the HMAC-SHA256 of “t.body” with your secret and compare it with v1. Reject messages whose t is older than 5 minutes.
import crypto from "node:crypto";
export function verifyDocuFirma(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}