Quickstart
Mint a test key, make your first call, and send a document for signature in about ten minutes.
All documentation
This ends with a document you can actually sign. Nothing here touches real email or your plan allowance, because every step runs on a test key.
Mint a test key
In the web app, as a workspace admin, open Settings, Developer, API keys, and create a key in Test mode. The secret is shown once. Only a hash is stored, so there is no way to reveal it later.
ESIGN_API_KEY=sk_test_...
ESIGN_API_BASE=https://api.documentesign.com/v1NEXT_PUBLIC_, VITE_ or REACT_APP_. If one leaks, revoke it in the same screen - revocation takes effect on the next request.Prove the key works
GET /account is the cheapest call that confirms everything at once: the key is valid, the plan allows API access, and you can see which mode you are in.
curl https://api.documentesign.com/v1/account \
-H "Authorization: Bearer $ESIGN_API_KEY"{
"organization": { "id": "org_...", "name": "Acme Inc" },
"plan": { "code": "business", "trialing": false },
"mode": "TEST",
"usage": {
"documents_used": 0,
"documents_included": 40,
"documents_billable": 0,
"overage_amount_cents": 0,
"period_start": "2026-09-01T00:00:00.000Z",
"period_end": "2026-10-01T00:00:00.000Z"
}
}Check that modeis what you expected. A surprising share of "the document vanished" reports are a live key looking for a sandbox document.
Upload a file
Documents are built from uploaded files. This is a multipart request, not JSON.
curl https://api.documentesign.com/v1/files \
-H "Authorization: Bearer $ESIGN_API_KEY" \
-F "file=@nda.pdf"{
"id": "file_9f2c...",
"name": "nda.pdf",
"mime_type": "application/pdf",
"size_bytes": 48210,
"created_at": "2026-09-01T10:00:00.000Z"
}Create and send
Hold on to the file id and build a document around it. Every signer needs at least one signature field or the send is rejected, so place one while you are here. Coordinates are normalised: 0,0 is the top left of the page and 1,1 the bottom right.
curl https://api.documentesign.com/v1/documents \
-H "Authorization: Bearer $ESIGN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "NDA - Acme",
"files": ["file_9f2c..."],
"recipients": [
{ "name": "Sam Rivera", "email": "sam@example.com", "type": "signer" }
],
"fields": [
{ "type": "SIGNATURE", "pageNumber": 1,
"xNorm": 0.1, "yNorm": 0.8, "widthNorm": 0.25, "heightNorm": 0.06 }
],
"send": true
}'{
"id": "doc_7a1b...",
"status": "in_progress",
"title": "NDA - Acme",
"mode": "TEST",
"recipients": [
{ "id": "rcp_3d9e...", "name": "Sam Rivera",
"email": "sam@example.com", "role": null, "status": "sent" }
],
"created_at": "2026-09-01T10:00:05.000Z"
}Store id against your own record now. Without it you cannot check status later, download the signed PDF, or match an incoming webhook to the right row.
Collect the result
Once everyone has signed, the sealed PDF and the audit certificate are available as short-lived download URLs.
curl https://api.documentesign.com/v1/documents/doc_7a1b.../files/signed \
-H "Authorization: Bearer $ESIGN_API_KEY"{ "url": "https://...", "expires_in": 600 }Polling for that is fine while you are building. In production, listen for the document.completed webhook instead and fetch the file when it arrives.
Going live
Mint a sk_live_ key in the same screen and change ESIGN_API_KEY. Nothing else moves: the base URL and every endpoint are identical between the two modes. Live documents email real recipients and count against your plan, so make sure your loop conditions are right before you flip it.