Shareable and embeddable template links
Publish one URL that anyone can open, fill and sign. Each visit becomes its own document, and the link can be embedded in your app.
All documentation
Everything else in this documentation assumes you know who is signing. A template link inverts that: you publish one URL, and whoever opens it fills in their own details and signs. Each visit becomes its own document. It is the right shape for a vendor NDA on your supplier page, a waiver on a booking confirmation, or a consent form you hand out at scale.
400 exactly_one_open_role_required.Publish a link
Read the template first so you have its role ids - GET /v1/templates/{id} returns them. Then mark one open and assign the rest.
curl https://api.documentesign.com/v1/templates/tpl_4c8a.../links \
-H "Authorization: Bearer $ESIGN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "Supplier NDA - website",
"headline": "Sign our mutual NDA",
"signers": [
{ "placeholder_id": "ph_1", "is_open": true },
{ "placeholder_id": "ph_2", "is_open": false,
"name": "Dana Poole", "email": "dana@acme.com" }
],
"max_uses": 500
}'{
"id": "lnk_2f8d...",
"slug": "k4m9xa",
"url": "https://app.documentesign.com/start/k4m9xa",
"template_id": "tpl_4c8a...",
"use_count": 0,
"max_uses": 500,
"enabled": true,
"signers": [
{ "placeholder_id": "ph_1", "role": "Supplier", "is_open": true,
"name": null, "email": null },
{ "placeholder_id": "ph_2", "role": "Counsel", "is_open": false,
"name": "Dana Poole", "email": "dana@acme.com" }
],
"created_at": "2026-09-01T10:00:00.000Z"
}Hand out url and you are done. It keeps working until you disable it, it expires, or it runs out of uses.
Embedding one
The url above is a full page, and it is deliberately not frameable - loading it in an iframe is refused by the browser. To embed the link in your own site, mint a signed URL for it:
curl https://api.documentesign.com/v1/template-links/lnk_2f8d.../embed-link \
-H "Authorization: Bearer $ESIGN_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "expires_in": 900 }'{
"url": "https://app.documentesign.com/start/embed/eyJhbGciOi...",
"expires_at": "2026-09-01T10:15:00.000Z"
}Drop that into an iframe. The visitor fills the open role and signs without ever leaving your page - the signing step stays in the frame too, so there is no jarring hand-off at the end.
<iframe
src={embedUrl}
title="Sign the agreement"
style={{ width: "100%", height: 780, border: 0 }}
/>409 embedding_not_configured. And the envelope is short-lived by design, so mint it when you render the page rather than storing it. Rotating the link's slug does not invalidate an outstanding embed - the envelope carries the link id, not the slug.Controlling a link
- expires_at and max_usesboth stop a link on their own. A visitor arriving after either gets a plain "no longer available" page rather than an error.
- Rotate (
POST /template-links/{id}/rotate) issues a new slug and kills the old one. Use it when a link leaks. - Delete removes the link permanently. Documents already created from it are unaffected.
Tracking what comes through
Every visit produces an ordinary document, so nothing new is needed to follow it. Subscribe to webhooks and you will get document.sent when a visitor starts, then document.completed when everyone has signed. Read use_count on the link for a running total.
sk_test_ key produces sandbox documents: watermarked, nobody emailed, nothing counted. Build the embed against a test link before you publish a real one.What is not supported
- No prefill on the link. Neither you nor the visitor can supply field values through a template link today. If you need values filled in advance, you know who the signer is, so use a template send with
field_valuesinstead. - reCAPTCHA always applies to the visitor form, embedded or not. An embedded link is no less public than a shared one.