API reference
The QuillSign REST API lets you create, send, and track envelopes programmatically. The base URL is https://quillsign-dev.com/v1. A machine-readable description is published at /v1/openapi.json.
Authentication
Create an API key under Profile → Developer → API keys. The secret is shown once. Send it as a bearer token:
Authorization: Bearer qsk_xxxxxxxxxxxxxxxxxxxxxxxx
Keys inherit your account's organization and role. Revoke a key any time from the same screen.
Conventions
- Idempotency. Send an
Idempotency-Keyheader on create/send; a retry with the same key returns the original response (and anIdempotent-Replay: trueheader). - Pagination. List endpoints accept
?limit=and?cursor=and return{ "envelopes": [...], "cursor": "..." }; pass the cursor back to fetch the next page. - Content type. Request and response bodies are JSON. PDFs are base64-encoded on upload and returned as binary on download.
POST/v1/envelopes
Create a draft envelope from a base64-encoded PDF.
curl https://quillsign-dev.com/v1/envelopes \
-H "Authorization: Bearer qsk_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-4821" \
-d '{
"title": "Master Services Agreement",
"filename": "msa.pdf",
"fileBase64": "JVBERi0xLjcKJ…"
}'
Returns 201 with the envelope, including its id.
PUT/v1/envelopes/{id}
Set recipients and fields on a draft. Fields use normalized coordinates (0–1) and reference a recipient and a document page.
curl -X PUT https://quillsign-dev.com/v1/envelopes/$ID \
-H "Authorization: Bearer qsk_…" -H "Content-Type: application/json" \
-d '{
"routing": "sequential",
"recipients": [
{"id":"r1","name":"Dana Lee","email":"dana@acme.com","role":"signer","order":1}
],
"fields": [
{"id":"f1","recipientId":"r1","type":"signature","docIndex":0,
"page":0,"x":0.1,"y":0.8,"w":0.25,"h":0.05}
]
}'
POST/v1/envelopes/{id}/send
Send the envelope for signature. Each recipient receives a signing token; the response includes per-recipient signUrl values you can distribute.
GET/v1/envelopes/{id}
Fetch an envelope's current status, recipients, fields, audit trail, and (once complete) completedHash.
GET/v1/envelopes/{id}/document
Download the working PDF, or the sealed copy with ?completed=true. Returns application/pdf.
GET/v1/envelopes
List your envelopes, newest first. Supports limit and cursor.
GET/v1/templates · POST/v1/templates/{id}/use
List available templates, then create (and optionally send) an envelope from one by supplying recipients for its roles.
curl https://quillsign-dev.com/v1/templates/$TPL/use \
-H "Authorization: Bearer qsk_…" -H "Content-Type: application/json" \
-d '{"sendNow": true,
"recipients":[{"roleId":"r1","name":"Dana Lee","email":"dana@acme.com"}]}'
Webhooks
Register an endpoint under Profile → Developer → Webhooks. QuillSign POSTs a JSON body on these events:
envelope.sent, envelope.viewed, envelope.recipient_signed, envelope.recipient_approved, envelope.completed, envelope.declined, envelope.voided, envelope.expired.
Each delivery is signed. Verify it with the signing secret shown when you created the webhook:
// headers: X-QuillSign-Timestamp, X-QuillSign-Signature: t=<ts>,v1=<hmac>
const expected = crypto
.createHmac("sha256", webhookSecret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
// constant-time compare expected against the v1 value
Delivery is durable: failed attempts are retried and dead-lettered, so a brief outage on your side won't drop events.
Errors
Errors return a JSON body { "error": "message" } with an appropriate HTTP status: 400 validation, 401 bad/missing key, 403 not permitted, 404 not found, 409 conflict, 429 rate-limited.