sign.ytDocs

Guides

Signing links and embedding

Each recipient signs on a sign.yt page at a personal, unguessable URL. By default sign.yt emails that link; you can also fetch it and hand it over yourself.

The signing URL#

https://sign.yt/sign/<access_token>

The page shows the sending organization's (or team's) branding. Treat the URL as opaque and use it exactly as returned. The token is a bearer credential: anyone holding it can act as that recipient (subject to the document's verification setting), so treat it like a password. Signing links are never included in GET /documents/{id} responses.

Links stop working when the document is completed, cancelled, rejected or expired, and are rotated when you change the recipient's email or phone.

For pending documents you can retrieve a recipient's current link, for example to show it inside your own portal or send it over another channel. The key's creator must be the document's creator or an organization admin, the document must be PENDING, and the recipient must have an active invitation (SENT or VIEWED; in sequential order that means it is their turn). Every retrieval is recorded in the audit trail.

curl -sS "https://api.sign.yt/v1/documents/$DOC_ID/recipients/$RECIPIENT_ID/signing-link" \
  -H "Authorization: Bearer $SIGNYT_API_KEY"
# {"signing_url": "https://sign.yt/sign/q3Jd..."}

Errors: 403 document_forbidden, 409 document_not_pending, 404 recipient_not_found, 409 recipient_not_invited. The SDKs have no method for this endpoint yet; use raw HTTP.

The invitation email is still sent when the document is sent. Recipients can open either link; it is the same credential.

Redirect after signing#

Set redirect_url_after_sign when creating a document (POST /documents payload, POST /templates/{id}/use, the redirect_url_after_sign form field of POST /documents/bulk, or a campaign), or later with PATCH /documents/{id} while the document is DRAFT or PENDING. After a recipient finishes signing, the success page shows a 5-second countdown and a manual link, then sends them to:

https://crm.example.com/signed?document_id=3f1c2a9e-5b7d-4c11-9a3e-0d4b8e2f6a71&status=signed

Your own query parameters are kept; document_id and status are added. Signing tokens are never included, so treat the redirect as a hint and confirm the state with GET /documents/{id} or the webhooks.

  • Only https:// URLs with a real host name, no credentials (user@), no whitespace or backslashes, at most 2048 characters. Anything else is rejected with 422.
  • Org admins can limit redirects to allowed redirect domains (Settings, Signing integration; subdomains included). A URL outside the list fails with 422 redirect_domain_not_allowed.
  • API keys and MCP can only set a redirect when the organization has an allowlist; otherwise the call fails with 422 redirect_domain_not_allowlisted.
  • Documents created in the app may use any https URL while the list is empty; the signer then sees "After signing you will be redirected to host" before signing.
  • The allowlist is checked again when the signing page is shown, so removing a domain also stops redirects for existing documents.

Embedding in your app#

Regular signing links (/sign/<token>) can never be framed: they are served with X-Frame-Options: DENY and frame-ancestors 'none'. Organizations on Business and above can embed signing on their own sites:

  1. An org admin adds the embedding origins (for example https://portal.example.com, https only, no paths or wildcards) under Settings, Signing integration.
  2. Take the recipient's signing link and replace /sign/ with /embed/sign/.
  3. Show it in an iframe on one of those origins. The page is served with Content-Security-Policy: frame-ancestors <your origins> for that org's links only; any other token, organization or site gets frame-ancestors 'none'.
Embed and listen for events
<iframe src="https://sign.yt/embed/sign/TOKEN" style="width:100%;height:900px;border:0"
        allow="clipboard-write"></iframe>
<script>
window.addEventListener("message", (e) => {
  if (e.origin !== "https://sign.yt" || e.data?.source !== "sign.yt") return;
  // e.data.type: "signed" | "declined" | "error"; e.data.document_id
  console.log(e.data);
});
</script>

The frame posts {source: "sign.yt", type, document_id} to the parent with targetOrigin set to your allowed origins, so only an approved parent receives it. signed also carries the document status; error carries an error code when signing fails. The post-sign redirect is not followed inside the frame; react to the signed event instead.

Verification codes in a frame. Email/SMS verification works in the frame through a SameSite=None; Secure; Partitioned cookie that is set only for the embed flow of an org that allows embedding. Browsers that block all third-party cookies (some privacy modes) cannot complete a code step inside an iframe; use verification_type: NONE for embedded flows where you already authenticate the user, or open the regular link in a new tab.

Without embedding, use a redirect or new-tab flow: send the document from your backend, fetch the signing link, send the user to it and come back via redirect_url_after_sign.

Verification before signing#

The document's verification_type decides what the recipient must do after opening the link: nothing (NONE), enter a code sent by email (EMAIL_OTP), by SMS (SMS_OTP) or both (BOTH_OTP). Organizations with identity verification enabled can require an ID check (ID_VERIFIED) that the signer completes before the document opens; see Identity verification. Before the signature is accepted the signer confirms an explicit consent statement, which is stored with its hash in the evidence.

To let anyone sign (for example a sign-up form), use a template with a public link: each visitor enters their name and email and gets their own document.