Getting started
Create a key, send your first document in test mode, and watch the events arrive. About ten minutes end to end.
Updated
On this page
This walks you from nothing to a signed document. Everything here runs against a sandbox key, so emails are marked as test documents, documents are watermarked, and nothing is billed. Use email addresses you control.
1. Get a key
Create an account and choose Light or above for API access, then open Settings → API keys and create a key. Sandbox keys are prefixed sk_test_, live keys sk_live_. Use the sandbox one for everything below.
The key identifies both your workspace and the mode. There is no separate “test mode” flag to remember and no environment variable to get wrong — if the key starts with sk_test_, the request is a test request.
2. Send a document
Signclad fetches your file from a URL, so a presigned S3 link, a public URL, or anything your server can hand out for a few minutes all work. You can also upload the bytes with POST /files first and pass the returned file_id. Documents and templates take PDF, .doc and .docx — up to 20 files per document, 25 MB each.
curl -X POST https://api.signclad.com/api/v1/documents \
-H "X-Api-Key: $SIGNCLAD_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "Loan agreement",
"subject": "Please sign your loan agreement",
"message": "<p>Two signatures, about a minute.</p>",
"reminders": true,
"expires_in": 30,
"metadata": { "loan_id": "48213" },
"files": [
{ "name": "loan-agreement.pdf",
"file_url": "https://files.example.com/loan-agreement.pdf?X-Amz-Expires=7200" }
],
"recipients": [
{ "id": "signer-1", "name": "Jane Doe", "email": "[email protected]" }
],
"fields": [[
{ "api_id": "borrower_signature", "type": "signature", "recipient_id": "signer-1",
"page": 1, "x": 375, "y": 206, "width": 180, "height": 44, "required": true },
{ "api_id": "borrower_date", "type": "date", "recipient_id": "signer-1",
"page": 1, "x": 375, "y": 262, "width": 120, "height": 24,
"lock_sign_date": true, "date_format": "MM/DD/YYYY" }
]]
}'
The same call from Node (18+, no dependencies) and from Python with requests:
import { randomUUID } from 'node:crypto';
const body = {
name: 'Loan agreement',
subject: 'Please sign your loan agreement',
files: [
{ name: 'loan-agreement.pdf', file_url: 'https://files.example.com/loan-agreement.pdf' },
],
recipients: [{ id: 'signer-1', name: 'Jane Doe', email: '[email protected]' }],
fields: [[
{ api_id: 'borrower_signature', type: 'signature', recipient_id: 'signer-1',
page: 1, x: 375, y: 206, width: 180, height: 44, required: true },
]],
};
const response = await fetch('https://api.signclad.com/api/v1/documents', {
method: 'POST',
headers: {
'X-Api-Key': process.env.SIGNCLAD_API_KEY,
'Idempotency-Key': randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const document = await response.json();
console.log(document.id, document.status); // "Created" — the transient value
import os
import uuid
import requests
body = {
"name": "Loan agreement",
"subject": "Please sign your loan agreement",
"files": [
{"name": "loan-agreement.pdf", "file_url": "https://files.example.com/loan-agreement.pdf"}
],
"recipients": [{"id": "signer-1", "name": "Jane Doe", "email": "[email protected]"}],
"fields": [[
{"api_id": "borrower_signature", "type": "signature", "recipient_id": "signer-1",
"page": 1, "x": 375, "y": 206, "width": 180, "height": 44, "required": True}
]],
}
response = requests.post(
"https://api.signclad.com/api/v1/documents",
headers={
"X-Api-Key": os.environ["SIGNCLAD_API_KEY"],
"Idempotency-Key": str(uuid.uuid4()),
},
json=body,
timeout=30,
)
response.raise_for_status()
document = response.json()
print(document["id"], document["status"]) # "Created" — the transient value
Two things about the response will look wrong if you are not expecting them, and both are deliberate:
statusisCreated, whatever you passed fordraft. It is a transient value. The settled status —DraftorSent— appears on the nextGET.files[].pages_numberis0andfiles[].statusis not yetready— it readsuploaded, thenprocessing. Ingest has not finished. The real page count arrives on the nextGET.
Signing URLs in the response are valid immediately, so you can hand a recipient their link before ingest finishes.
3. Read it back
curl https://api.signclad.com/api/v1/documents/8f14e45f-ea8f-4b2c-9f0e-1b2c3d4e5f60 \
-H "X-Api-Key: $SIGNCLAD_API_KEY"
Once the send job has run, status is Sent, pages_number is real, files[].status is ready, and each recipient carries a status of its own. Read it immediately after the create and you may still catch Created or Sending. Fields come back grouped by type rather than in the order you sent them, and width and height are decimal strings while x, y, and page stay numbers. That is the compatibility contract, quirks included.
4. Sign it
Test mode emails the recipients with a clear test notice. Open the link in the email or the recipient’s embedded_signing_url and sign the watermarked test document. If you lose the URL, mint a new one rather than recreating the document:
curl -X POST \
https://api.signclad.com/api/v1/documents/{id}/recipients/signer-1/signing_url \
-H "X-Api-Key: $SIGNCLAD_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "expires_in_minutes": 60 }'
5. Watch the events
Create a webhook endpoint pointed at your receiver — or at the hosted inbox in Settings → Webhooks, which records requests so you can look at real payloads before writing any code.
curl -X POST https://api.signclad.com/api/v1/webhook_endpoints \
-H "X-Api-Key: $SIGNCLAD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/webhooks/signclad",
"description": "Local development",
"event_types": ["document_sent", "document_viewed", "document_signed", "document_completed"],
"include_test_mode": true,
"verify": true
}'
verify: true sends a ping before the endpoint goes live and shows you the result: the endpoint starts paused and only activates if your receiver answers 2xx. Without it the endpoint is active immediately and nothing is pinged. Note include_test_mode too — without it, test-mode documents produce no deliveries.
6. Download the evidence
When every signer has finished:
curl -L https://api.signclad.com/api/v1/documents/{id}/completed_pdf \
-H "X-Api-Key: $SIGNCLAD_API_KEY" -o completed.pdf
Before that, this endpoint returns 404 — not 403, and not an empty 200. It is the one place where a 404 does not mean “no such document”.
The completed PDF carries the audit page and a digital seal using a self-issued certificate. audit_trail_url on the document gives you the same evidence as signed JSON.
Common questions
Which languages does the Signclad eSignature API support?
Any language that can make an HTTPS request. Signclad is a plain REST API — JSON in, JSON out, one
X-Api-Key header — so curl, Node’s fetch, Python’s requests, PHP’s Guzzle, Ruby’s Net::HTTP,
and Go’s net/http all work without a library. The samples above are Node and Python; the
API reference gives the request shape for every operation, and
the OpenAPI document generates a typed client for most languages.
There is no published Signclad SDK package yet.
Why is status still Created after I sent the document?
Because the create and send responses answer with a transient status, deliberately: POST /documents
answers Created and POST /documents/{id}/send answers Draft, whatever you passed. The settled
status — Draft, Sent, Completed — appears on the next GET /documents/{id}. Never branch on
the status in a create response; read the document back, or wait for the webhook.
Does test mode send real email?
Yes. A sandbox key (sk_test_) delivers real messages to the recipients, marked as a test and
watermarked as not legally binding, and never bills. That means a send to an address you do not
control really bounces. Use addresses you own, or set embedded_signing: true — which already
defaults every recipient’s send_email to false — to get signing links without any mail at all.
See Sandbox and test mode.
What to read next
- Authentication and keys — key types, rotation, and scopes.
- Sandbox and test mode — what test mode does and does not do.
- Creating a document — every option on the create call.
- Webhooks — signatures, health, and replay.
- Errors and rate limits — the exact error shapes.