eSign
Send a PDF to one or more people. Each confirms a code from their email and signs. You get back a sealed PDF and a completion certificate.
How it works
- You send a PDF, the signers and where each one signs.
- Finovel emails the first signers a link. Everyone with the lowest
orderis asked first, then the next, and so on. - Each signer confirms a code sent to their email, reads the document and signs, or declines.
- When the last person signs, Finovel seals the PDF and tells you, by webhook if you have one.
Sending an envelope
curl -X POST https://api.finovel.in/v1/esign/envelopes \
-H "Authorization: Bearer fin_test_your_key" \
-H "Idempotency-Key: agreement-48213" \
-F "file=@agreement.pdf" \
-F 'envelope={
"title": "Loan agreement",
"expiresInDays": 14,
"signers": [
{ "name": "Asha Rao", "email": "asha@example.com", "order": 1,
"fields": [{ "page": 1, "x": 0.1, "y": 0.75, "width": 0.3, "height": 0.08, "type": "signature" }] },
{ "name": "Ravi Menon", "email": "ravi@example.com", "order": 2,
"fields": [{ "page": 1, "x": 0.55, "y": 0.75, "width": 0.3, "height": 0.08, "type": "signature" }] }
]
}'{
"id": "env_...",
"title": "Loan agreement",
"status": "sent",
"environment": "sandbox",
"expires_at": "2026-11-15T09:30:00.000Z",
"signers": [
{ "id": "sgn_...", "name": "Asha Rao", "order": 1, "method": "simple", "status": "invited", "signed_at": null },
{ "id": "sgn_...", "name": "Ravi Menon", "order": 2, "method": "simple", "status": "waiting", "signed_at": null }
]
}A PDF can be up to 20 MB and 99 pages, and cannot have a password, form fields or existing signatures. An envelope can have up to 20 signers and 100 fields. Send an Idempotency-Key so a retry returns the same envelope.
Placing fields
Pages count from 1. x, y, width and height are fractions of the page, measured from its top left corner. Each signer needs at least one signature field.
The other types are initials, date and name, filled in for the signer, and text, which the signer types. You can set label and required on a field.
Calls
| Call | What it does |
|---|---|
POST /v1/esign/envelopes | Create and send an envelope. Send the PDF as file and the details as envelope (JSON). |
GET /v1/esign/envelopes/{id} | See its status and who has signed. |
POST /v1/esign/envelopes/{id}/void | Cancel it. Send a JSON body with a reason. |
GET /v1/esign/envelopes/{id}/document | Download the signed PDF, once it is completed. |
GET /v1/esign/envelopes/{id}/certificate | Download the completion certificate, once it is completed. |
Status
status | Meaning |
|---|---|
sent | Waiting for signatures. |
completed | Everyone has signed, and the signed PDF is ready. |
declined | A signer declined. |
expired | The signing period ended first. |
voided | You cancelled it. |
Subscribe to esign.envelope.completed, esign.envelope.declined and esign.envelope.expired with a webhook instead of asking repeatedly.
Charges
You are charged per signature. Sending an envelope holds the price of one signature for each signer, and fails with 402 if your wallet cannot cover them all.
Each signature is charged when it is made. If an envelope is declined, expires or is cancelled, the holds of people who had not signed are released, and signatures already made stay charged.
Sandbox
With a fin_test_ key, envelopes work the same way and cost nothing. Every page is marked as not valid, and signers are told it is a test.
Aadhaar OTP signing works in sandbox only, against a test provider, with "method": "aadhaar" on a signer. Its code is always 123456.