Core Concepts

The SmartDocs API is organized around a small set of resources. This page explains how they relate so the reference reads naturally.

Organizations

Everything you create belongs to your organization — templates, PDF assets, signing processes, and API keys are all org-scoped, and an API key can only see its own organization's data.

Access inside an organization is role-based: OWNER, ADMIN, and MEMBER. API keys carry either ADMIN or MEMBER (never OWNER); required roles vary by endpoint — managing templates and PDF assets, and creating direct signing processes, require ADMIN, while reading data and starting signings from a published template are available to MEMBER keys. The required role for each operation is noted in the API reference. Plans (FREE, PRO, ENTERPRISE) set quotas — storage and monthly signing volume — and gate features such as SMS-verified signing. Exceeding a plan quota returns a 402 with a stable error code (see Conventions).

Templates

A template is a reusable document definition. The PDF-oriented /templates resource supports two kinds:

  • PDF — built on an uploaded PDF, with signing fields placed on its pages.
  • HTML — rendered to PDF from an HTML layout with dynamic input data.

The important difference is where the document bytes come from and when field geometry is known:

KindSource documentHow document data is filledHow signer fields are placed
PDFAn uploaded, processed PDF asset.The PDF field editor's Sender fields become inputSchema + prefillFields; data prints those values onto the PDF.The PDF field editor's Signer fields store fixed page coordinates (page, x, y, w, h).
HTMLStored HTML and CSS rendered to PDF at start time.The HTML editor's variables marked asked at start become inputSchema; data fills Liquid such as {{ customer.name }}.The HTML editor's signer fields bind to <span data-sd-field="..."> markers; coordinates are measured from the rendered PDF.

A template moves through three statuses: DRAFT → PUBLISHED → ARCHIVED. The draft is mutable — you edit it via PATCH /templates/{id}/draft. Publishing snapshots the draft into a template version: an immutable, numbered record of everything needed to start a signing. Already-published versions never change; publishing again creates the next version, and in-flight signing processes keep pointing at the exact version they were started from.

The draft, unpublished changes included, is returned only to callers that may edit templates. For everyone else, MEMBER keys included, draft is null: read latestPublishedVersion for what can be started.

A version's definition contains:

  • Signer roles — the named parties (each with a stable role key) that must sign.
  • Input schema — the dynamic data your integration supplies at start time (rendered into HTML templates and prefillable fields).
  • Prefill fields — PDF-template text overlays fed by input data. These become part of the generated source PDF and are not editable by the signer.
  • Signing fields — typed boxes (TEXT, DATE, CHECKBOX, SIGNATURE) placed on the document and assigned to a role. These are the fields the signer fills or confirms.

POST /templates/{id}/start-signing starts a signing process from the latest published version: you supply the runtime data, one concrete signer per role, and an expiry.

Start requests have two different fill mechanisms. These match what the dashboard editor shows:

  • data supplies values filled by the sender before the document is sent. In the dashboard start wizard this is the Prefill step. For PDF templates, data feeds Sender fields from the PDF field editor. For HTML templates, data fills variables from the Variables tab, including variables marked asked at start. Once rendered, these values are baked into the source PDF for the signing process.
  • fieldPrefills supplies editable defaults for fields filled by a signer. In the PDF field editor, set a field to Signer and use its API field key from Additional settings. In the HTML editor, use the field ID / data-sd-field value unless you set an explicit key. A signer can accept, change, or clear these values. The dashboard start wizard currently does not collect fieldPrefills; this is an API integration feature.

If a value should appear as normal document text and also be verified in a signer-editable field, send it twice: once in data and once in fieldPrefills.

fieldPrefills accepts primitive values only. TEXT fields accept strings or numbers, DATE fields accept yyyy-mm-dd (or %TODAY%), CHECKBOX fields accept booleans, and SIGNATURE fields cannot be prefilled.

For HTML templates, Liquid can conditionally remove data-sd-field markers. Optional signing fields whose marker is absent are skipped for that signing process; required fields whose marker is absent return 400, because the signer would otherwise be asked to complete a field with no place on the rendered document.

Signing processes

