---
title: "Embedded signing"
url: "https://docs.signnow.com/docs/guides-embedded-signing"
type: "page"
section: "Documentation"
slug: "guides-embedded-signing"
---

# Embedded signing

# About embedded signing

API users can embed SignNow into their website or app to allow their customers to sign documents without sending them emails, and without leaving the website. No additional registration required, no email, no interruptions to the workflow built in your app.

Embedding SignNow into your application allows you to add a link that opens a document in a SignNow iFrame directly within the app. The process consists of two steps:

1. Prepare a document for signature by creating an embedded invite to sign.
2. Generate a link for the invite to build into your app.

**Before you begin**

Before composing your request, make sure that:

- you are the owner of the document or document group
- you are about to create an invite for a document, not a template
- your document contains [fields](/docs/fields)
- your document is not in _pending_ or _signed_ status
- all the roles or role IDs in the document are assigned to signers of the invite

---

## Signing features

Embedded signing is available for [documents](/docs/document-embedded-signing/operations/create-embedded-signing-invite) and [document groups](/docs/doc-group-embedded-signing/operations/create-embedded-invite-document-group). It can be set up for multiple signers who must sign the document in a specific order just like in a regular [invite to sign in SignNow](/docs/document-field-invite/operations/post-field_invite). Different fields in the document can be assigned to separate signer roles. The information provided in the fields can be used to generate a name for a signed copy automatically before saving it. Signers may verify their identity via three different methods of authentication.

### Recipient roles

An embedded invite can include three recipient types:

- **Signer**: signs the document and fills in the assigned fields.
- **Viewer**: opens the document in read-only mode without signing or filling fields. Available for the [document group embedded invite](/docs/doc-group-embedded-signing/operations/create-embedded-invite-document-group).
- **Approver**: reviews and approves the document without signing or filling fields. Use it when someone needs to confirm content before or after signers act on it.

The structure differs by endpoint:

- For [document embedded invites](/docs/document-embedded-signing/operations/create-embedded-signing-invite), approvers are added in a separate `approvers` array alongside `invites`.
- For [document group embedded invites](/docs/doc-group-embedded-signing/operations/create-embedded-invite-document-group), approvers and viewers are entries inside the shared `signers` array, distinguished by `action: approve` on each document.

_Example 1. Create document embedded invite payload_

```json
{
  "name_formula": "document_name|signer1_name|signer2_name|signer3_name|date",
  "invites": [
    {
      "email": "signer_1_@email.com",
      "role_id": "role_id_1",
      "order": 1,
      "auth_method": "none",
      "first_name": "Jane",
      "last_name": "Doe",
      "prefill_signature_name": "Jane Doe",
      "force_new_signature": 1,
      "redirect_uri": "https://example.com",
      "delivery_type": "email", 
      "subject": "Sign the document",
      "message": "Please review the document and sign it at your earliest convenience.",
      "authentication": {
        "type": "password",
        "password": "password123"
      }
    },
    {
      "email": "signer_2_@email.com",
      "role_id": "role_id_2",
      "order": 1,
      "auth_method": "none",
      "first_name": "John",
      "last_name": "Doe",
      "authentication": {
        "type": "phone",
        "method": "phone_call",
        "phone": "+1XXX-XXXXXXX"
      }
    },
    {
      "email": "signer_3_@email.com",
      "role_id": "role_id_3",
      "order": 2,
      "auth_method": "none",
      "first_name": "Jane",
      "authentication": {
        "type": "phone",
        "method": "sms",
        "phone": "+1XXX-XXXXXXX",
        "sms_message": "Your custom sample message with {password}"
      }
    }
  ],
  "approvers": [
    {
      "email": "approver_1_@email.com",
      "role": "Approver 1",
      "order": 3,
      "auth_method": "none",
      "first_name": "Sarah",
      "last_name": "Williams",
      "authentication": {
        "type": "password",
        "password": "approverpass456"
      }
    }
  ],
  "from_email": "anna.green@email.com",
  "from_name": "Anna Green"
}
```

