Embedded components
Embedded Signing
Let users review and sign documents directly inside your web app with embedded iframes. Mint one-time signing tokens and enforce signing order sequences.
Last updated:
On this page
Overview
Embedded signing allows your users to sign agreements directly within your application interface without receiving an email invitation link or being redirected to an external domain.
The signer reviews the document, navigates required fields, adopts or draws an e-signature, and submits the completed envelope. All interactions occur inside a secure, sandboxed iframe.
Configuring embedded signers
A signer signs in your app when their deliveryMode is "EMBEDDED". Signers added in the embedded sender widget are EMBEDDED by default. When you create an envelope with POST /api/v1/inkfree/envelopes (see Envelopes) or a draft with POST /api/v1/inkfree/embed/drafts, set it on the signer:
"signers": [
{
"id": 0,
"name": "Ana Ruiz",
"email": "ana@example.com",
"deliveryMode": "EMBEDDED"
}
]Signer eligibility rules
An embedded signer must be a regular signer with a valid email. An embedded signer cannot be a CC recipient or carry the reviewer role in the signers list, cannot be sent a link by SMS, and cannot delegate. (Approvers are set under approval.reviewers instead; see Embedded approvers.) It can have an access code or a one-time code (by email or text): the signer is asked for it inside the iframe before the document opens. You can mix embedded and email signers on one envelope. Bulk send does not support embedded signers. Inkfree also does not return a signing link for an embedded signer in GET /api/v1/inkfree/envelopes/{id}; the only way in is a token from your server.
Mint a signing session token
/api/v1/inkfree/embed/sessionsMint a one-time token for an embedded signer
Requires the X-API-Key header
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
scope | string | Required | Must be "signing". |
requestId | string | Required | The envelope id. The envelope must be Pending for a signer, or InReview for an approver. |
signerEmail | string | Required | The email of the person who will open the widget, not case sensitive. While the envelope is InReview and the email is an approver's, the token is for that approver; otherwise it must match an EMBEDDED signer. |
parentOrigin | string | Required | The origin of the page that will show the widget, registered under Settings > API Keys > Embedded signing origins (for example https://app.example.com). |
Example curl command
curl -X POST "https://services.softsages.com/core/api/v1/inkfree/embed/sessions" \
-H "X-API-Key: sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"scope": "signing",
"requestId": "e4b281f9a0c3451ea9f1388b7d23a105",
"signerEmail": "ana@example.com",
"parentOrigin": "https://app.example.com"
}'Responses
{
"token": "YOUR_ONE_TIME_TOKEN",
"scope": "signing",
"requestId": "e4b281f9a0c3451ea9f1388b7d23a105",
"expiresInSeconds": 300
}The token works once and expires after 300 seconds. Mint it when your user opens the page, then pass it straight to the browser.
requestId or signerEmail, an unknown scope, SIGNER_NOT_EMBEDDED, NOT_YOUR_TURN, or the envelope is not in the state this email needs: Pending for a signer, InReview for an approver (REQUEST_COMPLETED, REQUEST_VOIDED, REQUEST_EXPIRED, REQUEST_DECLINED, REQUEST_NOT_READY). For a signer, REQUEST_NOT_READY means the envelope is still waiting for its approvers (InReview) or for its scheduled send time (Scheduled); poll the envelope until it is Pending. An approver's token is minted while the envelope is InReview and does not get REQUEST_NOT_READY for that (see Embedded approvers). A signer who has already signed, or an approver who has already approved, also gets REQUEST_COMPLETED. A rejected envelope gives REQUEST_DECLINED.ORIGIN_NOT_REGISTERED, or your account is scheduled for deletion.REQUEST_NOT_FOUND or SIGNER_NOT_FOUND (that email is not a signer on the envelope).Validation rules & signing order
Inkfree issues a signing token only when all of these are true:
- Your API key is active and your account is open.
parentOriginis registered under Settings > API Keys > Embedded signing origins.- The envelope exists and its status is
Pending: approvers, if any, have approved and a scheduled send time has passed (REQUEST_NOT_READYotherwise). An approver's token is the exception, see below. - The email belongs to a signer on the envelope with
deliveryMode: "EMBEDDED", who is a regular signer (not a CC recipient). While the envelope isInReview, it may instead belong to anEMBEDDEDapprover underapproval.reviewers. - The signer has not signed yet. An access code or one-time code on the signer does not stop the token: the signer enters it inside the iframe.
- Signing order: If the envelope uses a signing order, it must be this signer's turn. A token requested before the earlier signers have signed is refused with
NOT_YOUR_TURN.
Handling sequential signing
Subscribe to the signer.signed webhook on your server. When signer 1 has signed, tell your app that signer 2 can start. Mint signer 2's token only at that moment, when signer 2 opens the page, so the 300 seconds are not used up while they wait.
Embedded approvers
Approvers can approve inside your app too, with the same token call and the same widget. An approver is embedded when their deliveryMode is "EMBEDDED"; every approver added in the sender widget or pre-filled on a draft is. Inkfree sends an embedded approver no email.
- After sending, the envelope is
InReview. Read it and find the approvers underapproval.reviewerswithstatusPending. - Mint a token with
scope: "signing"and the approver's email assignerEmail. - Mount the widget with
type: "sign". The approver sees the document with Approve and Reject. - The widget sends
approval_viewed, thenapproval_completedorapproval_rejected. Confirm on your server: when every approver has approved, the envelope becomesPendingand you can mint tokens for the signers. A rejection makes itRejected.
An approver gets a token only while they are Pending and it is their turn. An approver who is not embedded gets SIGNER_NOT_EMBEDDED; one who already approved gets REQUEST_COMPLETED; with an approval order, a later approver gets NOT_YOUR_TURN. In an approver group, once one member approves the others are Skipped and get NOT_YOUR_TURN. A decision counts once. An approver with an EMAIL delivery mode (possible on envelopes you create with POST /api/v1/inkfree/envelopes) is emailed as usual.
No approval webhook
There is no webhook when an approver approves or rejects. Use the widget events as a hint and poll GET /api/v1/inkfree/envelopes/{id} to confirm.
Mounting the signing widget
Once your server returns the one-time token, initialize the widget in your web page:
<div id="signing-container" style="width: 100%; height: 750px;"></div>
<script src="https://sign.inkfree.app/embed/inkfree-embed.js"></script>
<script>
var widget = InkfreeEmbed.mount({
container: "#signing-container",
type: "sign",
token: token,
theme: {
primaryColor: "#0a7d5c",
buttonTextColor: "#ffffff"
}
});
widget.on("sign_completed", function (event) {
console.log("Document signed by:", event.data.signerRole);
// Display confirmation screen or redirect
});
widget.on("sign_declined", function () {
console.log("Document was declined by signer");
});
</script>A signer who completes the flow produces these events, in order: ready, signer_viewed, sign_started (once, when the signer fills the first field or adopts a signature) and sign_completed. A signer who declines produces sign_declined instead, and the decline reason stays inside Inkfree. After sign_completed or sign_declined the widget stays on a final screen until your page removes it. sign_completed means this signer's signature was accepted; other signers may still be pending. See the SDK reference for every event and error code.
Confirming results on your server
Client-side browser events can fail to dispatch if the user closes their browser immediately after pressing Complete or drops connection. Always confirm completion server-to-server:
- Webhook notifications: Subscribe to
signer.opened,signer.signed,signer.declined,envelope.completedand, where identity verification is used,signer.identity_verifiedandsigner.identity_verification_blocked. There is no webhook when approvers approve or when a scheduled send goes out: poll the envelope for those. - Query envelope status: Call
GET /api/v1/inkfree/envelopes/{id}to inspect current completion status. The response carries each signer'sdeliveryModeandstatus, the approvers underapproval.reviewers(withstatusanddeliveryMode; nourlfor embedded approvers),scheduleTimeand thesignRequestConfigpermissions. - Download the signed PDF: Call
GET /api/v1/inkfree/envelopes/{id}/document?signed=trueto download the legal PDF and certificate. The signing frame offers a download button after signing unless the sender switched offsignRequestConfig.allowDocumentDownload(on by default); the file is downloaded in the iframe, so keep the SDK's default sandbox. You can always fetch the signed file from your server instead.
Envelope dispatched webhook note
An envelope whose recipients are all embedded signers (no email signers and no CC recipients) does not emit an envelope.sent webhook, because Inkfree sends no email. Do not wait for that event; use signer.signed and envelope.completed instead.
Email notifications behavior
- Embedded signers and approvers: Receive no invitation emails, reminder notifications or SMS texts from Inkfree.
- Email signers and CC recipients: Receive Inkfree's standard email notifications as usual when mixed on the same envelope.
- Completion notifications: Delivery of final completion emails respects
signRequestConfig.sendNotificationOnCompletion. Set this tofalseif your signers should not receive emails from Inkfree upon envelope completion. The sender is always copied on completion.