Developers

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, or voided.
  • 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

  1. 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.
  2. When your system issues equipment, call POST /documents with the template ID, the employee's name/email, the pre-fill values and your ticket number as external_id, with send: true.
  3. The employee receives the email — or Ops opens the returned signing_url on a tablet at the counter.
  4. Your webhook receives document.completed; fetch download_url and 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 });