### Recipient authentication during the signing session

There are three identity verification methods you can add to an embedded document or document group invite. When recipients open the document or document group in your application, they must complete authentication before signing. 

**Authentication type: `phone`**

**Method: `sms`**

This type of authentication requires a signer to provide the password sent via SMS to their phone number. When using this type in the invite, you can set up the text message which contains a {password} placeholder.

```json
{
  "authentication": {
    "type": "phone",
    "method": "sms",
    "phone": "+1XXXXXXXXX",
    "sms_message": "Custom test message with {password}"
  }
}
```

**Authentication type: `phone`**

**Method: `phone_call`**

This type of authentication is used to verify the signer’s identity with a password delivered through a phone call.

```json
{
  "authentication": {
    "type": "phone",
    "method": "phone_call",
    "phone": "+1XXXXXXXXX"
  }
}
```

**Authentication type: `password`**

This type of authentication requires a signer to provide a password to the document for signature.

```json
{
  "authentication": {
    "type": "password",
    "password": "abc123"
  }
}
```

_Example: Authentication type password_

![enter-password.png](/reference-assets/images/Embedded%20signing%20guide/enter-password.png)

### Authentication methods used in the integrated application

The `auth_method` parameter is defined by the application owner to specify the method used to authenticate the signer within the integrated application.

Possible values are: `password`, `email`, `mfa`, `biometric`, `social`, `other`, `none`. 

The `auth_method` parameter is saved to the document history along with a client ID. You can retrieve the predefined `auth_method` with [`GET /document/{{doc_id}}/historyfull`](/docs/document/operations/get-document-historyfull) request.

<!-- theme: danger -->
> The `auth_method` parameter does not influence the signer's authentication method during the signing session. Use the `authentication` parameter to configure the signer's authentication for the signing session.

### Name generation (name_formula)

Embedded signing provides an option of generating the **signed document name** using the `name_formula` parameter. 

To create a formula combine any text (this part would be a text prefix) with **field names** from your document. SignNow extracts contents from the given fields and uses them in the name generation. Contents of the fields must be provided by the signer, so the name generation **starts only when the document has been completed**.

#### Formula syntax

Use pipes `|` to separate the prefix and the field names.

#### Example

**Formula**: `text_prefix|signer_name|signed_date`

**Text prefix:** Contract

**Document field 1**: (`signer_name`): User enters `John Smith`

**Document field 2**: (`signed_date`): User enters `20.01.2026`

Resulting document name: `Contract John Smith 20.01.2026`

> You cannot use signature fields for `name_formula`.

### Options for adding a signature

```json
{
  "email": "signer@email.com",
  "role_id": "c8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "order": 1,
  "auth_method": "none",
  "prefill_signature_name": "Jane Doe",
  "required_preset_signature_name": "Jane Doe",
  "force_new_signature": 0
}
```

| Parameter | Description |
|-----------|-------------|
| `prefill_signature_name` | The text displayed in the Signature field. The signer can edit this value. |
| `required_preset_signature_name` | The text displayed in the Signature field. The signer **cannot** edit this value. Cannot be used simultaneously with `prefill_signature_name` or `force_new_signature` for the same role. |
| `force_new_signature` | Defines whether the signer can use their saved signature. `0` — signer can use a saved signature; `1` — signer must add a new signature. |


![prefilled-for-signer.png](/reference-assets/images/Embedded%20signing%20guide/prefilled-for-signer.png)


### Redirect URIs and language parameters

In the embedded invite, you can also specify a page that opens after the document has been completed. To do so, add a link to the selected page in the `redirect_uri` parameter. You can set up different links for different signer actions, such as a separate page for when a signer declines to sign or closes the signing session.

```json
{
      "email": "signer@email.com",
      "role_id": "c8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "order": 1,
      "auth_method": "none",
      "language": "en", 
      "redirect_uri": "https://signnow.com",
      "decline_redirect_uri": "https://airslate.com",
      "close_redirect_uri": "https://blog.signnow.com/category/developers",
      "redirect_target": "self"
    }
```

