Envelopes API
The envelopes API sends documents for signature from your own system. An envelope is what the app calls a signature request: the same thing, under its API name. It holds up to 10 documents, the people who sign or receive them, and the fields each signer fills.
AutomaDoc Sign records a simple electronic signature with an audit trail: who signed, when, from where, and the fingerprint (SHA-256) of every file. It is not a certificate-based digital signature. Some documents (wills, family matters, court filings) and some official systems need another form of signature, so check what yours requires.
Authentication
Section titled “Authentication”Every route takes a company API key (it starts with amk_), in either header:
X-Webhook-API-Key: amk_…Authorization: Bearer amk_…An admin creates company keys in the Company Portal, under Company → API keys (see the API quickstart). A template’s own key opens that one template, not your company’s envelopes: it is refused with API_KEY_INVALID. A key sees every envelope of its company, whether it was made through the API or in the portal, and nothing of another company (ENVELOPE_NOT_FOUND).
Two rate limits apply:
- 60 requests a minute per key, across all the envelope routes.
- 600 documents a minute per company, shared with the document API and the HTTP trigger. A create counts one per document in it.
Past either one the answer is 429 with RATE_LIMITED.
How an envelope goes out
Section titled “How an envelope goes out”POST /api/v1/envelopesstores your documents and answers201at once, with the envelope still adraftand each documentprepareState: "pending".- AutomaDoc prepares every document: Word, Excel and PowerPoint files become PDF, and the text is searched for your anchors and
[[…]]tags. A document still pending after 30 minutes fails astimeout. - Once the last document is ready, the fields from anchors and tags are placed and, with
send: true, the envelope is sent. Email recipients whose turn it is get their invitation. - Read
GET /api/v1/envelopes/:idto follow it. If it could not be sent, it stays adraftandsendErrorsays why.
The public API has no separate send call: an envelope created without send: true stays a draft. A draft that could not be sent cannot be retried through the API either; create a new envelope. Drafts nobody changes for 30 days are deleted.
Create an envelope
Section titled “Create an envelope”POST https://api.automadoc.cc/api/v1/envelopesSend the body as JSON (Content-Type: application/json, at most 14 MB), or as multipart/form-data with an envelope part holding the same JSON plus one part per file (at most 26 MB for the whole request).
| Field | Required | What it does |
|---|---|---|
title |
yes | Shown to the signers and in the emails. Up to 200 characters. |
message |
no | A note to the recipients, up to 1,000 characters. |
documents |
yes | 1 to 10 documents, in order (below). |
recipients |
yes | 1 to 20 recipients (below). |
fields |
no | Fields placed by coordinates (below). At most 500. |
anchors |
no | Fields placed relative to text in the documents (below). At most 50. |
autoTags |
no | true places fields from [[…]] tags written in the documents (below). |
send |
no | true sends the envelope as soon as the documents are prepared and the fields placed. Otherwise it stays a draft. |
locale |
no | The language of the emails and the signing page: en, zh, id, es, vi, th or ja. Anything else is ignored. |
timezone |
no | An IANA time zone (Asia/Jakarta) for dates written on the documents and the certificate. Default UTC. |
expiryDays |
no | Days from sending until the envelope expires: 1 to 120, default 30. |
reminders |
no | { "everyDays": 3, "max": 3 } (the default; everyDays 1 to 30, max 0 to 10), or false for none. |
appendCertificate |
no | Default true: each signed PDF ends with the certificate of completion. The certificate is always downloadable on its own too. |
Documents
Section titled “Documents”Each document is exactly one of:
| Field | What it is |
|---|---|
base64 |
The file’s bytes in base64 (a data: prefix is accepted). All base64 documents of a request may total at most 10 MB once decoded; send larger files as multipart. |
file |
The name of a part of the multipart request that holds the file. |
generationId |
A completed document AutomaDoc generated for your company (the generationId of the document API, or any other generated document still kept). Its file is copied into the envelope. |
name is optional: it defaults to the part’s file name, the generated file’s name, or “Document 1”, “Document 2”. A trailing .pdf, .docx, .xlsx or .pptx is dropped. Files may be PDF, Word, Excel or PowerPoint, recognised by their content, never by their name. Each file may be at most 25 MB, and an envelope’s files at most 50 MB together.
Recipients
Section titled “Recipients”| Field | Required | What it does |
|---|---|---|
key |
yes | Your own name for this recipient (client), used by fields and anchors and returned in every response. 1 to 60 letters, digits, _, - or ., unique in the request. |
role |
yes | signer (fills fields and signs) or cc (receives the signed result). |
name |
yes | Up to 120 characters. |
email |
with reach: "email" |
Where the invitation is sent. Optional for a link recipient. |
reach |
no | "email" (default): AutomaDoc emails the invitation when it is this recipient’s turn. "link": nothing is mailed, and the create response returns a signingUrl for you to deliver. |
routingOrder |
no | 1 to 100, default 1. Recipients with the same number sign in parallel; a higher number waits until every lower one has finished. |
accessCode |
no | 6 to 128 characters the recipient must type before they see the documents. Five wrong codes lock the link. Pass it to the recipient yourself, not in the same message as the link. |
slot |
no | With autoTags: the role name used in the tags (Client) this recipient fills. |
Fields by coordinates
Section titled “Fields by coordinates”| Field | Required | What it does |
|---|---|---|
document |
yes | The document’s index in documents, from 0. |
recipient |
yes | A recipient key. Only signers have fields. |
type |
yes | signature, initials, name, date_signed, text, checkbox, company or email. |
page |
yes | The page, from 1. |
x, y, w, h |
yes | Position and size in points (1/72 inch), measured from the top-left corner of the page as it is displayed (after any rotation). A field must be at least 8 points wide and high and lie inside the page. |
required |
no | Default true. |
label |
no | A hint shown to the signer, up to 100 characters. |
options |
no | For text fields: maxLength (1 to 1,000), validate ("number" or "email"), fontSize (6 to 72, shrinks to fit). |
name and email start with the recipient’s name and address, which the signer can change; date_signed is filled with the signing date, written in the envelope’s time zone. Pages and positions are checked against the prepared documents when the envelope is sent (field_bad_page, field_off_page), since a Word file has no pages until it is converted.
Fields by anchor text
Section titled “Fields by anchor text”An anchor places a field relative to text already in the document, so you do not need coordinates:
| Field | Required | What it does |
|---|---|---|
anchor |
yes | The text to find, up to 200 characters. Matching is exact and case-sensitive; any run of spaces or line breaks matches any other. |
recipient |
yes | A recipient key. |
type |
yes | A field type, as above. |
occurrence |
no | "all" (default: a field at every match, at most 200), or n for the n-th match only, counted across all the envelope’s documents in reading order. |
offsetX, offsetY |
no | Points from the top-left of the matched text to the top-left of the field (-2,000 to 2,000, default 0). Negative offsetY moves up. |
w, h |
no | The field’s size in points (8 to 1,000). Default: signature 160×48, initials 64×40, checkbox 14×14, date 110×20, email 180×20, other text 160×20. |
required, label |
no | As for fields by coordinates. |
A field that would run off the page is moved back onto it. An anchor that matches nothing makes no field, which usually shows up as signer_without_fields in sendError.
Fields from tags
Section titled “Fields from tags”With autoTags: true, tags written in the documents become fields for the recipient whose slot matches the tag’s role (exactly, case kept):
[[sign:Client]] [[initials:Client]] [[name:Client]] [[date:Client]][[text:Client:PO number]] [[check:Client]] [[company:Client]] [[email:Client]][[sign:Client;w=180;h=50]] [[text:Client:Notes;optional]]The field’s top-left corner is the tag’s top-left corner, so the field covers the tag. A tag whose role no recipient fills makes no field.
The response
Section titled “The response”201 Created with the envelope. Right after a create it is a draft whose documents are still being prepared:
{ "id": "env_01JAB3K9Q7M2X8R4T6V0W1Y2Z3", "status": "draft", "finishing": false, "finalizeFailed": false, "title": "Service agreement ACME-2026-114", "createdAt": 1792290600000, "sentAt": null, "expiresAt": null, "completedAt": null, "documents": [ { "id": "doc_01JAB3K9RA5C7E9G1H3J5K7M9N", "name": "Service agreement", "prepareState": "pending", "prepareError": null, "pageCount": null, "originalSha256": "3b7e0c…", "preparedSha256": null, "finalSha256": null, "deliveredSha256": null } ], "recipients": [ { "id": "rcp_01JAB3K9R2B4D6F8H0J2K4M6P8", "key": "client", "role": "signer", "name": "Dana Lee", "email": "dana@example.com", "status": "created", "routingOrder": 1, "viewedAt": null, "completedAt": null, "declineReason": null } ], "auditHead": "a41f9d…", "sendError": null}A recipient with reach: "link" also has a signingUrl (https://sign.automadoc.cc/#/…) in this response only: no later read returns it, so store it now. The link starts working when the envelope is sent. Each email invitation and reminder carries a fresh link, so a link recipient is never reminded by email.
Read an envelope
Section titled “Read an envelope”GET https://api.automadoc.cc/api/v1/envelopes/{envelopeId}Answers the same shape as the create, as of now. Poll it every few seconds while the documents prepare; once the envelope is out, polling every few minutes is plenty.
status |
Meaning |
|---|---|
draft |
Not sent: documents preparing, send not asked, or sendError says why it could not go. |
sent |
Out for signature. |
completed |
Everyone signed and the signed files are ready. |
declined |
A signer declined; their declineReason is on their recipient. |
voided |
You voided it. |
expired |
expiresAt passed before everyone signed. |
finishing: true (with status: "sent") means everyone has signed and the signed PDFs are being made. finalizeFailed: true means they could not be made after every retry: the signatures are kept and our team was alerted.
Recipients go created (not yet their turn), sent, viewed, then completed or declined. A cc recipient is sent from the start.
Each document carries the SHA-256 of every stage: originalSha256 (your file), preparedSha256 (the PDF everyone saw and signed), finalSha256 (stamped with the signatures) and deliveredSha256 (the file you download: stamped, plus the certificate when appended). auditHead is the hash of the last event in the envelope’s audit trail. Anyone can check a delivered file with POST https://api.automadoc.cc/api/verify and { "sha256": "…" } (lower-case hex of the whole file), which answers whether it matches a completed envelope.
List envelopes
Section titled “List envelopes”GET https://api.automadoc.cc/api/v1/envelopes?status=completed&since=1792290600000&limit=50| Query | What it does |
|---|---|
status |
draft, sent, completed, declined, voided or expired. |
since |
Only envelopes updated at or after this time (Unix ms). |
limit |
1 to 100, default 25. |
cursor |
The nextCursor of the previous page. |
The answer is { "envelopes": [ … ], "nextCursor": "…" }, newest first; nextCursor is null on the last page. key is null for recipients of envelopes made in the portal.
Download the signed files
Section titled “Download the signed files”GET https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/documents/{documentId}/signedGET https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/certificateGET https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/combinedsigned is one signed document; certificate is the certificate of completion on its own; combined is every signed document in one PDF (with the certificate at the end when appended), made only for envelopes of two or more documents. These work once the envelope is completed: before, they answer 409 with DOCUMENT_NOT_FOUND.
The answer is a short-lived link, not the file:
{ "url": "https://api.automadoc.cc/api/esign-files/env_01JAB3K9Q7M2X8R4T6V0W1Y2Z3/final/doc_01JAB3K9RA5C7E9G1H3J5K7M9N.pdf?e=…&d=a&n=…&s=…", "filename": "Service agreement.pdf", "expiresAt": 1792306800000, "sha256": "e5a01c…"}Fetch url within 15 minutes; it needs no key. Ask again for a fresh one. sha256 is the file’s fingerprint (for signed, the document’s deliveredSha256). Every download is recorded in the audit trail. Signed files of a completed envelope are kept until someone deletes them.
Void an envelope
Section titled “Void an envelope”POST https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/void{ "reason": "Replaced by version 2" }Stops a sent envelope: the links stop working, and recipients who had already been sent it are told by email. reason is required (up to 500 characters). Answers the envelope, now voided. Only a sent envelope that is still open can be voided.
Remind a recipient
Section titled “Remind a recipient”POST https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/recipients/{recipientId}/remindrecipientId is the recipient’s id (rcp_…), not your key. Emails the recipient a fresh link at once; the link in earlier emails stops working. Only for an email recipient whose turn it is, at most once every 10 minutes. Answers { "remindedAt": 1792300000000, "channel": "email" }. Automatic reminders follow the envelope’s reminders setting without any call.
Example: curl
Section titled “Example: curl”Create an envelope with one signer, place the signature next to the text “Client signature:” and the date next to “Date:”, and send it. The JSON goes in the envelope part and the PDF in a part named contract:
cat > envelope.json <<'EOF'{ "title": "Service agreement ACME-2026-114", "message": "Please review and sign by Friday.", "timezone": "Asia/Jakarta", "documents": [{ "name": "Service agreement", "file": "contract" }], "recipients": [ { "key": "client", "role": "signer", "name": "Dana Lee", "email": "dana@example.com" } ], "anchors": [ { "anchor": "Client signature:", "recipient": "client", "type": "signature", "offsetX": 110, "offsetY": -10 }, { "anchor": "Date:", "recipient": "client", "type": "date_signed", "offsetX": 40, "occurrence": 1 } ], "send": true}EOF
curl -X POST 'https://api.automadoc.cc/api/v1/envelopes' \ -H "X-Webhook-API-Key: $AUTOMADOC_KEY" \ -F 'envelope=<envelope.json' \ -F 'contract=@contract.pdf;type=application/pdf'Follow it until status is sent (or sendError is set), then until it is completed:
curl -s 'https://api.automadoc.cc/api/v1/envelopes/ENVELOPE_ID' \ -H "X-Webhook-API-Key: $AUTOMADOC_KEY"Once it is completed, get the signed document’s link and download it:
url=$(curl -s 'https://api.automadoc.cc/api/v1/envelopes/ENVELOPE_ID/documents/DOCUMENT_ID/signed' \ -H "X-Webhook-API-Key: $AUTOMADOC_KEY" | jq -r .url)curl -s -o signed.pdf "$url"The same create as JSON puts the file in base64 instead: "documents": [{ "name": "Service agreement", "base64": "JVBERi0xLjcK…" }].
Example: Node.js
Section titled “Example: Node.js”Node.js 18 or later. Run with AUTOMADOC_KEY=amk_… node sign.mjs:
import { readFile, writeFile } from 'node:fs/promises'import { createHash } from 'node:crypto'
const API = 'https://api.automadoc.cc'const KEY = process.env.AUTOMADOC_KEY
async function call(method, path, body) { const res = await fetch(API + path, { method, headers: body ? { 'X-Webhook-API-Key': KEY, 'Content-Type': 'application/json' } : { 'X-Webhook-API-Key': KEY }, body: body ? JSON.stringify(body) : undefined, }) const json = await res.json() if (!res.ok) throw new Error(`${res.status} ${json.code}: ${json.error}`) return json}
const pdf = await readFile('contract.pdf')let envelope = await call('POST', '/api/v1/envelopes', { title: 'Service agreement ACME-2026-114', documents: [{ name: 'Service agreement', base64: pdf.toString('base64') }], recipients: [{ key: 'client', role: 'signer', name: 'Dana Lee', email: 'dana@example.com' }], anchors: [{ anchor: 'Client signature:', recipient: 'client', type: 'signature', offsetX: 110, offsetY: -10 }], send: true,})
// The documents are prepared and the fields placed, then the envelope is sent.while (envelope.status === 'draft' && !envelope.sendError) { await new Promise((resolve) => setTimeout(resolve, 2000)) envelope = await call('GET', `/api/v1/envelopes/${envelope.id}`)}if (envelope.sendError) throw new Error(`Not sent: ${JSON.stringify(envelope.sendError)}`)console.log(`${envelope.id} is ${envelope.status}`)
// Later (a scheduled job, say): download every signed document of a completed envelope.export async function downloadSigned(envelopeId) { const current = await call('GET', `/api/v1/envelopes/${envelopeId}`) if (current.status !== 'completed') return false for (const doc of current.documents) { const link = await call('GET', `/api/v1/envelopes/${envelopeId}/documents/${doc.id}/signed`) const bytes = Buffer.from(await (await fetch(link.url)).arrayBuffer()) if (createHash('sha256').update(bytes).digest('hex') !== link.sha256) throw new Error('Download damaged') await writeFile(`${doc.id}.pdf`, bytes) } return true}Errors
Section titled “Errors”Errors are JSON: { "code": "…", "error": "English text" }, with path naming the part of the request at fault (recipients[1].email) when there is one.
| HTTP | code |
When |
|---|---|---|
| 400 | INVALID_REQUEST |
The request is not valid; see path and error. |
| 401 | API_KEY_MISSING |
No key in X-Webhook-API-Key or Authorization. |
| 403 | API_KEY_INVALID |
The key is unknown or revoked, or it is a template’s own key. |
| 403 | ESIGN_SEND_BLOCKED |
Remind: sending is paused for your company while a report about its emails is reviewed. Contact support. |
| 404 | ENVELOPE_NOT_FOUND |
No such envelope in your company. |
| 404 | RECIPIENT_NOT_FOUND |
Remind: no such recipient in this envelope. |
| 404 | DOCUMENT_NOT_FOUND |
Download: no such document, or no such file (a combined file for a one-document envelope). |
| 404 | GENERATION_NOT_FOUND |
A generationId that is not a generated document of your company. |
| 409 | GENERATION_NOT_COMPLETED |
The generated document is not completed, or no longer kept. |
| 409 | DOCUMENT_NOT_FOUND |
Download before the envelope is completed. |
| 409 | ENVELOPE_NOT_DRAFT |
Void or remind on an envelope that was never sent. |
| 409 | ENVELOPE_CLOSED |
Void or remind on a completed, declined, voided or expired envelope. |
| 409 | ENVELOPE_FINISHING |
Void or remind after everyone signed, while the signed files are being made. |
| 409 | NOT_ALLOWED |
Remind a recipient whose turn it is not, or a link recipient. |
| 410 | ENVELOPE_CLOSED |
Download after the envelope’s files were deleted. |
| 413 | FILE_TOO_LARGE |
A file over 25 MB, or a multipart request over 26 MB. |
| 413 | ENVELOPE_TOO_LARGE |
The base64 documents total over 10 MB, or the files over 50 MB. |
| 413 | INVALID_REQUEST |
A JSON body over 14 MB. |
| 415 | UNSUPPORTED_FILE |
A file that is not a PDF, Word, Excel or PowerPoint file. |
| 429 | RATE_LIMITED |
Over 60 requests a minute for the key, or 600 documents a minute for the company. |
| 429 | ESIGN_SEND_RATE_LIMITED |
Remind: this recipient was reminded less than 10 minutes ago. |
| 502 | ESIGN_WORKER_UNAVAILABLE |
Remind: the reminder could not be delivered. |
| 503 | ESIGN_WORKER_UNSUPPORTED |
Documents cannot be prepared for signature right now. Try again later; nothing was created. |
A create refused while its documents are being stored deletes the draft and its files, so nothing half-made is left.
Why an envelope was not sent
Section titled “Why an envelope was not sent”With send: true, sending happens after the create has answered, so its refusals arrive in sendError of the envelope (which stays a draft), not as an HTTP status:
sendError.code |
Meaning |
|---|---|
SEND_PROBLEMS |
The envelope is not complete; problems lists why (below). |
QUOTA_EXCEEDED |
The monthly allowance and every document pack are used up (see what it costs). |
ESIGN_SEND_RATE_LIMITED |
Free: your company already sent 3 envelopes in the last hour. On any plan: more than 10 sends in one minute. |
ESIGN_RECIPIENT_CAP |
This send would pass the recipients a day your company may reach (below). |
ESIGN_SEND_BLOCKED |
Sending is paused for your company while a report about its emails is reviewed. Contact support. |
ESIGN_EMAIL_UNAVAILABLE |
Email cannot be sent for this envelope. Nothing was sent or charged; recipients with reach: "link" can still be used. |
ESIGN_EMAIL_UNVERIFIED |
The person who created the key has no verified email address. |
ESIGN_ALREADY_PENDING |
This generated document is already out for signature in another envelope. |
INVALID_REQUEST |
The tags and anchors together made more than 500 fields, or something unexpected went wrong. |
Each problem is { "code": "…" }, with documentId, recipientId or fieldId when it is about one of them (ids, not your keys):
| Problem | Meaning |
|---|---|
document_failed |
A document could not be prepared; its prepareError says why (below). |
too_many_pages |
More than 300 pages across the documents. |
envelope_too_large |
The files total more than 50 MB, or the prepared PDFs more than 100 MB. |
no_signer |
No recipient has the role signer. |
signer_without_fields |
A signer has no field: an anchor matched nothing, or a tag’s role had no slot. |
recipient_missing_email |
An email recipient has no address. |
recipient_role_unavailable |
A role other than signer or cc. |
too_many_fields |
More than 500 fields. |
field_for_non_signer |
A field was given to a cc recipient. |
field_bad_page |
A field’s page is past the end of its document. |
field_off_page |
A field runs off its page, or is smaller than 8 points. |
field_type_unavailable |
A field type other than the eight listed above. |
A document’s prepareError is one of pdf_encrypted (the PDF is password-protected), file_too_large (its prepared PDF would pass 50 MB), too_many_pages, unsupported_file, invalid_file (the file is damaged), conversion_failed, source_unavailable, timeout or internal.
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Documents per envelope | 10 |
| One file | 25 MB |
| Files of one envelope together | 50 MB |
| One prepared document (the PDF everyone signs) | 50 MB |
| Prepared documents of one envelope together | 100 MB |
| Pages across an envelope’s documents | 300 |
| Recipients per envelope | 20 |
| Fields per envelope | 500 |
| Anchors per request | 50, each matching at most 200 times |
| JSON request body | 14 MB, with at most 10 MB of base64 documents |
| Multipart request | 26 MB |
| Expiry | 1 to 120 days after sending, default 30 |
| Reminders | every 1 to 30 days, at most 10; default every 3 days, 3 times |
| Wrong access codes before a link locks | 5 |
| Download links | 15 minutes |
| Drafts | deleted after 30 days without a change |
| Files of declined, voided and expired envelopes | deleted 90 days after closing |
To send more than 26 MB of files, add them by generationId, which does not travel in the request.
Sending caps. Without Pro and without a Business seat, a company sends at most 3 envelopes an hour and reaches at most 20 recipients a day (5 a day in the account’s first 24 hours). With Pro or a Business seat, it reaches up to 1,000 recipients a day. Every recipient counts, cc and link recipients included, over a rolling 24 hours. Every company sends at most 10 envelopes a minute.
What it costs
Section titled “What it costs”- A sent envelope uses one document from your allowance, however many documents and recipients it holds. It is charged when it is sent and not given back if it is later voided, declined or expired. A draft costs nothing.
- Documents AutomaDoc generated are free to send the first time: an envelope whose documents all come from
generationIdcosts nothing, unless one of them was already sent in another envelope; then it costs one document. An envelope that mixes generated and uploaded files costs one. - What pays. An envelope sent with a company key is automated, like the document API: free with Pro (or a trial); otherwise counted against your Business seats’ automation allowance first, then the free monthly allowance, then your document packs. When all are used up,
sendErrorisQUOTA_EXCEEDED. A Starter seat belongs to a person and does not cover API sends.
The sending caps above apply on every plan.