Signit API
Automate sending from your own systems. Base URL https://www.pdfsignit.com/api/v1. JSON in, JSON out. Available on Team, Business, Enterprise and the free trial.
Authentication
Create a key in Settings → API & webhooks and send it as a bearer token. Keys are shown once and stored hashed.
Authorization: Bearer sk_live_…
GET /api/v1/me
→ { "email": "ops@example.com", "plan": "business", "documents_this_month": 42, "documents_limit": 90 }
Concepts
- Template — a PDF with fields placed for one or more roles (e.g. Employee, Manager). Build it once in the app.
- Document — one instance of a template (or a raw PDF) with real signers. Status:
draft → sent → completed, orvoided. - Pre-fill — text/date/checkbox fields whose label you set on the template can be filled by the API before sending.
- external_id — your own reference (ticket number, employee ID). Searchable in the app and returned in every payload.
Create a document
POST /documents — from a template (JSON) or from a PDF (multipart). Add "send": true to send immediately; otherwise it's created as a draft you can send later.
POST /api/v1/documents
Content-Type: application/json
{
"template_id": "kQ3f9zLm2A7b",
"title": "Uniform Agreement — Jordan Smith", // optional, defaults to template name
"signers": [
{ "role": "Employee", "name": "Jordan Smith", "email": "jordan@example.com" }
],
"prefill": { "Employee number": "10482", "Site": "Burnaby HQ", "Items issued": "2× Polo, 1× Jacket" },
"external_id": "QM-TICKET-3391",
"metadata": { "employee_id": 10482, "ticket": 3391 }, // any JSON, echoed back
"message": "Please sign to confirm receipt of your uniform.",
"send": true
}
201 Created
{
"id": "Ej0UFKUMpgW0vK",
"title": "Uniform Agreement — Jordan Smith",
"status": "sent",
"external_id": "QM-TICKET-3391",
"metadata": { "employee_id": 10482, "ticket": 3391 },
"template_id": "kQ3f9zLm2A7b",
"sent_at": "2026-09-29T20:11:04.000Z",
"download_url": null,
"signers": [
{ "id": "GVcpf2tV5G6o", "role": "Employee", "name": "Jordan Smith", "email": "jordan@example.com",
"status": "pending", "signing_url": "https://www.pdfsignit.com/sign/…" }
],
"fields": [ { "type": "text", "label": "Employee number", "value": "10482", "page": 0 }, … ]
}
From a raw PDF (multipart): send file plus signers (JSON string) and optional fields — each with signer_index, type (signature | initials | date | text | checkbox), page (0-based) and x, y, w, h as fractions of the page (0–1, y from top).
curl -X POST https://www.pdfsignit.com/api/v1/documents \
-H "Authorization: Bearer sk_live_…" \
-F file=@agreement.pdf \
-F title="Client Services Agreement" \
-F 'signers=[{"name":"Dana Lee","email":"dana@example.com"}]' \
-F 'fields=[{"signer_index":0,"type":"signature","page":1,"x":0.12,"y":0.78,"w":0.3,"h":0.06},
{"signer_index":0,"type":"date","page":1,"x":0.55,"y":0.78,"w":0.2,"h":0.04}]' \
-F send=true
Signing links. Each signer's signing_url is returned so you can also show it in your own UI or open it on a tablet for in-person signing. Signers are emailed automatically when a document is sent.
Get a document
GET /api/v1/documents/{id}
→ same shape as above, including per-signer status, viewed_at / signed_at, and download_url once completed.
GET /api/v1/documents/{id}/audit
→ { "data": [ { "at": "…", "actor": "jordan@example.com", "event": "Document signed", "ip": "…" }, … ] }
List documents
GET /api/v1/documents?status=completed&external_id=QM-TICKET-3391&limit=25
→ { "data": [ … ] }
Send · Remind · Void
POST /api/v1/documents/{id}/send → sends a draft (validates every signer has a signature field)
POST /api/v1/documents/{id}/remind → re-emails everyone who hasn't signed
POST /api/v1/documents/{id}/void → cancels; links stop working (not allowed once completed)
Download
GET /api/v1/documents/{id}/download → sealed PDF with certificate (409 until completed)
GET /api/v1/documents/{id}/original → the PDF as uploaded
Templates
GET /api/v1/templates
→ { "data": [ { "id": "kQ3f9zLm2A7b", "name": "Uniform Agreement", "roles": ["Employee"],
"fields": [ { "type": "text", "label": "Employee number", "role": "Employee", "page": 0, "required": true }, … ] } ] }
Templates are designed in the app (Templates → New). Label the text fields you want to pre-fill; labels are matched case-insensitively.
Webhooks
Set an HTTPS endpoint in Settings. Signit POSTs JSON for document.viewed, document.signed, document.declined, document.completed and document.voided, retrying up to 3 times. Respond 2xx quickly and do the work asynchronously.
POST https://your-app.example.com/webhooks/signit
X-Signit-Event: document.completed
X-Signit-Timestamp: 1790712664
X-Signit-Signature: v1=5f8c…
{ "id": "evt_…", "event": "document.completed", "created_at": "…",
"document": { "id": "Ej0UFKUMpgW0vK", "status": "completed", "external_id": "QM-TICKET-3391",
"download_url": "https://www.pdfsignit.com/api/v1/documents/Ej0UFKUMpgW0vK/download", "signers": [ … ] } }
Verify the signature (Node):
const crypto = require('crypto');
function verify(secret, rawBody, headers) {
const ts = headers['x-signit-timestamp'];
const expected = 'v1=' + crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(headers['x-signit-signature'] || ''));
return ok && Math.abs(Date.now() / 1000 - Number(ts)) < 300; // reject replays older than 5 min
}
Errors
401 { "error": { "code": "unauthorized", "message": "Invalid or revoked API key." } }
402 { "error": { "code": "plan_limit", "message": "The Business plan allows 90 documents per month…" } }
404 { "error": { "code": "not_found", "message": "Document not found." } }
400 { "error": { "code": "invalid_request", "message": "Missing signer for role(s): Employee" } }
429 rate limited — 120 requests / minute per IP
Worked example: uniform agreement signed at pickup
- In Signit, upload your Uniform Agreement PDF as a template, add the role Employee, place a signature and date field, and add text fields labelled Employee number, Site and Items issued.
- When your system issues equipment, call
POST /documentswith the template ID, the employee's name/email, the pre-fill values and your ticket number asexternal_id, withsend: true. - The employee receives the email — or Ops opens the returned
signing_urlon a tablet at the counter. - Your webhook receives
document.completed; fetchdownload_urland attach the sealed PDF to the employee's equipment record.
// Node 18+ / Azure Functions
const r = await fetch('https://www.pdfsignit.com/api/v1/documents', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.SIGNIT_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
template_id: process.env.SIGNIT_UNIFORM_TEMPLATE,
signers: [{ role: 'Employee', name: emp.name, email: emp.email }],
prefill: { 'Employee number': emp.number, 'Site': ticket.site, 'Items issued': items.join(', ') },
external_id: `QM-TICKET-${ticket.id}`,
send: true,
}),
});
const doc = await r.json();
await db.tickets.update(ticket.id, { signit_document_id: doc.id, signing_url: doc.signers[0].signing_url });