| Parameter | Description |
|-----------|-------------|
| `redirect_uri` | When all requested fields are completed and signed, the signer is redirected to this URI. |
| `decline_redirect_uri` | The link that opens when the signer declines to sign the document. |
| `close_redirect_uri` | The link that opens when a signer clicks **Save Progress and Finish Later** during a signing session or **Close** in view mode. |
| `redirect_target` | Defines how redirect URIs are opened. `blank` — opens in a new browser tab; `self` — opens in the same tab. |
| `language` | Sets the language of the signing session. Possible values: `en` (English), `es` (Spanish), `fr` (French). |

> Note that redirect parameters are not supported for approvers.

### Invite email settings

If you send the embedded invite with recipients by email, you can customize the email subject and message. Note that `subject`,`message`, `session_expiration`, and `link_expiration` are available when `delivery_type` is set to `email`.

```json
{
    "invites": [
        {
            "email": "signer@email.com",
            "role_id": "c8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "order": 1,
            "auth_method": "none",
            "delivery_type": "email",
            "subject": "Review and sign the document.",
            "message": "Please review the document and sign it at your earliest convenience.",
            "link_expiration": 43200,
            "session_expiration": 1440

        }
    ]
}
```

#### Link and session expiration

- `link_expiration` — how long the email invite link remains valid before it expires. Ranges from 15 to 43,200 minutes (30 days). 15 minutes by default.
- `session_expiration` — how long the signing session stays active once opened. Ranges from 15 to 1,440 minutes (24 hours). Resets each time a new signing link is generated.

<!-- theme: danger -->
> **Session expiration and auto-completion**<br>When `session_expiration` runs out, the signing session ends automatically. Documents without required signing fields are marked as completed, and the `document_group.complete` webhook fires — even if not all documents with signing fields have been signed.

Note that the session expiration timer resets each time a new signing link is generated for the invite.

> For large document groups (10+ documents), set `session_expiration` to 60 minutes or higher (maximum 1,440 minutes). After receiving the `document_group.complete` webhook, always verify the actual completion status with [`GET /documentgroup/{{document_group_id}}`](/docs/document-group/operations/get-documentgroup) or [`GET /v2/document-groups/{{document_group_id}}`](/docs/document-group/operations/get-document-group-info-v2) before processing.

### Sender's email address and name

Using the `from_email` and `from_name` parameters, customize the appearance of the sender's email address and name.

```json
{
  "from_email": "anna.green@email.com",
  "from_name": "Anna Green"
}
```

`from_email`: Use this attribute to customize the email address that appears: 1) in the invite, reassign, reminder, and complete emails: in email **subject** (part before @) and email **body;** when clicking **Contact Sender**, and in **Reply-to**; 2) in the signing session: when clicking **Contact Sender** in the **More Actions** menu.

<details>

**<summary>from_email in the UI</summary>**

![from_email_invites.png](/reference-assets/images/Embedded%20signing%20guide/from_email_invites.png)

![from_email_invites_contact_replyto.png](/reference-assets/images/Embedded%20signing%20guide/from_email_invites_contact_replyto.png)

![from_email_ss.png](/reference-assets/images/Embedded%20signing%20guide/from_email_ss.png)

</details>

`from_name`: Use this attribute to customize the name that appears in email **subject** of the invite, reassign, reminder, and completed emails.

<details>

**<summary>from_name in the UI</summary>**

![from_name_invites.png](/reference-assets/images/Embedded%20signing%20guide/from_name_invites.png)

</details>

> Both parameters are optional and are applied only when `delivery_type` = `email`.

Explore the three scenarios of passing the `from_name` and `from_email` parameters:

#### When both `from_email` and `from_name` are passed:

The custom `from_name` appears:

- in email subject of the invite, reassign, reminder, and completed emails.

The custom `from_email` appears:

