docs
/
AI skills

Send a document for e-signature

Put a PDF on a form, say who signs it, in which order and where on the page, send it after a yes, follow who has signed, remind, cancel or void, and get the signed PDF with its certificate of completion.

A signing request is a signed document (signed_document, also called an envelope): one agreement sent to one set of people. It is made by sending a form whose Document tab is switched on (crm_form.data.signing). Each send makes a new one, with a private copy of the PDF, its SHA-256 fingerprint, a private link per signer, and an audit trail of every view, consent, signature and download with the signer's IP address and browser (crm.signed.document.ts 70–87).

Related jobs: the form itself, its fields and its share link are in Shared form from a collection; the site page that shows forms is in Put a form on a website page.

Ask first

  • The document: the PDF. Nothing else can be signed.
  • Who signs: each person's name and email, and the role they sign as ("Client", "Employee", "Witness"…). One person per role.
  • In which order: one after another (the default), or everyone at once.
  • Who only gets a copy of the signed PDF.
  • What each signer fills in: a signature, initials, the date, their name, or text (a company name, a title), and where on which page.
  • Questions to answer as well, if any, and which signer each one is for.
  • How long the link stays open (default 30 days) and whether to remind them automatically every few days.
  • The record it is for, if any: a contact or an employee.

Steps

1. File Manager: the PDF, kept private

Upload the PDF as a private file: POST /repository/file/upload (multipart) with file, location: "signing-documents" and isPrivate: "true". In the Studio, the form's Document tab does this itself ("Uploaded privately: only your team can open it").

The file is checked when the form is sent, not before: it must start as a PDF (%PDF-) and its pages must be readable, or the send fails with "… is not a PDF" or "… is not a readable PDF" (crm.signed.document.ts 808–827).

Hands on: the file's path and page size (a US Letter page is 612 × 792 points). Check: POST /repository/file/exists with { "location": "signing-documents/<file name>" } answers exists: true.

2. Forms: the form and its questions

Look first: find_records on crm_form. Make the form as in Shared form from a collection, with create_record on crm_form (name, title, description, schema). A form may ask no questions at all; then the signer is only asked to sign.

Fields that matter for signing (signing-model.ts 145–203):

