Skip to content

Sending & Signing

This covers the full document flow: upload → add recipients → place fields → send → each recipient signs → done. In the app this spans several full-screen steps (Upload, Add Recipients, Prepare Document, the signing Editor) rather than one page, but it's one continuous API sequence — documented here as a single flow with the field-by-field reference for each step.

There is no separate 'multisign' API

A single-recipient envelope and a multi-recipient envelope are the same thing — "multi" just means more than one recipient added to the same workflow. What really varies is the sequence: ORDERED (one recipient acts at a time, in turn) or UNORDERED (every recipient can act in parallel, as soon as it's sent).

Overview

sequenceDiagram
    participant Owner
    participant API
    participant R1 as Recipient 1
    participant R2 as Recipient 2

    Owner->>API: POST /document/v1 (upload PDF)
    API-->>Owner: { id, workflowId } (draft)
    Owner->>API: POST /workflow/v1/{workflowId}/recipients ([R1, R2])
    Owner->>API: POST /workflow/v1/{documentId}/fields (place signature fields)
    Owner->>API: POST /workflow/v1/{workflowId}/commence

    alt Ordered
        API->>R1: Commence email (R1's turn)
        R1->>API: fields/save + /sign
        API-->>API: Advance sequence
        API->>R2: Commence email (R2's turn)
        R2->>API: fields/save + /sign
        API-->>API: Last recipient done -> seal + completed
    else Unordered
        API->>R1: Commence email
        API->>R2: Commence email
        par Both act independently
            R1->>API: fields/save + /sign
        and
            R2->>API: fields/save + /sign
        end
        API-->>API: Last recipient done -> seal + completed
    end

1. Upload

Covered in Documents → Upload. Omitting workflowId creates a new draft workflow; the response gives you both the document id and the workflow id you'll use for every following step.

2. Recipients

Endpoint summary

Method Path Summary
GET /workflow/v1/{workflowId}/recipients List recipients
GET /workflow/v1/{workflowId}/recipients/{recipientId} Get one
POST /workflow/v1/{workflowId}/recipients Add recipients (draft only)
PUT /workflow/v1/{workflowId}/recipients Update recipients (draft only)
DELETE /workflow/v1/{workflowId}/recipients/{recipientId} Remove (draft only)
POST /workflow/v1/{workflowId}/recipients/{recipientId}/delegate Delegate a turn to someone else

Adding recipients

POST /workflow/v1/887/recipients
Content-Type: application/json

[
  { "name": "Jane Doe", "emailAddress": "jane@example.com", "useDigitalCert": false, "recipientOrder": "1", "recipientColor": "#4F46E5", "recipientRole": "SIGNER" },
  { "name": "Legal Team", "emailAddress": "legal@example.com", "useDigitalCert": false, "recipientOrder": "2", "recipientColor": "#059669", "recipientRole": "APPROVER" }
]
Field Type Validation
name string required, 2–50 chars, letters + single interior spaces
emailAddress string required, valid email, ≤255 chars
recipientPassword string optional — a per-recipient access password, separate from account credentials

A recipient carrying a recipientPassword must enter it before the document opens. The signing page checks it with Recipient access passwords below. | useDigitalCert | boolean | required | | recipientOrder | string | required only when the workflow's sequence is ORDERED | | recipientColor | string | required — hex color for that recipient's field highlighting | | recipientRole | string | SIGNER, APPROVER, or CC (blank defaults to SIGNER) | | enforceIdentity | boolean | optional — gates signing behind OTP identity verification |

If an email doesn't match an existing platform user, a guest account is created for them automatically — no separate invite step is needed.

Errors: workflow isn't in draft or isn't owned by the caller; recipients aren't allowed on a self-sign workflow; a Power Survey workflow only accepts SIGNER-role recipients; duplicate order/email under an ordered sequence.

PUT /workflow/v1/{workflowId}/recipients edits existing recipients before sending (same shape + required id). POST .../delegate (below) hands a turn to someone else, usable even after the workflow is sent.

Delegating

POST /workflow/v1/887/recipients/5501/delegate
Content-Type: application/json

{ "name": "Backup Signer", "emailAddress": "backup@example.com" }

Usable by the workflow owner or the recipient themself. The delegate inherits the original recipient's order/role/fields.

3. Place fields

Endpoint summary

Method Path Summary
POST /workflow/v1/{documentId}/fields Add a field
POST /workflow/v1/fields/list Add multiple fields at once
PUT /workflow/v1/{documentId}/fields/{fieldId} Update a field
PATCH /workflow/v1/{documentId}/fields/{fieldId}/required Toggle required/styling only
GET /workflow/v1/{workflowId}/fields, /all-fields, /fields/{fieldId} Read fields
DELETE /workflow/v1/{workflowId}/fields/{fieldId} Delete a field
POST /workflow/v1/1200/fields
Content-Type: application/json

{ "pageNo": 1, "fieldType": "SIGNATURE", "box": { "x": 100, "y": 200, "width": 150, "height": 40 }, "recipientId": 5501, "fieldRequired": true }
Field Validation
pageNo required, ≥1
box required — {x, y, width, height}
fieldType one of SIGNATURE, TEXT, CHECKBOX, NAME, EMAIL, NUMBER, DROPDOWN, NOTE, TEXTAREA, DIGITAL_SIGNATURE, INITIALS, IMAGE, DATE, STAMP
recipientId which recipient this field belongs to
signatureAssetId optional — which saved library entry was applied here (see below)

PUT .../fields/{fieldId} additionally supports styling (textColor, fontFamily, bold, italic, underline, strikethrough, textAlign, backgroundColor, fontSize, placeholder, dateLang, useAsLabel).

STAMP fields

STAMP is an image field a recipient fills from their own saved stamps — same mechanic as SIGNATURE and INITIALS (a saved image dropped into a placed box), but it is not a signature: it carries no signatureQualifier, consumes no signature quota, and takes no part in the signing/sealing step. Like a signature field, it is reserved for the recipient it belongs to — a personal assistant can never fill one on their behalf.

Validation differs from SIGNATURE/INITIALS in one place: an empty stamp is rejected only when the field is marked required. An empty signature always means an unfinished document because every client can fill one; a stamp is newer, so an older client that can't render a stamp picker must still be able to submit a document that contains one.

Which saved signature was used: signatureAssetId

Signature, initials and stamp fields all accept an optional signatureAssetId — the id of the entry in the signer's own saved library that produced the image.

  • The image itself is still value. signatureAssetId is a pure link, never dereferenced server-side; it exists so a reopened document shows the correct entry per field even after the signer edits one of their saved signatures.
  • Null means "leave what's stored alone." A client that knows nothing about the library can't wipe the link. Zero and negative values are treated the same as null.
  • Reads are per-viewer. GET .../fields returns signatureAssetId only to the signer the field belongs to; every other participant sees null, since library ids are per-user and would otherwise resolve against the reader's own library.

4. Send

POST /workflow/v1/887/commence
Content-Type: application/json

{ "title": "Please review and sign", "message": "See attached NDA for your signature." }

What happens next depends entirely on the sequence:

Sequence Behavior
ORDERED Dispatches only the first action-required recipient (leading CC rows are auto-processed first); the next recipient is dispatched only once the prior one finishes.
UNORDERED Dispatches every non-CC recipient at once — true parallel signing.
SURVEY (Power Survey) Triggers async bulk fan-out — see Power Survey. Returns 202 Accepted instead of 200.

Responses: 200 OK (normal send completed), 202 Accepted (Power Survey dispatch started), 400 (no recipients, wrong status/owner, or your plan disallows document sharing).

5. Recipient views and signs

Each recipient reaches the signing UI via the guest signing flow (or, if already logged in, just their normal session), then:

POST /workflow/v1/1200/fields/save
Content-Type: application/json

[
  { "id": 5501, "value": "Jane Doe", "type": "TEXT" },
  { "id": 5502, "value": "data:image/png;base64,...", "type": "SIGNATURE", "signatureAssetId": 41 },
  { "id": 5503, "value": "data:image/png;base64,...", "type": "STAMP",     "signatureAssetId": 77 }
]

Send signatureAssetId whenever the value came from a saved library entry — one submission can carry a different entry per field, which is exactly how a signer applies two different signatures to the same document. Omit it and the stored link is left untouched.

...for each field, followed by:

POST /workflow/v1/887/sign
Content-Type: application/json

{ "id": 5502, "image": "data:image/png;base64,..." }

id is the field id, image the rendered signature/initials image. If the recipient is signing with a digital certificate (useDigitalCert: true) and a password is included in the fields/save call, this is where their signing password is verified — first use provisions their key material, later uses just verify it. This can only happen interactively (never as a background job), since the private key itself is password-protected at the point it was created.

If instead this recipient is an APPROVER: POST /workflow/v1/887/approve with a comment. To reject: POST /workflow/v1/887/decline with a reason — GET /workflow/v1/887/reject-details returns the structured reason afterward.

Recipient access passwords

When a recipient was added with a recipientPassword, the signing page asks for it before showing the document, and verifies it with:

POST /workflow/v1/verify/workflow
Content-Type: application/json

{ "recipientID": 3310, "password": "hunter2" }

Returns a bare true or false. The stored password is hashed, so this endpoint compares hashes rather than returning anything about the password itself. An unknown recipientID returns RECIPIENT_NOT_FOUND.

The password only gates opening the document. It is not a signing credential — the digital- certificate password in fields/save above is a different thing entirely.

CC recipients: marking the copy read

A CC recipient has nothing to sign; they are sent a copy. Their client confirms they have seen it with:

POST /workflow/v1/887/cc/complete

Returns 200 with no body. It is a no-op — deliberately silent, not an error — if the caller is not a CC recipient on that workflow, so a client can call it without first checking the role.

6. Sequence advances automatically

Under ORDERED, the moment one recipient finishes, the next non-CC recipient in order is automatically dispatched — there's no separate "advance" call to make. CC-role recipients are skipped over and simply notified once the sequence reaches their position.

7. Completion

Once the last action-required recipient signs or approves, completion happens automatically:

  1. The invisible sealing/certification signature is applied.
  2. The workflow's status becomes COMPLETED.
  3. The evidence report becomes available: GET /workflow/v1/evidence-report/{workflowId} — an HTML audit trail of who signed what, when, from what IP, with what consent record. This is what the app's Audit Report screen renders.

Signature details

Once a document is signed, the cryptographic detail of each signature can be read back:

GET /workflow/v1/digital-signature/details/887

Returns one entry per document, each holding the signatures found inside that PDF:

[
  {
    "docName": "supplier-agreement.pdf",
    "docId": 1200,
    "signatureInfoList": [
      {
        "fieldId": "Signature_1",
        "pageNo": 3,
        "signatureType": "VISIBLE",
        "signatureTime": "2026-08-14T10:41:55.000+00:00",
        "signatureName": "Ayşe Yılmaz",
        "filter": "Adobe.PPKLite",
        "subFilter": "ETSI.CAdES.detached",
        "reason": "I approve this document",
        "location": "Istanbul",
        "digestAlgo": "SHA256",
        "signatureAlgo": "RSA",
        "signatureValidity": true,
        "certificateDetailsList": [ { } ]
      }
    ]
  }
]

signatureType distinguishes a VISIBLE signature placed in a field from an INVISIBLE sealing or certification signature, which has no field on the page. signatureTime is resolved from the signature itself — an RFC 3161 document timestamp first, then an embedded timestamp token, then the signature dictionary — so invisible signatures carry a time too.

signatureValidity is the result of verifying that signature against the document bytes. A false here means the content changed after signing.

Voided workflows

A workflow that's been declined or otherwise voided is read-only from then on — the app's Void screen just displays its final state; there's no separate "void" API action beyond decline (see step 5) or a Power Survey parent cascading a void to its children (see Power Survey).

Two mechanics worth knowing about

  • Hidden assistant pre-review. If a recipient has Assistant delegation enabled, their turn is transparently routed through their assistant first. This never appears in anyone else's recipient list — from every other participant's perspective, nothing looks different.
  • Auto-delegation ("away") swaps. If a recipient has an active auto-delegation window, the platform can silently substitute their stand-in delegate at the moment their turn starts, rather than waiting on someone who's away.

Neither requires any special handling from an integrating client — both are resolved server-side before a commence email is ever sent.

Remote/CSC signing bridge

For signers using a remote qualified-signature provider (the CSC protocol) instead of a locally-drawn signature:

GET /workflow/v1/list/user/keys?connectorName=CSC_2
POST /workflow/v1/1200/sign/csc
Content-Type: application/json

{ "id": 5501, "connectorName": "CSC_2", "qualifier": "QES" }

Returns a hash to be signed by the remote provider's own authorization flow; the resulting signature is then submitted:

POST /workflow/v1/1200/signature/csc
Content-Type: application/json

{ "hash": "...", "code": "...", "connectorName": "CSC_2", "qualifier": "QES", "credentialID": "..." }

POST /workflow/v1/signature/csc/batch performs the same exchange across multiple documents in a single authorization step — useful when a signer needs to qualified-sign several documents at once. GET /workflow/v1/check-user-credits/{workflowId}?qualifier=QES and GET /workflow/v1/service-plan-qualifier let the UI pre-check credit/plan eligibility before starting this flow.