- in email body of the invite, reassign, reminder, and completed emails.
- when clicking **Contact Sender** and in **Reply-to** in the emails.
- in the signing session: when clicking **Contact Sender** in the **More Actions** menu.

---

#### When only `from_email` is passed:

The part of `from_email` (before `@`) appears:

- in email subject of the invite, reassign, reminder, and completed emails.

The custom `from_email` appears:

- in email body of the invite, reassign, reminder, and completed emails.
- when clicking **Contact Sender** and in **Reply-to** in the emails.
- in the signing session: when clicking **Contact Sender** in the **More Actions** menu.

---

#### When only `from_name` is passed:

The custom `from_name` appears:

- in email subject of the invite, reassign, reminder, and completed emails.

The default (owner’s) `from_email` appears:

- in email body of the invite, reassign, reminder, and completed emails.
- when clicking **Contact Sender** and in **Reply-to** in the emails.
- in the signing session: when clicking **Contact Sender** in the **More Actions** menu.

> The priority for customizing the sender's email address and name is as follows:<br> 1. `from_email`/`from_name`<br> 2. Invite settings<br> 3. Branding at document / document group / application / user level<br> 4. Generic<br> 5. Branding at organization level

<!-- theme: success -->
> Get the existing `from_email` and `from_name` attributes using the [Get document](/docs/document/operations/get-document) (in `document_attributes`) request, or [Get document group](/docs/document-group/operations/get-documentgroup), [Get document group info](/docs/document-group/operations/get-document-group-info-v2) (in `document_group_attributes`) requests.

## Brand customization

If you want to personalize the signing session (colors, logo, element visibility) you can do so with [SignNow branding](/docs/guides-branding).

## Embedded link in your system

Once all the settings have been applied and the embedded invite is created, the invite object itself remains in the SignNow application. To build it into your website, [generate a link to this invite](/docs/document-embedded-signing/operations/generate-link-for-embedded-invite).

_Example of the request for link generation_

```bash
curl --request POST \
  --url https://api.signnow.com/v2/documents/{{document_id}}/embedded-invites/{{field_invite_id}}/link/ \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer {{access_token}}' \
  --header 'Content-Type: application/json' \
  --data '{
  "auth_method": "none",
  "link_expiration": 15
}'
```

## Embedded in iFrame

If you use an iFrame for an embedded signing, then be sure to set the iFrame dimensions to 100% by 100%. This is necessary so that the signing session and user experience will be correct for the signer, especially on mobile devices.

## Create embedded signature invite

### Step 1. Upload a document

First, add the document that you’d like to have signed. There are three options to do so:

- [Upload a document](/docs/document/operations/upload-document)

```bash
curl --request POST \
--url https://api.signnow.com/document \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{access_token}}' \
--header 'Content-Type: multipart/form-data' \
--form file=@/path/to/your/file.pdf
```

- [Upload a document from URL](/docs/document/operations/post-v2-documents-url)

```bash
curl --request POST \
--url https://api.signnow.com/v2/documents/url \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{access_token}}' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://file.com"
}'
```

- [Upload a document which contains the text tags](/docs/document/operations/upload-document-with-text-tags)

```bash
curl --request POST \
--url https://api.signnow.com/document/fieldextract \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{access_token}}' \
--header 'Content-Type: multipart/form-data' \
--form file= \
--form Tags= \
--form 'Tags[]:tag_name='
```

### [Step 2. Add fields](/docs/request-payments/operations/put-document-document_id)

Let's add one signature field and two text fields.

```bash
curl --location --request PUT 'https://api.signnow.com/document/{{document_id}}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{access_token}}' \
--data '{
  "fields": [
    {
      "page_number": 1,
      "type": "signature",
      "name": "signature_1",
      "role": "Signer 1",
      "required": true,
      "height": 40,
      "width": 50,
      "x": 260,
      "y": 60
    },
    {
      "page_number": 0,
      "type": "text",
      "name": "signer_name",
      "role": "Signer 1",
      "required": true,
      "height": 40,
      "width": 50,
      "x": 217,
      "y": 32
    },
    {
      "page_number": 0,
      "type": "text",
      "name": "signed_date",
      "role": "Signer 1",
      "required": true,
      "height": 40,
      "width": 50,
      "x": 260,
      "y": 80
    }
  ]
}'
```