A signing process is one document sent to an ordered set of signers. It is created in one of two ways — its origin records which:

  • TEMPLATE — started from a published template version via start-signing.
  • DIRECT — created from a raw PDF asset via POST /signing-processes, with signers and fields declared inline.

How signers reach the document is the dispatchMode:

  • EMAIL — each signer receives a hosted signing link by email: in sign order, or all at once when the process signs at the same time (see signingMode below).
  • KIOSK — signers sign in person on a staff-supervised device; no emails are sent.
  • CURRENT_USER — the caller signs the document themselves (single signer). Needs a signed-in member; an API key gets 400.

How signers are authenticated is the authPolicy:

  • AES_OTP — the signer must pass an SMS one-time code before submitting (advanced signature; external signers need a phoneE164).
  • SES_LINK_ONLY — possession of the personal invite link authorizes signing.

A process is born SENT — there is no draft state — and moves through a strict lifecycle:

SENT → IN_PROGRESS → COMPLETED, or terminally DECLINED, VOIDED (cancelled by you via POST /signing-processes/{id}/void), or EXPIRED (passed its expiresAt; extendable beforehand via POST /signing-processes/{id}/extend).

An emailed invite link works until expiresAt, however far out you set it. Extending an email-dispatch process mails everyone whose turn it is a fresh invite with the new deadline.

Who started a process is either a member or an API key, never both:

FieldStarted by a member in the dashboardStarted with an API key
createdByUserIdthe member's user idnull
createdByApiKeyIdnullthe key's id
createdByApiKeynull{ "id": ..., "name": ... }

Both id fields are nullable, so read them as optional: code that assumes createdByUserId is always a string breaks on the first process an integration starts. Keys belong to the organization, see Authentication.

Which mails a process sends to external recipients is fixed when it is created and returned as notifications:

"notifications": {
  "signerCompleted": true,
  "cc": { "started": true, "progress": true, "completed": true, "terminated": true }
}
  • signerCompleted: signers get the completed document by mail. With false, SmartDocs sends them no copy and you hand the document over yourself (GET /signing-processes/{id}/files).
  • cc: the four mails to CC recipients: the process started, each signature, completed, and ended (declined, voided or expired). With all four false, CC recipients are listed on the process and nobody is emailed.

Send notifications with POST /signing-processes, start-signing or kiosk-session to choose per process, in either direction; omitted keys take the organization's setting, which admins choose in the dashboard. For an online form, set notifications.signerCompleted in its draft. Choosing is part of the Enterprise plan: on Free and Pro a request that sets notifications answers 402 BILLING_NOTIFICATION_SETTINGS_NOT_ENTITLED. Without the plan (on Free and Pro, or after a downgrade) every mail goes out; stored choices are kept and apply again after an upgrade. notifications is null on processes created before these settings existed, and every mail goes out for them. Invitations to sign or approve are always sent, and webhooks are never affected.

Signers

Each party on a process occupies a signer slot with a signOrder that runs 1, 2, 3 and so on. Each slot tracks its own status (PENDING → READY → OPENED → COMPLETED, or DECLINED / EXPIRED).

The process's signingMode decides how parties take their turn. It is fixed when the process is sent:

  • SEQUENTIAL (the default) — one after another in signOrder: signer 2 is only invited and activated once signer 1 completes.
  • PARALLEL — everyone is invited at once and signs in any order; the process completes when the last party has signed. Approval steps are not allowed in this mode (400 SIGNING_PARALLEL_NOT_ALLOWED).

signOrder stays each party's identity in both modes: fields are assigned with assignedSignerSignOrder. A process started from a template always uses the template's signingMode.

A slot's kind says what that party does. SIGNER (the default, and what you get when you omit the field) fills the fields assigned to it and signs. APPROVER reviews and releases the document without signing it: the slot owns no fields, nothing of theirs is rendered onto the PDF, and the process waits at that step until they decide. Refusing ends the process for everyone, with a mandatory reason. Approval steps are an Enterprise feature; creating a process with one on another plan answers 402 BILLING_APPROVAL_NOT_ENTITLED, and a process needs at least one SIGNER.

The signer.completed and signing.declined webhooks carry the same kind, so a consumer can tell an approval apart from a signature without a second lookup.

