DenSign API & Webhooks
Send documents for signature, track them, download the certified PDF, and get real-time completion events — all over a simple REST API. Available on the Business plan.
Authentication
Authenticate every request with your API key in the X-DenSign-Key header
(or ?api_key= query param). Keep it secret — treat it like a password.
curl https://sign.dendat.ai/api/v1/documents \
-H "X-DenSign-Key: YOUR_API_KEY"
401 Unauthorized.Base URL
https://sign.dendat.ai
Send a document for signature
Upload a PDF and one or more signers. DenSign auto-detects fields, emails each signer a
secure link, and (optionally) calls your webhook on completion. multipart/form-data.
| Field | Req | Description |
|---|---|---|
file | yes | The PDF to be signed |
title | no | Document title (defaults to filename) |
signer_name | yes | First signer's name |
signer_email | yes | First signer's email |
message | no | Note included in the signing email |
webhook_url | no | URL to POST when the document is completed |
curl -X POST https://sign.dendat.ai/api/v1/send \
-H "X-DenSign-Key: YOUR_API_KEY" \
-F "[email protected]" \
-F "title=Service Agreement" \
-F "signer_name=Jane Doe" \
-F "[email protected]" \
-F "webhook_url=https://yourapp.com/hooks/densign"
Response 201 Created
{
"success": true,
"document_id": 123,
"status": "sent",
"signing_url": "https://sign.dendat.ai/sign/<token>"
}
Get a document
Returns the document, its status, signers, and fields. Related:
GET /api/v1/document/{id}/fields.
Download the signed PDF
Returns the completed, certified PDF (with the appended certificate page). Available once
status = completed.
Audit trail
Full, timestamped audit log — viewed, signed, completed, reminders — for legal evidence.
List documents
Paginated list of your documents, filterable by status.
Bulk send
Send the same document to many recipients in one call. See also
POST /api/v1/document/{id}/bulk-remind to nudge all pending signers.
Webhooks
Set webhook_url when sending. When every signer completes, DenSign
POSTs a JSON event to your URL:
POST https://yourapp.com/hooks/densign
X-DenSign-Event: document.completed
X-DenSign-Signature: t=1720080000,v1=<hmac-sha256-hex>
{
"id": "evt_...",
"event": "document.completed",
"created": 1720080000,
"document_id": 123,
"title": "Service Agreement",
"status": "completed",
"completed_at": "2026-07-04T09:00:00",
"signed_file_hash": "3f9a2c...",
"certificate_url": "https://sign.dendat.ai/verify?hash=3f9a2c...",
"signers": [{ "name": "Jane Doe", "email": "[email protected]", "status": "signed", "signed_at": "..." }]
}
Respond 2xx to acknowledge. DenSign retries once on failure.
Verifying the webhook signature
Every webhook is signed so you can confirm it genuinely came from DenSign and was not tampered
with. The X-DenSign-Signature header is t=<timestamp>,v1=<signature>,
where the signature is HMAC-SHA256 of "{timestamp}.{raw_body}" using your
webhook signing secret.
Python
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
expected = hmac.new(secret.encode(),
f'{parts["t"]}.{raw_body.decode()}'.encode(),
hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
Node.js
const crypto = require("crypto");
function verify(rawBody, header, secret) {
const p = Object.fromEntries(header.split(",").map(s => s.split("=")));
const expected = crypto.createHmac("sha256", secret)
.update(`${p.t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(p.v1));
}
Public document verification
Anyone holding a signed DenSign PDF can confirm it is authentic and unaltered — no account needed — at https://sign.dendat.ai/verify by entering the SHA-256 content hash printed on the certificate page. Great for counterparties, banks, and auditors.
Need an API key or higher limits? Upgrade to Business or email [email protected].