### [Step 3. Get the role id or name](/docs/document/operations/get-document)

Make a [Get document](/docs/document/operations/get-document) request to extract the role ID or role name. You can find it in the roles array.

```json
 "roles": [
        {
            "unique_id": "26XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "signing_order": "1",
            "name": "Signer 1"
        }
    ]
```

### [Step 4. Create embedded invite for document](/docs/document-embedded-signing/operations/create-embedded-signing-invite)


```bash
curl --request POST \
  --url https://api.signnow.com/v2/documents/{{document_id}}/embedded-invites \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer {{access_token}}' \
  --header 'Content-Type: application/json' \
  --data '{
  "name_formula": "Contract|signer_name|signed_date",
  "invites": [
    {
      "email": "signer@email.com",
      "role_id": "26XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "order": 1,
      "auth_method": "none",
      "first_name": "John",
      "last_name": "Doe"
    }
  ],
  "approvers": [
    {
      "email": "approver@email.com",
      "role": "Approver 1",
      "order": 2,
      "auth_method": "none",
      "first_name": "Sarah",
      "last_name": "Williams"
    }
  ]
}'
```

_Response_

```json
{
  "data": [
    {
      "id": "13XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "email": "signer@email.com",
      "role_id": "26XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "order": 1,
      "status": "pending"
    },
    {
      "id": "a7XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "email": "approver@email.com",
      "role_id": "44XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "order": 2,
      "status": "created"
    }
  ]
}
```