A slot that refused carries declineReason: what the participant gave as the reason, required when an approval is refused and optional when a signature is declined, null otherwise. The signing.declined webhook carries the same text as reason.

Signers act on a hosted signing page that SmartDocs serves and links to from the invite email (or the kiosk session). Your integration never constructs signing URLs and never calls the signer endpoints with an API key — those endpoints authenticate the signer, not your server. You can re-send the invite of a participant whose turn it is (every open participant under PARALLEL) with POST /signing-processes/{id}/signers/{signerId}/resend-invite, which also invalidates the previously emailed link. Under SEQUENTIAL, participants later in the order are invited automatically once the step before them is done, so a resend for them answers 400.

Sending participants back to your app

Give returnUrl to POST /signing-processes or start-signing and the hosted signing page sends participants back to your application when they are done: the last screen shows a Weiter (Continue) button and follows it on its own after five seconds. A signer entry can carry its own returnUrl, which wins over the process one for that participant (for example the patient goes back to your patient portal, your staff to the internal case view).

SmartDocs appends what happened and keeps your own query parameters:

https://app.example.com/plans/RZ-000123?event=signed&processId=7c0d5b6e-2f43-4a1e-9c55-0f6b3e8f4a21

event is signed, approved (an approval step) or declined (a declined signature or a refused approval). Both go into the query string, before any #fragment, so an app that keeps its route after # reads them from location.search, not from the hash. Treat them as a hint for your interface, not as proof: anyone can open that address by hand, so confirm the state with GET /signing-processes/{id} or the webhooks.

  • The host must be on the organization's allowed return URL domains, maintained in the dashboard under Organization, API keys (members with the right to manage API keys). app.example.com matches exactly; *.example.com covers every subdomain but not example.com itself. Any other host answers 400 SIGNING_RETURN_URL_NOT_ALLOWED.
  • HTTPS only; plain HTTP is accepted for localhost while you develop.
  • Kiosk and self-sign processes have no browser screen to leave from (the tablet goes back to its queue): kiosk-session, dispatchMode: "KIOSK" and dispatchMode: "CURRENT_USER" refuse a returnUrl with 400.
  • Return URLs are part of plans with API access (Pro and Enterprise); otherwise 402 BILLING_RETURN_URL_NOT_ENTITLED.
  • The list is checked again when the participant finishes. Removing a domain also stops processes that already carry it; their last screen then simply says the window can be closed.
  • A participant who opens the link again after acting (a reload, or a response lost on a weak connection) sees "already signed" with the same button, without the automatic redirect.
  • The process and each signer slot return their returnUrl on every GET.

PDF assets

Uploaded PDFs become PDF assets, the input for direct signings and PDF templates. Two things to know:

  • Deduplication — assets are content-addressed by SHA-256 within your organization. Uploading a byte-identical file returns the existing asset rather than storing a copy.
  • Who can read an asset: a key reads the assets it uploaded (a byte-identical upload counts), the source PDFs of templates it can open, and the documents of signing processes it can see (all of them with an ADMIN key). Anything else answers 404, and a direct signing process can only start from an asset the key can read. Signed PDFs and certificates are fetched through GET /signing-processes/{id}/files.
  • Async processing — after the two-step upload (initiate → PUT → commit), preview and thumbnail artifacts are generated in the background: QUEUED → PROCESSING → READY (or FAILED, which can be retried). Actions that depend on artifacts — publishing a PDF template, starting a signing — require the asset to be READY and answer 409 until then.

Audit trail

Every signing process carries an append-only list of audit events — process created and sent, signer opened, OTP verified, signer submitted and completed, process completed, declined, voided, and so on. Each event stores the hash of its predecessor and its own hash, forming a per-process hash chain: any attempt to alter or remove history breaks the chain. Events also record the document's SHA-256 at the time, binding the trail to the exact bytes being signed.

When the last signer completes, SmartDocs renders the final signed PDF and a completion certificate summarizing the signers, the authentication evidence, and the audit chain. Both are retrievable as time-limited download URLs via GET /signing-processes/{id}/files once the process is COMPLETED — the path for pulling signed documents into your own systems.

Webhooks