On a fieldValueEffect
x-control"signature"A signature field: drawn or typed, with consent. Its answer is { image?, typedName?, consent: true }.
signatureModes["draw"], ["type"] or both (default)How it may be signed.
signerRolea role's id or labelAsked of that signer only. A field with none is asked of the first signer.
required (in the schema's required list)A required signature field left empty is refused.

Hands on: the form's name and sk. Check: open it in Forms (/crm-form?uid=<sk>); the fields are there.

3. Forms › Document: the PDF, the signers and the spots

In the Studio: the form's Document tab (/crm-form?uid=<sk>&formTab=document). Its switch turns signing on; then Settings, Signers and the page itself, where spots are dragged into place for each signer.

Through the API, update_record_partial on the form with the key data.signing:

FieldValueNotes
enabledtruefalse keeps the setup but sends the form as a plain form.
documents[{ file: { path, name, mimeType: "application/pdf" } }]Several PDFs are allowed; spots name one by fileIndex (0-based).
roles[{ id: "client", label: "Client", order: 1 }]Lower order signs first. The id is the label in lower case with - for spaces.
spotssee belowEvery spot needs a role.
signingOrdersequential or parallelSequential emails the next signer when the one before finishes. The Studio starts with sequential; a form saved without it is sent parallel.
expiresInDaysdays, default 30After that the request closes as expired.
reminderDaysdays, 0 = noneAn automatic reminder to whoever hasn't signed, that often.
consentTextwordingEmpty uses the standard consent to sign electronically.

A spot: { id, fileIndex, page, x, y, width, height, type, role, field?, required?, label? }.

  • x, y, width, height are PDF points (1/72 inch), measured from the bottom-left corner of the page; x, y is the spot's bottom-left corner. page starts at 1. Without a size, a signature is 160 × 40, initials 60 × 22, the rest 120 × 22 (signing-model.ts 83–108).
  • role is the signer role's id.
typeWhat goes on the page
signatureThe signature from the linked signature field, else the one the signer adopts on the page: their drawing, or their typed name in a script face.
initialsDrawn or typed initials; worked out from the name if they give none.
dateThe date they signed, as yyyy-mm-dd in UTC (an evening signature in the Americas shows the next day).
nameWhat they type, else their signature name, else their name on the request.
textThe answer to the linked field, else what they type.

Sending is refused, and nothing is sent, when (crm.signed.document.ts 203–235):

  • no document is on the form: "This form has no document to sign.";
  • no spot has a role, or none is placed: "Place at least one spot on the document…";
  • a spot has no role: "N spot(s) on the document have no signer role.";
  • a role with spots has nobody: 409, reason: "role-without-participant" (step 4);
  • a spot is on a page or document the PDF doesn't have.

Hands on: the form, ready to send. Check: read the form back; data.signing.spots has a spot of every type the person asked for, each with a role, and documents[0].file.path is the file from step 1.

4. Forms › Access: who signs and who gets a copy

The people are the form's participants: [{ email, name, role, accessCode }]. In the Studio, picking a person under Signers on the Document tab adds them with that role.

  • A participant whose role matches a signer role's id or label signs as that role.
  • Anyone else (no role, or a role that isn't a signer role) only gets the finished copy.
  • One person per role. A second person with the same role also only gets a copy.

The signing link opens the site's form page. Each signer's link is <the site's forms page>?form=<form name>&sign=<their token>. If the site's Forms feature is off, it still goes out as <site>/form?…, and that page is a 404 (tested). Make sure Forms is on, or a page of the person's own holds it, before sending: see Site Config: Forms.

If the business has publishing approval for forms switched on, the form must be published first, or the send answers 409, reason: "not-published".

Hands on: the participants, with their roles. Check: read the form back; every signer role has exactly one participant.

5. Forms: send it

Stop. Sending emails each signer their private link. Show the document, each signer with their role and order, who gets only a copy, and when it expires. Wait for a yes.

In the Studio: the form's Access tab › Send to all. Through the API, call_appengine POST /crm/form/<form name>/invite (staff) with:

{ "context": { "datatype": "customer", "id": "<customer sk>", "label": "Ana Reyes" }, "expiresInDays": 14 }

Both are optional. Without context, the request is tied to the first signer's contact (or employee) when there is one with that email.

SendWhat happens
{} or no emailsA new request every time. Sequential: the first signer is emailed; parallel: every signer. Copy-only people get nothing yet.
{ "emails": ["[email protected]"] } while a request for this form is still openThat person is reminded on the open request; their link doesn't change.

It answers { signing: true, envelope: { sk, status: "sent", signingOrder, expiresAt }, sent, results: [{ email, role, sent, queued, copyOnly, reminder, link }] }.

Hands on: the request's sk (envelope.sk). Check: step 7. The request is sent, and the first signer's status is sent.

6. The signer: open, fill in, sign or decline

What the signer's link does (crm-form.service.ts 154–173; base-app SigningForm.tsx):

  • It opens the form for that person only, with only their questions, then the document with their spots marked. They adopt a signature (draw, or type their name), fill each spot, tick the consent and submit, or Decline with a reason.
  • The first open is recorded as viewed, with IP and browser.
  • A link that can't be used now says why:
StateAnswerSigner sees
not their turn (sequential)409, sign-waitingNot your turn yet
already signed410, sign-signedYou have already signed
complete410, sign-completedThis document is complete, with a download button
declined, cancelled, voided, expired410, sign-declined … sign-expiredwhy it can't be signed
wrong or partial link404, sign-invalidThis signing link is not valid

A page of your own submits with POST /api/client/forms/<form name>/submit and the answers plus signToken and __signing: { consent: true, signature?: { image | typedName }, initials?, spots?: { "<spot id>": { text } } }. Without consent it answers 400 "Consent to sign electronically is required" (tested). The PDF being signed is GET /api/client/forms/<name>/sign/<token>/document?file=0; a decline is POST …/sign/<token>/decline with { reason } (required, tested).

When the last signer signs, the request completes at once: their answers are saved as a submission, every spot is written into the PDF, a certificate of completion is added (each signer's name, email, role, time, IP, browser and method, the original's fingerprint, the event log), and the signed PDF is stored privately.

Never sign or decline on someone's behalf, and never open a signer's link to "check it": the first open is recorded in the audit trail as that person viewing it. Use the request's record (step 7) to check.

Hands on: nothing; this is the signer's part.

7. Signed Documents: follow up

In the Studio: Signed Documents (/signed-docs), the Signing tab of Forms (/crm-form?activeTab=signing), or a form's own Signing tab. Each request shows who has signed, each waiting signer's link to copy, the audit trail, the emails sent, and the buttons below.

Through the API (staff):

JobCall
ListGET /crm/signed-documents?q=&status=&formId=&page=&pageSize=. q searches title, form and people. status: draft, sent, in_progress, completed, declined, cancelled, voided, expired, or open (sent or in progress) or needs-attention (all signed, PDF not built yet).
For one recordGET /crm/signed-documents/context/<datatype>/<id>
One requestGET /crm/signed-documents/<sk>: participants with their status and link, spots, audit trail, and summary: { signers, signed, waitingOn, needsAttention }
DownloadGET /crm/signed-documents/<sk>/download (the signed PDF with its certificate) or ?which=original&file=0 (the copy that was sent). It is a PDF file, not JSON.
RemindPOST /crm/signed-documents/<sk>/remind with {} (everyone still to sign) or { "participantId": "…" }
CancelPOST /crm/signed-documents/<sk>/cancel with { reason }: nobody can sign it any more. Not for one that is already closed.
VoidPOST /crm/signed-documents/<sk>/void with { reason }: it stops being valid, even when completed. The signers' links stop working, including their download; staff can still download it.
Rebuild the PDFPOST /crm/signed-documents/<sk>/retry-merge

Stop. Remind, cancel and void each email people: remind the waiting signers; cancel and void everyone who was already sent it. Say who, and wait for a yes.

A sent request can't be edited. To change the document, the people or the spots, cancel it, fix the form, and send again.

Tested on 2026-10-20 on a test engine with a one-page PDF, one "Client" signer and one copy-only person: send → link opened (viewed) → signed with a typed signature, a date and a text spot → completed at once, one certificate page added, the same signed PDF from the staff download and the copy person's link. A second send was reminded with emails, then declined (410 on the link afterwards); a third was cancelled; voiding a cancelled one answers 409 "already cancelled".

Hands on: the request's status and, when complete, the signed PDF. Check: GET /crm/signed-documents/<sk>: status is completed, merge.status is done, and every signer is signed.

What is sent

WhenTemplateTo
Sent, and each next signer's turnsignature-requestthat signer
Reminder (by hand or every reminderDays)signature-request, marked as a reminderwaiting signers
Everyone has signedsignature-completed, with their download linkevery participant, copy-only ones too, and the sender
A signer declinedsignature-declinedthe sender and everyone already sent it
Cancelled or voidedsignature-cancelledeveryone already sent it
Expiredsignature-expiredthe sender and the waiting signers
The signed PDF couldn't be builtsignature-merge-failedthe sender

The "sender" is the staff member who sent it. Each email is a message owned by the request, listed on its screen. A job every 15 minutes closes expired requests, sends the automatic reminders, and rebuilds a failed PDF up to 6 times (signed-document.job.ts).

When the request completes, each signer's submission gets data.signedDocument: { id, status: "completed", completedAt, sha256 }, and the record in context is told it is signed: a Business Made contract (bm_contract) gets the signed PDF in its files and becomes active, and goes back to draft if the request is declined, cancelled, voided or expires.

When it's done

Tell the person:

  • the document, each signer with role and order, and who gets only a copy;
  • the request's sk and status, who has signed and who it is waiting on, and when it expires;
  • that the signer's link opens the site's forms page;
  • when complete: that the signed PDF with its certificate is in Signed Documents, and everyone was emailed their copy.

What it can't do yet

  • Forms only. There is no Studio screen to send a PDF without a form. POST /crm/signed-documents makes a draft request, but its links point at a /sign page that sites don't have; don't use it.
  • One person per role. Two clients signing need two roles ("Client", "Co-client").
  • No change after sending. Cancel and send again.
  • The link goes to a 404 when the site's Forms feature is off (step 4).
  • A copy-only person's link says "Not your turn yet" until the request is complete, as if they were to sign.
  • Date spots use the UTC date.
  • Email only. Signing requests are not sent by text.
  • No in-person signing by staff. Staff entering an answer on the form are not a signer.

Don'ts

  • Don't send, remind, cancel or void without a yes. Each one emails people.
  • Don't upload the document as a public file.
  • Don't sign, decline or open a signer's link on their behalf.
  • Don't give two people the same signer role and expect both to sign.
  • Don't place spots in screen pixels or from the top of the page; they are PDF points from the bottom-left.
  • Don't send before the site's forms page works.
  • Don't void a completed document to "fix" it; void means it is no longer valid.