Skip to the content

Documentation

Templates and text tags

Make a template from HTML or from a PDF, Word, Excel, PowerPoint or image file by writing text tags where fields go.

A text tag is written inside the document's own text where a field should go:

{{Buyer signature;type=signature;role=Buyer}}

The first part is the name. After it come key=value pairs separated by semicolons. A tag needs at least one key=value; {{signer.name}} with none is a merge field and is left alone.

Key Meaning
type signature, initials, date_signed, stamp, text (default), number, date, email, phone, zip, checkbox, dropdown (or select), multiselect, image, file, payment
role Who fills it in, any words. The first role written is signer_1, the next signer_2, and so on
required true (default) or false
default A starting value. Not allowed on signature, initials, date_signed or stamp
options A comma list for dropdown and multiselect: options=Monthly,Yearly
label The caption the signer sees (default: the name)
width, height Size in points (1/72 inch); each type has a default
max_length Most characters a text field takes
amount, currency For payment: a fixed amount, amount=150.00;currency=usd. A payment takes exactly one of amount, formula, price or link (see Payments below)
formula For payment: an amount worked out from other fields, formula=quantity*unit_price*(1+tax/100)
price For payment: a Stripe price on the connected Stripe account, price=price_1AbC…
link For payment: a Stripe payment link from the connected Stripe account, link=https://buy.stripe.com/…

A value that holds a semicolon or an equals sign goes in double quotes: default="Smith; Jones".

From HTML

POST /api/v1/templates/html with { "name", "html", "paper" } prints your HTML to a PDF and places a field wherever a tag sits. Scripts, styles that load anything, frames, forms and remote addresses are removed before printing; pictures must be data: addresses; up to 2 MB. The answer is { templateId, fields, warnings }. A tag that could not be read comes back in warnings, naming that tag.

From a document source

POST /api/v1/templates/source with { "name", "source", "profile", "paper" } keeps a document written in the shared editor's JSON format ({ "type": "doc", "content": [...] }) as a template. profile is typeset (default) or contract; paper is letter or a4. Needs the documents:write scope and an Idempotency-Key. Answers 201 with { templateId, profile, version, hash, warnings }.

curl -X POST https://docustay.app/api/v1/templates/source \
  -H "Authorization: Bearer $DOCUSTAY_KEY" -H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" \
  -d '{ "name": "Notice", "source": { "type": "doc", "content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "Hello" }] }] } }'

Ask for an AI draft

AI drafting is off by default; it is refused plainly while it is off for your workspace or when a limit is reached. A draft is a suggestion for a person to read: nothing is saved or sent.

POST /api/v1/documents/ai/draft with { "prompt", "mode" } (mode is template or document) answers 202 with { jobId, state }.

curl -X POST https://docustay.app/api/v1/documents/ai/draft \
  -H "Authorization: Bearer $DOCUSTAY_KEY" -H "Content-Type: application/json" \
  -d '{ "prompt": "A one-page services agreement with a client signature", "mode": "template" }'

GET /api/v1/documents/ai/jobs/{id} returns { id, state, message, source, patches }. state is queued, running, done, failed or cancelled; poll until it is not queued or running. When done, source is the draft and patches.notes lists what to check.

curl https://docustay.app/api/v1/documents/ai/jobs/$JOB_ID -H "Authorization: Bearer $DOCUSTAY_KEY"

From a file

POST /api/v1/templates/file with { "name", "fileName", "file" } where file is the base64 of a PDF, Word, Excel, PowerPoint or image file with tags written in it. Tags are found in the file's text, covered with a white box and replaced by the field.

Check the seats

GET /api/v1/templates/{id} returns the template's seats. Send with one parties entry per seat: { "seat": "signer_1", "name": "…", "email": "…" }.

Payments

A payment field makes the signer pay on Stripe's own page before their signature completes. The money goes to the Stripe account you connect (Settings → Payments → Connect Stripe; Stripe's own sign-up page creates it in your name, separate from any Stripe account you already have). Docustay's fee is 2% of each payment on the Free plan and 0% on Pro, on top of Stripe's own fees, which Stripe charges to that Stripe account as usual. Card details are typed on Stripe's page; Docustay never receives or stores them.

A payment field takes exactly one way of setting the amount:

Amount Tag Notes
Fixed amount=150.00 0.50 to 999,999.99
Formula formula=quantity*unit_price*(1+tax/100) Numbers, the names of other text fields filled by the same person, + - * / and brackets. Nothing else is read, and nothing is run. The server works the amount out from the values the signer typed; the browser never sends an amount. If the person changes a number after paying, signing is refused.
Stripe price price=price_1AbC… A one-time price on your connected Stripe account. The amount comes from Stripe.
Stripe payment link link=https://buy.stripe.com/… A link from the same Stripe account, with a fixed price. Its items are charged as listed.

A price or link that cannot be found stops the send, with Stripe's reason, so the signer never meets it. The payments list on GET /api/v1/documents/{id} shows each payment: status, amount, Stripe's receipt link, refunds, and the Docustay fee (fee.basisPoints, fee.amountMinor) that was decided when the payment started. A refund returns the fee with it.

A tag in an HTML file, sent through the API

curl -X POST https://docustay.app/api/v1/templates/html \
  -H "Authorization: Bearer $DOCUSTAY_KEY" -H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" \
  -d '{ "name": "Services agreement", "html": "<p>Client: {{Client signature;type=signature;role=Client}}</p>" }'
CtrlI