> Learn more about [name_formula parameter](/docs/guides-embedded-signing#name-generation-name_formula). 

### [Step 4b. Create embedded invite for a document group](/docs/doc-group-embedded-signing/operations/create-embedded-invite-document-group)

For a document group embedded invite, approvers go into the same `signers` array as signers, distinguished by `action: "approve"` on each document. Approver-step rules:

- Only one approver is allowed per invite step.
- A step that contains an `approve` action must not include any other actions (no mixing with `sign` or `view` in the same step).
- The approver must reference every document ID in the document group.

```bash
curl --request POST \
  --url https://api.signnow.com/v2/document-groups/{{document_group_id}}/embedded-invites \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer {{access_token}}' \
  --header 'Content-Type: application/json' \
  --data '{
  "invites": [
    {
      "order": 1,
      "signers": [
        {
          "email": "approver@email.com",
          "auth_method": "none",
          "first_name": "Sarah",
          "last_name": "Williams",
          "documents": [
            {
              "id": "19XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
              "role": "Approver 1",
              "action": "approve"
            },
            {
              "id": "06XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
              "role": "Approver 1",
              "action": "approve"
            }
          ]
        }
      ]
    },
    {
      "order": 2,
      "signers": [
        {
          "email": "signer@email.com",
          "auth_method": "none",
          "first_name": "John",
          "last_name": "Doe",
          "documents": [
            {
              "id": "19XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
              "role": "Signer 1",
              "action": "sign"
            }
          ]
        }
      ]
    }
  ]
}'
```

_Response_

```json
{
  "data": {
    "id": "0cXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  }
}
```

### [Step 5. Generate signing link](/docs/document-embedded-signing/operations/generate-link-for-embedded-invite)

Use the embedded invite ID from the **Step 4** response to create a signing link.

> For document groups, replace `/documents/` with `/document-groups/` in the URL.

> The `auth_method` should match the one used when creating the embedded invite.

> `link_expiration` sets how long the generated signing link remains valid: from 15 to 45 minutes, 15 minutes by default.

```bash
curl --request POST \
  --url https://api.signnow.com/v2/documents/{{document_id}}/embedded-invites/{{embedded_invite_id}}/link/ \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer {{access_token}}' \
  --header 'Content-Type: application/json' \
  --data '{
  "auth_method": "none",
  "link_expiration": 45
}'
```

### Step 6. Open the embedded link

Here is how a signer will go through the signing process via an embedded link.

![embedded_signing.gif](/reference-assets/images/Embedded%20signing%20guide/embedded_signing.gif)

## Reuse the same documents for many signers

If every signer completes the same documents, prepare them once instead of uploading files and placing fields for each signing session. Create a copy per signer from a template, then run the embedded invite steps against that copy. The template stays untouched as the master version, and each signer works on an isolated copy.

There are two entry points, depending on how many documents each signer receives:

| Start from | Create the copy with | Then run |
|---|---|---|
| A document group template | [Create doc group from template](/docs/document-group-template/operations/post-v2-document-group-templates-unique_id-document-group) | **Step 4b** and **Step 5** |
| A document template | [Create document from template](/docs/template/operations/get-template-copy) | **Step 3**, **Step 4**, and **Step 5** |

Both are covered in [Documents, doc groups, and templates](/docs/entities), at **Step 8** and **Step 4** respectively. The [Sign PDFs in WordPress](/docs/sign-pdfs-in-wordpress) guide walks through the document group route end to end, from building the group to embedding the signing link in a page.

<!-- theme: warning -->

> **Note**: The copy keeps the template's fields and role names, but its document IDs, field IDs, and role IDs are all newly generated. Take the document IDs from the response that created the copy, and the role IDs from [Get document](/docs/document/operations/get-document) for that copy. Never reuse the template's IDs.

You cannot create an embedded invite for a template. Templates are masters for generating documents: create a document or document group from the template first, then invite recipients to that copy.

## Troubleshooting

| Error | Likely cause | What to do |
|---|---|---|
| 400 on **Finish** button | The signing session expired during the signing process. | Increase the `session_expiration` value. |
| CORS or network errors | Your domain is not allowed or a corporate firewall is blocking SignNow API calls. | Verify your domain is allowed and check firewall settings. |
| Unexpected behavior during signing | A browser extension is interfering with the signing session. | Test in incognito mode to rule out browser extension conflicts. |
| `The field invite is not pending or fulfilled.` (code `19001028`) when generating a signing link | The signer's invite is not in `pending` status: it was already signed, declined, or canceled, or an earlier signer in the signing order hasn't completed their step yet. | Check the invite status in the `field_invites` array of the [document details](/docs/document/operations/get-document) and request the link for a signer whose invite is `pending`. |
| `The current and field invite auth method is not the same.` (code `19015001`) when generating a signing link | The `auth_method` in the link request differs from the one set when the embedded invite was created. | Use the same `auth_method` value in both requests. |
| `Role {role_id} was not specified in any invite. All roles must be used.` when creating an embedded invite | The embedded invite must cover every role defined on the document. | Include an invite for each role in the request, or remove unused roles from the document or template. |
| `Cannot send invites for templates.` (code `19001003`) when creating an embedded invite | The ID in the request belongs to a template, not a document. | Create a document or document group from the template, then create the embedded invite for that copy. See [Reuse the same documents for many signers](/docs/guides-embedded-signing#reuse-the-same-documents-for-many-signers). |
| `Document not found` (code `19002001`) when creating an embedded invite | The ID doesn't identify a document available to the account that made the request. | Use the document IDs returned when you created the document or document group for this session, and authorize the request with the document owner's access token. |

## Try out in Postman

[Access](https://www.postman.com/signnow-api/workspace/signnow-public-collection/collection/24778743-ab521581-0e29-4ff5-8c90-41f364a312fb?action=share\&creator=24778743) this flow in Postman, and feel free to embed signing sessions into your system.

For more information, watch the video tutorial

https://youtu.be/8gVwWhTCWRU?si=msOprnj5ZKBOPghu.



---
*Full page: https://docs.signnow.com/docs/guides-embedded-signing*
