API reference
Every endpoint of the squiggli API, with parameters, bodies and responses.
Base URL https://squiggli.billy-965.workers.dev/v1. Send Authorization: Bearer sq_live_... (or sq_test_...) and JSON bodies. Objects come back as { "id", "object", ... }, lists as { "object": "list", "data", "has_more", "next_cursor" }, and errors as { "error": { "code", "message" } }. The machine-readable version is /openapi.json.
Envelopes
POST/v1/envelopesCreate an envelope
A draft, or sent at once with send: true. Documents are PDFs (file_base64, file_url) or templates (template_id + variables). Live sends: 402 card_required (with add_card_url) when the business has no card and no free documents left; 403 squiggli_not_enabled without a subscription.
Body
| Field | Type | Description |
|---|---|---|
title required | string | What signers see, e.g. "Harbour Lane lease, unit 4". |
message | string | A note to signers, shown in the email and on the signing page. |
documents | array of object | |
documents[].name | string | File name shown to signers. Defaults to the template name or "Document 1". |
documents[].file_base64 | string | A PDF, base64-encoded. Up to 10 MB. |
documents[].file_url | string | An https link squiggli downloads the PDF from (up to 10 MB). |
documents[].template_id | string | Render this template (tpl_...) as the document. |
documents[].variables | object | Values for the template's {{variables}}, e.g. {"client.name": "Ava Chen", "rent": "$650 a week"}. |
template_id | string | Shortcut for documents: [{ template_id, variables }]. |
variables | object | Values for the template's {{variables}}, e.g. {"client.name": "Ava Chen", "rent": "$650 a week"}. |
signers required | array of object | |
signers[].name required | string | |
signers[].email | string | Required when delivery is email. |
signers[].role | string | The template role this signer fills, e.g. "tenant". Without roles, signers fill the template's roles in order. |
signers[].delivery | "email" | "link" | email: squiggli emails the signing link and reminders. link: no emails; show signing_url yourself or embed it. |
signers[].order | integer | Signing order when signing_order is sequential (1 signs first). Defaults to list order. |
signers[].access_code | string | A code the signer must enter before they can see the document. Give it to them another way (phone, SMS, in person): it identifies them by more than the link. Recommended for delivery "link". |
fields | array of object | |
fields[].signer required | integer or string | Which signer fills it: their index in signers[] (0 is the first), their role, or their email. |
fields[].document | integer | Index into documents[]. Default 0. |
fields[].type required | "signature" | "initials" | "date_signed" | "name" | "email" | "text" | "checkbox" | |
fields[].page required | integer | 1 is the first page. |
fields[].x required | number | PDF points from the left edge of the page (A4 is 595 x 842 points). |
fields[].y required | number | PDF points from the top edge of the page. |
fields[].width | number | Points. Defaults by type: signature 200, initials 60, checkbox 14, others 160. |
fields[].height | number | Points. Defaults by type: signature 50, initials 32, checkbox 14, others 22. |
fields[].required | boolean | Default true, except checkboxes. |
fields[].label | string | |
fields[].key | string | Your own name for the field. Returned with its value in GET /v1/envelopes/{id}. |
fields[].value | string | Prefill a text field. The signer can change it. |
signing_order | "parallel" | "sequential" | parallel: everyone gets it at once. sequential: one after another, by order. |
deadline | string | Signing deadline (ISO 8601). After it the envelope expires. |
deadline_days | integer | Deadline as days from sending, instead of deadline. |
reminders | false or object | Automatic reminder emails. false turns them off. |
reminders.every_days | integer or null | Remind unsigned signers every N days. null for none. Default 3. |
reminders.before_deadline_days | array of integer | Also remind this many days before the deadline. Default [1]. |
reminders.max | integer | At most this many reminders per signer. Default 5. |
test | boolean | Test envelope: free and unlimited, watermarked "TEST - NOT LEGALLY BINDING". Always true with a sq_test_ key. |
whitelabel | boolean | No squiggli name or footer anywhere signers look: your business's name and colour only. $1.50 instead of $1.00. |
sender | object | Who signers are told sent it ("Ava Chen sent you..."), and who gets the decline and completed emails. Defaults to the business. |
sender.name required | string | |
sender.email | string | |
metadata | object | Your own key-value data (up to 20 keys), e.g. {"job_id": "J-1042"}. Returned with the envelope and in webhooks. |
redirect_url | string | Where the signing page sends a signer after they sign. |
send | boolean | true sends it now. false keeps a draft to send with POST /v1/envelopes/{id}/send. |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 201: The envelope.
GET/v1/envelopesList envelopes
Newest first.
| Parameter | In | Description |
|---|---|---|
status | query | Comma-separated statuses |
test | query | boolean |
template_id | query | string |
metadata[key] | query | Match a metadata value, e.g. metadata[job_id]=J-1042 |
limit | query | integer |
cursor | query | next_cursor from the previous page |
Returns 200: A page of envelopes.
GET/v1/envelopes/{id}Get an envelope
Everything: documents and page sizes, signers with their status, opens and links, fields and values, deadline, reminders, and download links once signed.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Returns 200: The envelope.
PATCH/v1/envelopes/{id}Update an envelope
Deadline, reminders, metadata and redirect_url any time it is open; title and message while it is a draft.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Body
| Field | Type | Description |
|---|---|---|
title | string | |
message | string or null | |
deadline | string or null | Move or clear the deadline. Works on sent envelopes too. |
reminders | false or object | Automatic reminder emails. false turns them off. |
reminders.every_days | integer or null | Remind unsigned signers every N days. null for none. Default 3. |
reminders.before_deadline_days | array of integer | Also remind this many days before the deadline. Default [1]. |
reminders.max | integer | At most this many reminders per signer. Default 5. |
metadata | object | Your own key-value data (up to 20 keys), e.g. {"job_id": "J-1042"}. Returned with the envelope and in webhooks. |
redirect_url | string or null |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: The envelope.
DELETE/v1/envelopes/{id}Delete a draft
Only drafts. Void sent envelopes instead.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: Deleted.
POST/v1/envelopes/{id}/sendSend a draft
Emails the signers whose turn it is (sequential envelopes go one at a time).
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: The envelope.
POST/v1/envelopes/{id}/voidVoid (cancel) an envelope
Signers are emailed that it was cancelled.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Body
| Field | Type | Description |
|---|---|---|
reason | string | Shown to signers in the cancellation email. |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: The envelope.
POST/v1/envelopes/{id}/remindRemind signers
A fresh link by email to signers whose turn it is, at most hourly per signer.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Body
| Field | Type | Description |
|---|---|---|
signer_ids | array of string | Default: every signer whose turn it is and who has not signed. |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: Who was reminded and who was skipped.
GET/v1/envelopes/{id}/eventsAudit trail
Every event in order, with IP address and device for signer actions.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Returns 200: Events.
GET/v1/envelopes/{id}/documents/{documentId}Download a document as sent
The PDF signers see.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
documentId required | path | Document id (doc_...) |
Returns 200: PDF (a PDF).
GET/v1/envelopes/{id}/signed.pdfDownload the signed PDF
Every document with every signature and value, once status is signed.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Returns 200: Signed PDF (a PDF).
GET/v1/envelopes/{id}/certificate.pdfDownload the completion certificate
Who signed, when, from where, and the audit trail.
| Parameter | In | Description |
|---|---|---|
id required | path | Envelope id (env_...) |
Returns 200: Certificate PDF (a PDF).
Templates
GET/v1/templatesList templates
Returns 200: Templates.
POST/v1/templatesCreate a template
Blocks (laid out by squiggli on A4, with {{variables}}) or a PDF with fields by role.
Body
| Field | Type | Description |
|---|---|---|
name | string | Required unless you use a starter (its name is the default). |
description | string | |
starter | string | Start from a ready-made design (GET /v1/templates/starters), e.g. "statement-of-work". Anything else you send overrides it. |
theme | object | How the document looks. Every setting is optional. |
theme.font | "helvetica" | "inter" | "roboto" | "poppins" | "montserrat" | "open-sans" | "lora" | "merriweather" | "playfair-display" | "instrument-sans" | "familjen-grotesk" | Body font. Default helvetica. |
theme.heading_font | "helvetica" | "inter" | "roboto" | "poppins" | "montserrat" | "open-sans" | "lora" | "merriweather" | "playfair-display" | "instrument-sans" | "familjen-grotesk" | Heading and cover title font. Default: the body font. |
theme.text_color | string | Body text. Default #141a2e. |
theme.heading_color | string | Headings. Default: the text colour. |
theme.accent_color | string | Table header rules, callout tint, and the cover when it has no background_color. |
theme.font_size | number | Body size in points. Default 11. |
theme.line_height | number | Default 1.45. |
theme.page_size | "A4" | "Letter" | Default A4. |
theme.margin | number | Page margin in points. Default 56. |
theme.page_numbers | boolean | Default true. Never on the cover. |
theme.header_logo | boolean | The business's logo at the top right of every page except the cover. |
blocks | array of object | A block document: squiggli lays it out on the page. Text can use {{variables}}. |
blocks[].type required | "heading" | |
blocks[].text required | string | |
blocks[].level | 1 or 2 or 3 | |
blocks[].color | string | |
blocks[].align | "left" | "center" | "right" | |
file_base64 | string | Or a PDF (base64) with fields placed on it. |
file_url | string | |
fields | array of object | Fields on the PDF, by role. Only with file_base64 or file_url. |
fields[].type required | "signature" | "initials" | "date_signed" | "name" | "email" | "text" | "checkbox" | |
fields[].page required | integer | 1 is the first page. |
fields[].x required | number | PDF points from the left edge of the page (A4 is 595 x 842 points). |
fields[].y required | number | PDF points from the top edge of the page. |
fields[].width | number | Points. Defaults by type: signature 200, initials 60, checkbox 14, others 160. |
fields[].height | number | Points. Defaults by type: signature 50, initials 32, checkbox 14, others 22. |
fields[].required | boolean | Default true, except checkboxes. |
fields[].label | string | |
fields[].key | string | Your own name for the field. Returned with its value in GET /v1/envelopes/{id}. |
fields[].role required | string | Signer role, e.g. "tenant" or "landlord". |
roles | array of object | Labels for the roles the fields use. Worked out from the fields when left out. |
roles[].key required | string | Signer role, e.g. "tenant" or "landlord". |
roles[].label | string |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 201: The template.
POST/v1/templates/previewPreview blocks
Renders unsaved blocks to a PDF.
Body
| Field | Type | Description |
|---|---|---|
blocks | array of object | A block document: squiggli lays it out on the page. Text can use {{variables}}. |
blocks[].type required | "heading" | |
blocks[].text required | string | |
blocks[].level | 1 or 2 or 3 | |
blocks[].color | string | |
blocks[].align | "left" | "center" | "right" |
Returns 200: Preview PDF (a PDF).
GET/v1/templates/{id}Get a template
| Parameter | In | Description |
|---|---|---|
id required | path | Template id (tpl_...) |
Returns 200: The template.
PATCH/v1/templates/{id}Update a template
Send only what changes.
| Parameter | In | Description |
|---|---|---|
id required | path | Template id (tpl_...) |
Body
| Field | Type | Description |
|---|---|---|
name | string | Required unless you use a starter (its name is the default). |
description | string | |
starter | string | Start from a ready-made design (GET /v1/templates/starters), e.g. "statement-of-work". Anything else you send overrides it. |
theme | object | How the document looks. Every setting is optional. |
theme.font | "helvetica" | "inter" | "roboto" | "poppins" | "montserrat" | "open-sans" | "lora" | "merriweather" | "playfair-display" | "instrument-sans" | "familjen-grotesk" | Body font. Default helvetica. |
theme.heading_font | "helvetica" | "inter" | "roboto" | "poppins" | "montserrat" | "open-sans" | "lora" | "merriweather" | "playfair-display" | "instrument-sans" | "familjen-grotesk" | Heading and cover title font. Default: the body font. |
theme.text_color | string | Body text. Default #141a2e. |
theme.heading_color | string | Headings. Default: the text colour. |
theme.accent_color | string | Table header rules, callout tint, and the cover when it has no background_color. |
theme.font_size | number | Body size in points. Default 11. |
theme.line_height | number | Default 1.45. |
theme.page_size | "A4" | "Letter" | Default A4. |
theme.margin | number | Page margin in points. Default 56. |
theme.page_numbers | boolean | Default true. Never on the cover. |
theme.header_logo | boolean | The business's logo at the top right of every page except the cover. |
blocks | array of object | A block document: squiggli lays it out on the page. Text can use {{variables}}. |
blocks[].type required | "heading" | |
blocks[].text required | string | |
blocks[].level | 1 or 2 or 3 | |
blocks[].color | string | |
blocks[].align | "left" | "center" | "right" | |
file_base64 | string | Or a PDF (base64) with fields placed on it. |
file_url | string | |
fields | array of object | Fields on the PDF, by role. Only with file_base64 or file_url. |
fields[].type required | "signature" | "initials" | "date_signed" | "name" | "email" | "text" | "checkbox" | |
fields[].page required | integer | 1 is the first page. |
fields[].x required | number | PDF points from the left edge of the page (A4 is 595 x 842 points). |
fields[].y required | number | PDF points from the top edge of the page. |
fields[].width | number | Points. Defaults by type: signature 200, initials 60, checkbox 14, others 160. |
fields[].height | number | Points. Defaults by type: signature 50, initials 32, checkbox 14, others 22. |
fields[].required | boolean | Default true, except checkboxes. |
fields[].label | string | |
fields[].key | string | Your own name for the field. Returned with its value in GET /v1/envelopes/{id}. |
fields[].role required | string | Signer role, e.g. "tenant" or "landlord". |
roles | array of object | Labels for the roles the fields use. Worked out from the fields when left out. |
roles[].key required | string | Signer role, e.g. "tenant" or "landlord". |
roles[].label | string |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: The template.
DELETE/v1/templates/{id}Delete a template
Envelopes already made from it are not affected.
| Parameter | In | Description |
|---|---|---|
id required | path | Template id (tpl_...) |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: Deleted.
POST/v1/templates/{id}/previewPreview a template
Renders it with these variables. Missing variables show as {{name}}.
| Parameter | In | Description |
|---|---|---|
id required | path | Template id (tpl_...) |
Body
| Field | Type | Description |
|---|---|---|
variables | object | Values for the template's {{variables}}, e.g. {"client.name": "Ava Chen", "rent": "$650 a week"}. |
Returns 200: Preview PDF (a PDF).
Webhooks
GET/v1/webhooksList webhooks
Returns 200: Webhooks.
POST/v1/webhooksCreate a webhook
Events: envelope.sent, envelope.viewed, envelope.signed, envelope.completed, envelope.declined, envelope.voided, envelope.expired. Each POST has Squiggli-Event-Id and Squiggli-Signature: t=<unix>,v1=hex(HMAC-SHA256(secret, "t.body")). Retried for about 21 hours.
Body
| Field | Type | Description |
|---|---|---|
url required | string | Public https URL that accepts POSTed JSON. |
events | array of "envelope.sent" | "envelope.viewed" | "envelope.signed" | "envelope.completed" | "envelope.declined" | "envelope.voided" | "envelope.expired" | Default: every event. |
all_envelopes | boolean | true: every envelope in the business. false (default): only envelopes made with this credential. |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 201: The webhook, with its secret (shown once).
DELETE/v1/webhooks/{id}Delete a webhook
| Parameter | In | Description |
|---|---|---|
id required | path | Webhook id (whk_...) |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: Deleted.
Keys and embed tokens
GET/v1/api-keysList API keys
Web app session or live key only.
Returns 200: Keys (without the secret part).
POST/v1/api-keysCreate an API key
Shown once.
Body
| Field | Type | Description |
|---|---|---|
name required | string | |
mode | "live" | "test" |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 201: The key.
DELETE/v1/api-keys/{id}Revoke an API key
| Parameter | In | Description |
|---|---|---|
id required | path | Key id (key_...) |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: Revoked.
POST/v1/embed-tokensCreate an embed token
For the editor or one envelope inside your web app. Load embed.js and pass the token.
Body
| Field | Type | Description |
|---|---|---|
scope required | "editor" | "envelope" | editor: the template editor. envelope: one envelope (build, review and send it). |
template_id | string | editor: open this template. Leave out to start a new one. |
envelope_id | string | Required for scope envelope. |
ttl_seconds | integer | Default 3600. |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 201: Token and iframe URL.
Account
GET/v1/meGet account
The business this credential acts for: whether it can send live documents, free documents left, prices.
Returns 200: Account.
GET/v1/usageGet usage
Documents sent this month (or ?month=YYYY-MM), by kind and source. Billed on the Kiewa statement.
| Parameter | In | Description |
|---|---|---|
month | query | string |
Returns 200: Usage.
GET/v1/settingsGet branding
The name, colour and logo signers see.
Returns 200: Settings.
PATCH/v1/settingsUpdate branding
Change the name, colour, logo or white-label default.
Body
| Field | Type | Description |
|---|---|---|
display_name | string or null | The name signers see. Default: the business name. |
brand_color | string or null | Hex colour (#2340c8, 2340c8 or #24c), used for the signing page button and email button. |
brand_display | "logo_and_name" | "name" | "logo" | How signers see you on the signing page and in emails: logo and name (default), name only, or logo only. Without a logo, the name is shown. |
whitelabel_default | boolean | New envelopes are white-labelled unless they say otherwise. |
notify_email | string or null | Gets decline, expiry and completed emails for envelopes with no sender email. |
logo_base64 | string or null | A PNG logo, base64 (under 500 KB). null removes it. |
Send an Idempotency-Key header so a retry can't do it twice.
Returns 200: Settings.
POST/v1/card-linkGet a card link
A Kiewa page where the business saves a card (billing). Comes back to the web app.
Returns 200: { url, expires_at }.