Instead of polling process status, register webhook endpoints (POST /webhooks, or in the dashboard under organization settings → Webhooks; PRO and ENTERPRISE plans) and SmartDocs POSTs you a signed JSON event at each lifecycle transition:

EventFired when
signing.sentA process was created and activated
signer.completedOne signer finished signing
signing.completedAll signers finished — the signed PDF exists
signing.declinedA signer declined
signing.expiredThe process passed its expiry
signing.voidedThe process was cancelled

Each delivery carries the full process snapshot in data.signingProcess, a links.files pointer to the files endpoint, and an id — the logical event id. Some events add fields next to data.signingProcess:

EventExtra fields in data
signer.completedsigner (the slot that finished, with its kind) and isLastSigner
signing.declineddeclinedBy (signerSlotId, signOrder, kind) and reason
signing.expiredexpiredAt
signing.voidedvoidedByUserId and voidedByApiKeyId: exactly one is set, the other is null

A process voided with an API key has voidedByUserId: null and the key's id in voidedByApiKeyId.

Things your consumer must do:

  • Verify the signature. Every request is HMAC-SHA256-signed with the endpoint's secret (shown once at creation). The X-SmartDocs-Signature header has the form t=<unix>,v1=<hex> where the digest covers "<t>.<rawBody>". Reject requests older than a few minutes (replay protection).
  • Deduplicate on id. Retries (and manual redeliveries) can deliver the same event more than once.
  • Don't rely on arrival order. Deliveries are retried independently with exponential backoff (4 attempts over about 3.5 minutes); use the payload's status and timestamps, not the order requests arrive in. After the retry budget the delivery is marked failed — redeliver it manually from the dashboard's delivery log if needed.
  • Answer fast with a 2xx. Anything else counts as a failure; endpoints that keep failing are disabled automatically (re-enable them in the dashboard, where you can also inspect the delivery log and redeliver events manually).

Webhook payloads never contain download URLs — call GET /signing-processes/{id}/files (with your API key) when you want the signed PDF; presigned URLs expire, the endpoint does not.

How it fits together

Organization ─┬─ Template ──< TemplateVersion (published, immutable)
              │      └─ definition: signer roles + input schema + signing fields
              ├─ PdfAsset (sha256-deduped, async processed)
              └─ SigningProcess (TEMPLATE or DIRECT origin)
                     ├─< SignerSlot (ordered; hosted signing links)
                     ├─< FieldDefinition ──< CommittedFieldValue
                     └─< AuditEvent (hash-chained)

Online Forms

/online-forms stores constrained block documents and reusable block templates. It is available to organization owners and admins (including ADMIN API keys). A draft can be edited; sending a document freezes its content and creates a signing process without a source PDF. Template publication updates the content used by future document creations.

Block templates are shared across the organization. A sent document follows the rules of its signing process: it is visible to whoever may see that process, and acting on it (the recipient link, retrying finalization, the unsigned PDF) needs the right to manage it. An unsent document draft belongs to whoever wrote it. The personal recipient link (POST /online-forms/{id}/signers/{signerId}/link) exists for PRIVATE_LINK delivery only; for an email document it answers 409, resend the invitation instead.

The portal includes form templates in its existing Templates library, alongside PDF and HTML templates. GET /templates/catalogue exposes this combined library with server-side filtering, sorting and pagination. Categories, tags and archiving work across all three formats. A template-based form process is included when filtering signing processes by its form-template ID.

The customer fills out and signs the form in the browser. SmartDocs records the visible content, accepted answers, signing statement, and timestamp for each recipient. It generates the signed PDF and existing completion certificate after all recipients sign. No unsigned PDFs are stored on send.

Forms reuse process status, authentication, expiry, withdrawal, webhooks, and final-file downloads. Unlike the PDF field system, form blocks have no page coordinates. Customer answers are structured by block ID; conditional sections can produce a different accepted view for each recipient. The signed PDF and evidence preserve those views.

Sent forms are immutable. Withdraw and create a separate replacement when terms or recipient details change. Existing signatures remain with the original process. Online-form templates share the organization's template quota; published documents count toward its signing-process quota.

See the Online Forms quickstart for requests, visibility rules, and how to retrieve accepted answers.