E-signature
The signing flow: turn a PDF into a sign document, place fields on it, invite recipients, collect their signatures over one-time links, and end with a completed, fingerprinted file.
The lifecycle
| Status | Meaning |
|---|---|
DRAFT | Created, fields not yet finalized |
PENDING | Sent, waiting on the first recipient |
IN_PROGRESS | At least one recipient has signed |
COMPLETED | Every signer is done — the fingerprint is computed |
EXPIRED | Passed expiryAt before completion |
CANCELLED | The owner cancelled it |
1. Create
POST /api/sign/create — the owner uploads a PDF (/sign/upload), which creates the SignDocument referencing one file, with a title, optional description, and an optional expiryAt (null = never expires).
2. Place fields
POST /api/sign/{docId}/fields — in the builder (/sign/build/:docId) the owner drags fields onto pages. Each field has a type, a page, an x / y / width / height, and the recipient it belongs to:
| Field type | |
|---|---|
SIGNATURE | A drawn / typed / uploaded signature |
INITIALS | Short-form sign-off |
DATE | Auto-filled on signing |
TEXT | A free-text entry the recipient fills |
CHECKBOX | An acknowledgement tick |
3. Recipients and flow
Each recipient has an email, a name, and a role:
| Role | Can |
|---|---|
SIGNER | Fill and sign their fields |
APPROVER | Approve without signing |
VIEWER | See the document only |
The signing flow is PARALLEL (everyone at once) or SEQUENTIAL (one at a time, in signingOrder).
4. Send
POST /api/sign/{docId}/send emails every recipient their unique link. Each link carries a UUID signingToken; only a SHA-256 hash of it is stored (tokenHash), so a database leak doesn't hand out working links.
The public signing page
/sign/:token — the recipient opens the link, no account needed:
| Step | Endpoint |
|---|---|
| Load the document + fields | GET /api/public/sign/{token} |
| View the PDF | GET /api/public/sign/{token}/pdf |
| Request an email OTP | POST /api/public/sign/{token}/otp/send |
| Confirm the OTP | POST /api/public/sign/{token}/otp/verify |
| Submit signature + field values | POST /api/public/sign/{token}/complete |
The OTP is stored as a SHA-256 hash with an expiry and an attempt counter — it's a genuine second factor on the identity of the signer, not just a formality.
Track and manage
| Action | Endpoint |
|---|---|
| List / search sent documents | GET /api/sign/list · /api/sign/search |
| Check status | GET /api/sign/{docId}/status |
| Resend to one recipient | POST /api/sign/{docId}/recipients/{recipientId}/resend |
| Cancel | POST /api/sign/{docId}/cancel |
| Delete | DELETE /api/sign/{docId} |
| Full audit trail | GET /api/sign/{docId}/audit |
| Integrity check | GET /api/sign/{docId}/integrity |
The tracking page (/sign/track) shows every document and where each recipient stands. See Document integrity & audit for what the audit and integrity endpoints return.