# Embedded Templates
> Allow users to create and edit templates inside your app with Dropbox Sign Embedded Templates. To find out how to build with this feature, click here.
# Embedded Templates Walkthrough
Embedded templates allow your users to create and edit templates on your site in an iFrame using [hellosign-embedded](https://github.com/hellosign/hellosign-embedded), Dropbox Sign's official client-side library. Templates are used to make frequently-used documents easier to send for signatures and share with others. They're also a powerful tool for automating workflows and using pre-filled data in your signature requests.
## Preliminary
Please complete the steps below before following along with the content.
1. [Create an API app](https://app.hellosign.com/oauth/createAppForm) (login required)
The API app domain name specifies where the iFrame can be opened. Embedded Template creation will only be possible on pages from this domain and its subdomains. However, you can use `skipDomainVerification` to embed requests created using `test_mode`.
2. Save your API app's Client ID and [API Key](/api/api-reference-authentication#api-key), which you'll need to use this feature.
## Try Dropbox Sign Embedded
To get a feel for how our Dropbox Sign Embedded library works, you can use our [Embedded Testing Tool](/docs/additional-resources/embedded-testing-tool) to quickly test any of our Embedded flows without having to write a single line of JavaScript.
You can request a sample document, or use the custom `claim_url` or `edit_url` that you'll generate in the [Server Side](#server-side) section below.
## Server Side
Allowing your site users to create a template involves first creating a template draft. This draft will be displayed on your site in an embedded iFrame, allowing the user to edit and finalize the template. Note that templates created via the embedded template process will only be accessible through the API.
### Creating a Template
Create a template draft by POSTing an API request to `https://api.hellosign.com/v3/template/create_embedded_draft` with the following parameters:
{/* */}
```json title="Default Example"
{
"client_id": "37dee8d8440c66d54cfa05d92c160882",
"file_urls": [
"https://www.dropbox.com/s/ad9qnhbrjjn64tu/mutual-NDA-example.pdf?dl=1"
],
"title": "Test Template",
"subject": "Please sign this document",
"message": "For your approval",
"signer_roles": [
{
"name": "Client",
"order": 0
},
{
"name": "Witness",
"order": 1
}
],
"cc_roles": [
"Manager"
],
"merge_fields": [
{
"name": "Full Name",
"type": "text"
},
{
"name": "Is Registered?",
"type": "checkbox"
}
],
"field_options": {
"date_format": "DD - MM - YYYY"
},
"test_mode": true
}
```
```json title="Form Fields Per Document Example"
{
"client_id": "37dee8d8440c66d54cfa05d92c160882",
"file_urls": [
"https://www.dropbox.com/s/ad9qnhbrjjn64tu/mutual-NDA-example.pdf?dl=1"
],
"title": "Test Template",
"subject": "Please sign this document",
"message": "For your approval",
"signer_roles": [
{
"name": "Client",
"order": 0
},
{
"name": "Witness",
"order": 1
}
],
"cc_roles": [
"Manager"
],
"merge_fields": [
{
"name": "Full Name",
"type": "text"
},
{
"name": "Is Registered?",
"type": "checkbox"
}
],
"field_options": {
"date_format": "DD - MM - YYYY"
},
"form_fields_per_document": [
{
"document_index": 0,
"api_id": "uniqueIdHere_1",
"name": "",
"placeholder": "",
"type": "text",
"x": 112,
"y": 328,
"width": 100,
"height": 16,
"required": true,
"signer": 1,
"page": 1,
"validation_type": "numbers_only"
},
{
"document_index": 0,
"api_id": "uniqueIdHere_2",
"name": "",
"type": "signature",
"x": 530,
"y": 415,
"width": 120,
"height": 30,
"required": true,
"signer": 0,
"page": 1
}
],
"test_mode": true
}
```
```json title="Form Fields Per Document and Groups Example"
{
"client_id": "37dee8d8440c66d54cfa05d92c160882",
"file_urls": [
"https://www.dropbox.com/s/ad9qnhbrjjn64tu/mutual-NDA-example.pdf?dl=1"
],
"title": "Test Template",
"subject": "Please sign this document",
"message": "For your approval",
"signer_roles": [
{
"name": "Client",
"order": 0
},
{
"name": "Witness",
"order": 1
}
],
"cc_roles": [
"Manager"
],
"merge_fields": [
{
"name": "Full Name",
"type": "text"
},
{
"name": "Is Registered?",
"type": "checkbox"
}
],
"field_options": {
"date_format": "DD - MM - YYYY"
},
"form_fields_per_document": [
{
"document_index": 0,
"api_id": "uniqueIdHere_1",
"name": "",
"type": "radio",
"x": 112,
"y": 328,
"width": 18,
"height": 18,
"required": false,
"group": "RadioItemGroup1",
"is_checked": 1,
"signer": 0,
"page": 1
},
{
"document_index": 0,
"api_id": "uniqueIdHere_2",
"name": "",
"type": "radio",
"x": 112,
"y": 370,
"width": 18,
"height": 18,
"required": false,
"group": "RadioItemGroup1",
"is_checked": 0,
"signer": 0,
"page": 1
}
],
"form_field_groups": [
{
"group_id": "RadioItemGroup1",
"group_label": "Radio Item Group 1",
"requirement": "require_0-1"
}
],
"test_mode": true
}
```
```json title="Form Fields Per Document and Rules Example"
{
"client_id": "37dee8d8440c66d54cfa05d92c160882",
"file_urls": [
"https://www.dropbox.com/s/ad9qnhbrjjn64tu/mutual-NDA-example.pdf?dl=1"
],
"title": "Test Template",
"subject": "Please sign this document",
"message": "For your approval",
"signer_roles": [
{
"name": "Client",
"order": 0
},
{
"name": "Witness",
"order": 1
}
],
"cc_roles": [
"Manager"
],
"merge_fields": [
{
"name": "Full Name",
"type": "text"
},
{
"name": "Is Registered?",
"type": "checkbox"
}
],
"field_options": {
"date_format": "DD - MM - YYYY"
},
"form_fields_per_document": [
{
"document_index": 0,
"api_id": "uniqueIdHere_1",
"name": "",
"type": "radio",
"x": 112,
"y": 328,
"width": 18,
"height": 18,
"required": false,
"group": "RadioItemGroup1",
"is_checked": 1,
"signer": 0,
"page": 1
},
{
"document_index": 0,
"api_id": "uniqueIdHere_2",
"name": "",
"type": "radio",
"x": 112,
"y": 370,
"width": 18,
"height": 18,
"required": false,
"group": "RadioItemGroup1",
"is_checked": 0,
"signer": 0,
"page": 1
}
],
"form_field_groups": [
{
"group_id": "RadioItemGroup1",
"group_label": "Radio Item Group 1",
"requirement": "require_0-1"
}
],
"test_mode": true
}
```
{/*
```curl cURL
curl -X POST 'https://api.hellosign.com/v3/template/create_embedded_draft' \
-u 'YOUR_API_KEY:' \
-F 'client_id=YOUR_CLIENT_ID' \
-F 'files[0]=@mutual-NDA-example.pdf' \
-F 'title=Test Template' \
-F 'subject=Please sign this document' \
-F 'message=For your approval' \
-F 'signer_roles[0][name]=Client' \
-F 'signer_roles[0][order]=0' \
-F 'signer_roles[0][name]=Witness' \
-F 'signer_roles[0][order]=1' \
-F 'cc_roles[]=Manager' \
-F 'merge_fields[0][name]=Full Name' \
-F 'merge_fields[0][type]=text' \
-F 'merge_fields[1][name]=Is Registered?' \
-F 'merge_fields[1][type]=checkbox' \
-F 'field_options[date_format]=DD - MM - YYYY' \
-F 'test_mode=1'
```
```php PHP
setUsername("YOUR_API_KEY");
// $config->setAccessToken("YOUR_ACCESS_TOKEN");
$field_options = (new Dropbox\Sign\Model\SubFieldOptions())
->setDateFormat(Dropbox\Sign\Model\SubFieldOptions::DATE_FORMAT_DD_MM_YYYY);
$merge_fields_1 = (new Dropbox\Sign\Model\SubMergeField())
->setName("Full Name")
->setType(Dropbox\Sign\Model\SubMergeField::TYPE_TEXT);
$merge_fields_2 = (new Dropbox\Sign\Model\SubMergeField())
->setName("Is Registered?")
->setType(Dropbox\Sign\Model\SubMergeField::TYPE_CHECKBOX);
$merge_fields = [
$merge_fields_1,
$merge_fields_2,
];
$signer_roles_1 = (new Dropbox\Sign\Model\SubTemplateRole())
->setName("Client")
->setOrder(0);
$signer_roles_2 = (new Dropbox\Sign\Model\SubTemplateRole())
->setName("Witness")
->setOrder(1);
$signer_roles = [
$signer_roles_1,
$signer_roles_2,
];
$template_create_embedded_draft_request = (new Dropbox\Sign\Model\TemplateCreateEmbeddedDraftRequest())
->setClientId("37dee8d8440c66d54cfa05d92c160882")
->setMessage("For your approval")
->setSubject("Please sign this document")
->setTestMode(true)
->setTitle("Test Template")
->setCcRoles([
"Manager",
])
->setFiles([
])
->setFieldOptions($field_options)
->setMergeFields($merge_fields)
->setSignerRoles($signer_roles);
try {
$response = (new Dropbox\Sign\Api\TemplateApi(config: $config))->templateCreateEmbeddedDraft(
template_create_embedded_draft_request: $template_create_embedded_draft_request,
);
print_r($response);
} catch (Dropbox\Sign\ApiException $e) {
echo "Exception when calling TemplateApi#templateCreateEmbeddedDraft: {$e->getMessage()}";
}
```
```csharp C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using Dropbox.Sign.Api;
using Dropbox.Sign.Client;
using Dropbox.Sign.Model;
namespace Dropbox.SignSandbox;
public class TemplateCreateEmbeddedDraftExample
{
public static void Run()
{
var config = new Configuration();
config.Username = "YOUR_API_KEY";
// config.AccessToken = "YOUR_ACCESS_TOKEN";
var fieldOptions = new SubFieldOptions(
dateFormat: SubFieldOptions.DateFormatEnum.DD_MM_YYYY
);
var mergeFields1 = new SubMergeField(
name: "Full Name",
type: SubMergeField.TypeEnum.Text
);
var mergeFields2 = new SubMergeField(
name: "Is Registered?",
type: SubMergeField.TypeEnum.Checkbox
);
var mergeFields = new List
{
mergeFields1,
mergeFields2,
};
var signerRoles1 = new SubTemplateRole(
name: "Client",
order: 0
);
var signerRoles2 = new SubTemplateRole(
name: "Witness",
order: 1
);
var signerRoles = new List
{
signerRoles1,
signerRoles2,
};
var templateCreateEmbeddedDraftRequest = new TemplateCreateEmbeddedDraftRequest(
clientId: "37dee8d8440c66d54cfa05d92c160882",
message: "For your approval",
subject: "Please sign this document",
testMode: true,
title: "Test Template",
ccRoles: [
"Manager",
],
files: new List
{
new FileStream(
path: "./example_signature_request.pdf",
mode: FileMode.Open
),
},
fieldOptions: fieldOptions,
mergeFields: mergeFields,
signerRoles: signerRoles
);
try
{
var response = new TemplateApi(config).TemplateCreateEmbeddedDraft(
templateCreateEmbeddedDraftRequest: templateCreateEmbeddedDraftRequest
);
Console.WriteLine(response);
}
catch (ApiException e)
{
Console.WriteLine("Exception when calling TemplateApi#TemplateCreateEmbeddedDraft: " + e.Message);
Console.WriteLine("Status Code: " + e.ErrorCode);
Console.WriteLine(e.StackTrace);
}
}
}
```
```ts TypeScript
import * as fs from 'fs';
import api from "@dropbox/sign"
import models from "@dropbox/sign"
const apiCaller = new api.TemplateApi();
apiCaller.username = "YOUR_API_KEY";
// apiCaller.accessToken = "YOUR_ACCESS_TOKEN";
const fieldOptions: models.SubFieldOptions = {
dateFormat: models.SubFieldOptions.DateFormatEnum.DdMmYyyy,
};
const mergeFields1: models.SubMergeField = {
name: "Full Name",
type: models.SubMergeField.TypeEnum.Text,
};
const mergeFields2: models.SubMergeField = {
name: "Is Registered?",
type: models.SubMergeField.TypeEnum.Checkbox,
};
const mergeFields = [
mergeFields1,
mergeFields2,
];
const signerRoles1: models.SubTemplateRole = {
name: "Client",
order: 0,
};
const signerRoles2: models.SubTemplateRole = {
name: "Witness",
order: 1,
};
const signerRoles = [
signerRoles1,
signerRoles2,
];
const templateCreateEmbeddedDraftRequest: models.TemplateCreateEmbeddedDraftRequest = {
clientId: "37dee8d8440c66d54cfa05d92c160882",
message: "For your approval",
subject: "Please sign this document",
testMode: true,
title: "Test Template",
ccRoles: [
"Manager",
],
files: [
fs.createReadStream("./example_signature_request.pdf"),
],
fieldOptions: fieldOptions,
mergeFields: mergeFields,
signerRoles: signerRoles,
};
apiCaller.templateCreateEmbeddedDraft(
templateCreateEmbeddedDraftRequest,
).then(response => {
console.log(response.body);
}).catch(error => {
console.log("Exception when calling TemplateApi#templateCreateEmbeddedDraft:");
console.log(error.body);
});
```
```java Java
package com.dropbox.sign_sandbox;
import com.dropbox.sign.ApiException;
import com.dropbox.sign.Configuration;
import com.dropbox.sign.api.*;
import com.dropbox.sign.auth.*;
import com.dropbox.sign.JSON;
import com.dropbox.sign.model.*;
import java.io.File;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TemplateCreateEmbeddedDraftExample
{
public static void main(String[] args)
{
var config = Configuration.getDefaultApiClient();
((HttpBasicAuth) config.getAuthentication("api_key")).setUsername("YOUR_API_KEY");
// ((HttpBearerAuth) config.getAuthentication("oauth2")).setBearerToken("YOUR_ACCESS_TOKEN");
var fieldOptions = new SubFieldOptions();
fieldOptions.dateFormat(SubFieldOptions.DateFormatEnum.DD_MM_YYYY);
var mergeFields1 = new SubMergeField();
mergeFields1.name("Full Name");
mergeFields1.type(SubMergeField.TypeEnum.TEXT);
var mergeFields2 = new SubMergeField();
mergeFields2.name("Is Registered?");
mergeFields2.type(SubMergeField.TypeEnum.CHECKBOX);
var mergeFields = new ArrayList(List.of (
mergeFields1,
mergeFields2
));
var signerRoles1 = new SubTemplateRole();
signerRoles1.name("Client");
signerRoles1.order(0);
var signerRoles2 = new SubTemplateRole();
signerRoles2.name("Witness");
signerRoles2.order(1);
var signerRoles = new ArrayList(List.of (
signerRoles1,
signerRoles2
));
var templateCreateEmbeddedDraftRequest = new TemplateCreateEmbeddedDraftRequest();
templateCreateEmbeddedDraftRequest.clientId("37dee8d8440c66d54cfa05d92c160882");
templateCreateEmbeddedDraftRequest.message("For your approval");
templateCreateEmbeddedDraftRequest.subject("Please sign this document");
templateCreateEmbeddedDraftRequest.testMode(true);
templateCreateEmbeddedDraftRequest.title("Test Template");
templateCreateEmbeddedDraftRequest.ccRoles(List.of (
"Manager"
));
templateCreateEmbeddedDraftRequest.files(List.of (
new File("./example_signature_request.pdf")
));
templateCreateEmbeddedDraftRequest.fieldOptions(fieldOptions);
templateCreateEmbeddedDraftRequest.mergeFields(mergeFields);
templateCreateEmbeddedDraftRequest.signerRoles(signerRoles);
try
{
var response = new TemplateApi(config).templateCreateEmbeddedDraft(
templateCreateEmbeddedDraftRequest
);
System.out.println(response);
} catch (ApiException e) {
System.err.println("Exception when calling TemplateApi#templateCreateEmbeddedDraft");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
```
```ruby Ruby
require "json"
require "dropbox-sign"
Dropbox::Sign.configure do |config|
config.username = "YOUR_API_KEY"
# config.access_token = "YOUR_ACCESS_TOKEN"
end
field_options = Dropbox::Sign::SubFieldOptions.new
field_options.date_format = "DD - MM - YYYY"
merge_fields_1 = Dropbox::Sign::SubMergeField.new
merge_fields_1.name = "Full Name"
merge_fields_1.type = "text"
merge_fields_2 = Dropbox::Sign::SubMergeField.new
merge_fields_2.name = "Is Registered?"
merge_fields_2.type = "checkbox"
merge_fields = [
merge_fields_1,
merge_fields_2,
]
signer_roles_1 = Dropbox::Sign::SubTemplateRole.new
signer_roles_1.name = "Client"
signer_roles_1.order = 0
signer_roles_2 = Dropbox::Sign::SubTemplateRole.new
signer_roles_2.name = "Witness"
signer_roles_2.order = 1
signer_roles = [
signer_roles_1,
signer_roles_2,
]
template_create_embedded_draft_request = Dropbox::Sign::TemplateCreateEmbeddedDraftRequest.new
template_create_embedded_draft_request.client_id = "37dee8d8440c66d54cfa05d92c160882"
template_create_embedded_draft_request.message = "For your approval"
template_create_embedded_draft_request.subject = "Please sign this document"
template_create_embedded_draft_request.test_mode = true
template_create_embedded_draft_request.title = "Test Template"
template_create_embedded_draft_request.cc_roles = [
"Manager",
]
template_create_embedded_draft_request.files = [
File.new("./example_signature_request.pdf", "r"),
]
template_create_embedded_draft_request.field_options = field_options
template_create_embedded_draft_request.merge_fields = merge_fields
template_create_embedded_draft_request.signer_roles = signer_roles
begin
response = Dropbox::Sign::TemplateApi.new.template_create_embedded_draft(
template_create_embedded_draft_request,
)
p response
rescue Dropbox::Sign::ApiError => e
puts "Exception when calling TemplateApi#template_create_embedded_draft: #{e}"
end
```
```python Python
import json
from datetime import date, datetime
from pprint import pprint
from dropbox_sign import ApiClient, ApiException, Configuration, api, models
configuration = Configuration(
username="YOUR_API_KEY",
# access_token="YOUR_ACCESS_TOKEN",
)
with ApiClient(configuration) as api_client:
field_options = models.SubFieldOptions(
date_format="DD - MM - YYYY",
)
merge_fields_1 = models.SubMergeField(
name="Full Name",
type="text",
)
merge_fields_2 = models.SubMergeField(
name="Is Registered?",
type="checkbox",
)
merge_fields = [
merge_fields_1,
merge_fields_2,
]
signer_roles_1 = models.SubTemplateRole(
name="Client",
order=0,
)
signer_roles_2 = models.SubTemplateRole(
name="Witness",
order=1,
)
signer_roles = [
signer_roles_1,
signer_roles_2,
]
template_create_embedded_draft_request = models.TemplateCreateEmbeddedDraftRequest(
client_id="37dee8d8440c66d54cfa05d92c160882",
message="For your approval",
subject="Please sign this document",
test_mode=True,
title="Test Template",
cc_roles=[
"Manager",
],
files=[
open("./example_signature_request.pdf", "rb").read(),
],
field_options=field_options,
merge_fields=merge_fields,
signer_roles=signer_roles,
)
try:
response = api.TemplateApi(api_client).template_create_embedded_draft(
template_create_embedded_draft_request=template_create_embedded_draft_request,
)
pprint(response)
except ApiException as e:
print("Exception when calling TemplateApi#template_create_embedded_draft: %s\n" % e)
```
*/}
Retrieve the `edit_url` from the API response, which will be a JSON object like the one below. Be sure to also store the `template_id` for future referencing of the completed template.
```json
{
"template": {
"template_id": "c26b8a16784f872a37ffa032f10d1c7c",
"edit_url": "https://app.hellosign.com/editor/embedded?token=1234567890abcdef",
"expires_at": 1234567890
}
}
```
Set up the frontend. If you are using a modern module bundler with [npm](https://npmjs.com/package/hellosign-embedded), simply install `hellosign-embedded`. Otherwise, our library can be [downloaded manually](https://github.com/hellosign/hellosign-embedded/releases), [compiled from source](https://github.com/hellosign/hellosign-embedded/wiki/Compile-From-Source), or [imported from our CDN](https://github.com/hellosign/hellosign-embedded/wiki/CDN-Links).
```bash
npm install hellosign-embedded
```
Create a new Embedded client. Import the `hellosign-embedded` module instantiate a new client.
```bash
import HelloSign from 'hellosign-embedded';
const client = new HelloSign({
clientId: 'Your API client ID'
});
```
Call `client.open()` with the `editUrl` you got from a previous step.
```bash
client.open(editUrl, {
skipDomainVerification: true
});
```
The embedded iFrame will be displayed and the user will be walked through the process of editing and finalizing the template for future use.
#### Pre-filled Data
By creating a template draft with merge fields, you are essentially telling your users, "The app can supply this information for you when you use the completed template to send a signature request."
This can be useful if, for example, your app stores contact information. If a user sends a signature request to one of the contacts in your system, you can pre-populate the signature request with contact details prior to sending. It's necessary to provide these details as 'merge fields' during the template creation because it indicates where the data should be placed within the document when sending the signature request.
As explained in the [creating a template](#creating-a-template) section, merge fields are specified during the template draft creation API request as a JSON array. Each merge field must have a unique name, and this is enforced by the API.
When the user is presented with the template draft editor, they are allowed to place these merge fields in the document. Merge fields appear to the user as standard Textbox and Checkbox fields. When one of these fields is placed on the document, the context menu will display the app as an option for the data source (in the "Who fills this out?" dropdown list), and the names of any pre-defined merge fields are listed in the dropdown underneath "What text goes here?".
Once the template is saved, the data to populate these merge fields can be specified in the API call to create a signature request. This not only saves the user time, but also ensures better data accuracy. To populate the merge fields, simply execute a [/signature\_request/send\_with\_template](/api/signature-request/send-with-template) and use the `custom_fields` parameter, or supply the same parameter when creating an embedded draft for previewing (see [previewing a signature request](#previewing-a-signature-request) below).
### Editing a Template
If a template was created using Embedded Templates, then you can also allow your users to edit it by calling [/embedded/edit\_url/\{template\_id}](/api/embedded/edit-url) and opening the `edit_url` with [hellosign-embedded](https://npmjs.com/package/hellosign-embedded). At the time of writing, you cannot use Embedded Templates to edit a template created on hellosign.com.
Make a GET or POST request to [/embedded/edit\_url/\{template\_id}](/api/embedded/edit-url).
A POST request is required if any changes are being made to merge fields or editor options. `test_mode` is optional with a POST request, however, it is required for users on Essentials and Standard plans.
```json title="Default Example"
{
"cc_roles": [
""
],
"merge_fields": []
}
```
{/*
```curl cURL
curl -X POST 'https://api.hellosign.com/v3/embedded/edit_url/{template_id}' \
-u 'YOUR_API_KEY:' \
-F 'cc_roles[0]=' \
-F 'merge_fields=[]'
```
```php PHP
setUsername("YOUR_API_KEY");
// $config->setAccessToken("YOUR_ACCESS_TOKEN");
$merge_fields = [
];
$embedded_edit_url_request = (new Dropbox\Sign\Model\EmbeddedEditUrlRequest())
->setCcRoles([
"",
])
->setMergeFields($merge_fields);
try {
$response = (new Dropbox\Sign\Api\EmbeddedApi(config: $config))->embeddedEditUrl(
template_id: "f57db65d3f933b5316d398057a36176831451a35",
embedded_edit_url_request: $embedded_edit_url_request,
);
print_r($response);
} catch (Dropbox\Sign\ApiException $e) {
echo "Exception when calling EmbeddedApi#embeddedEditUrl: {$e->getMessage()}";
}
```
```csharp C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using Dropbox.Sign.Api;
using Dropbox.Sign.Client;
using Dropbox.Sign.Model;
namespace Dropbox.SignSandbox;
public class EmbeddedEditUrlExample
{
public static void Run()
{
var config = new Configuration();
config.Username = "YOUR_API_KEY";
// config.AccessToken = "YOUR_ACCESS_TOKEN";
var mergeFields = new List();
var embeddedEditUrlRequest = new EmbeddedEditUrlRequest(
ccRoles: [
"",
],
mergeFields: mergeFields
);
try
{
var response = new EmbeddedApi(config).EmbeddedEditUrl(
templateId: "f57db65d3f933b5316d398057a36176831451a35",
embeddedEditUrlRequest: embeddedEditUrlRequest
);
Console.WriteLine(response);
}
catch (ApiException e)
{
Console.WriteLine("Exception when calling EmbeddedApi#EmbeddedEditUrl: " + e.Message);
Console.WriteLine("Status Code: " + e.ErrorCode);
Console.WriteLine(e.StackTrace);
}
}
}
```
```ts TypeScript
import * as fs from 'fs';
import api from "@dropbox/sign"
import models from "@dropbox/sign"
const apiCaller = new api.EmbeddedApi();
apiCaller.username = "YOUR_API_KEY";
// apiCaller.accessToken = "YOUR_ACCESS_TOKEN";
const mergeFields = [
];
const embeddedEditUrlRequest: models.EmbeddedEditUrlRequest = {
ccRoles: [
"",
],
mergeFields: mergeFields,
};
apiCaller.embeddedEditUrl(
"f57db65d3f933b5316d398057a36176831451a35", // templateId
embeddedEditUrlRequest,
).then(response => {
console.log(response.body);
}).catch(error => {
console.log("Exception when calling EmbeddedApi#embeddedEditUrl:");
console.log(error.body);
});
```
```java Java
package com.dropbox.sign_sandbox;
import com.dropbox.sign.ApiException;
import com.dropbox.sign.Configuration;
import com.dropbox.sign.api.*;
import com.dropbox.sign.auth.*;
import com.dropbox.sign.JSON;
import com.dropbox.sign.model.*;
import java.io.File;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class EmbeddedEditUrlExample
{
public static void main(String[] args)
{
var config = Configuration.getDefaultApiClient();
((HttpBasicAuth) config.getAuthentication("api_key")).setUsername("YOUR_API_KEY");
// ((HttpBearerAuth) config.getAuthentication("oauth2")).setBearerToken("YOUR_ACCESS_TOKEN");
var mergeFields = new ArrayList(List.of ());
var embeddedEditUrlRequest = new EmbeddedEditUrlRequest();
embeddedEditUrlRequest.ccRoles(List.of (
""
));
embeddedEditUrlRequest.mergeFields(mergeFields);
try
{
var response = new EmbeddedApi(config).embeddedEditUrl(
"f57db65d3f933b5316d398057a36176831451a35", // templateId
embeddedEditUrlRequest
);
System.out.println(response);
} catch (ApiException e) {
System.err.println("Exception when calling EmbeddedApi#embeddedEditUrl");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
```
```ruby Ruby
require "json"
require "dropbox-sign"
Dropbox::Sign.configure do |config|
config.username = "YOUR_API_KEY"
# config.access_token = "YOUR_ACCESS_TOKEN"
end
merge_fields = [
]
embedded_edit_url_request = Dropbox::Sign::EmbeddedEditUrlRequest.new
embedded_edit_url_request.cc_roles = [
"",
]
embedded_edit_url_request.merge_fields = merge_fields
begin
response = Dropbox::Sign::EmbeddedApi.new.embedded_edit_url(
"f57db65d3f933b5316d398057a36176831451a35", # template_id
embedded_edit_url_request,
)
p response
rescue Dropbox::Sign::ApiError => e
puts "Exception when calling EmbeddedApi#embedded_edit_url: #{e}"
end
```
```python Python
import json
from datetime import date, datetime
from pprint import pprint
from dropbox_sign import ApiClient, ApiException, Configuration, api, models
configuration = Configuration(
username="YOUR_API_KEY",
# access_token="YOUR_ACCESS_TOKEN",
)
with ApiClient(configuration) as api_client:
merge_fields = [
]
embedded_edit_url_request = models.EmbeddedEditUrlRequest(
cc_roles=[
"",
],
merge_fields=merge_fields,
)
try:
response = api.EmbeddedApi(api_client).embedded_edit_url(
template_id="f57db65d3f933b5316d398057a36176831451a35",
embedded_edit_url_request=embedded_edit_url_request,
)
pprint(response)
except ApiException as e:
print("Exception when calling EmbeddedApi#embedded_edit_url: %s\n" % e)
```
*/}
Retrieve the `edit_url` from the API response, which will be a JSON object like the one below. This URL will be used in the same manner as the `edit_url` retrieved for the template draft creation.
```json
{
"embedded": {
"edit_url": "https://app.hellosign.com/editor/embedded?token=1234567890abcdef",
"expires_at": 1234567890
}
}
```
Set up the frontend. Check out the [Client Side](#client-side) section below for a tutorial on how to set up the Embedded library.
Call `client.open()` with the `editUrl` you got from a previous step.
```json
client.open(editUrl, {
skipDomainVerification: true
});
```
The embedded iFrame will be displayed and the user will be walked through the process of editing and finalizing the template.
## Previewing a Signature Request
When your site user needs to send a signature request based on a template, you will need to create an embedded signature request draft. This draft can be opened in an embedded iFrame to allow the user to preview the request prior to sending. Creating the signature request draft for previewing is also a perfect opportunity to populate any pre-defined merge fields that might have been added by the user during the template creation process.
Create the embedded template draft by making a POST request to [/unclaimed\_draft/create\_embedded\_with\_template](/api/unclaimed-draft/create-embedded-with-template) with the following parameters:
```json title="Default Example"
{
"client_id": "b6b8e7deaf8f0b95c029dca049356d4a2cf9710a",
"template_ids": [
"61a832ff0d8423f91d503e76bfbcc750f7417c78"
],
"requester_email_address": "jack@dropboxsign.com",
"signers": [
{
"role": "Client",
"name": "George",
"email_address": "george@example.com"
}
],
"ccs": [
{
"role": "Accounting",
"email_address": "accounting@dropboxsign.com"
}
],
"test_mode": false
}
```
{/*
```curl cURL
curl -X POST 'https://api.hellosign.com/v3/unclaimed_draft/create_embedded_with_template' \
-u 'YOUR_API_KEY:' \
-F 'client_id=YOUR_CLIENT_ID' \
-F 'template_ids[]=61a832ff0d8423f91d503e76bfbcc750f7417c78' \
-F 'requester_email_address=jack@dropboxsign.com' \
-F 'signers[0][role]=Client' \
-F 'signers[0][name]=George' \
-F 'signers[0][email_address]=george@example.com' \
-F 'ccs[0][role]=Accounting' \
-F 'ccs[0][email_address]=accounting@dropboxsign.com' \
-F 'test_mode=1'
```
```php PHP
setUsername("YOUR_API_KEY");
// $config->setAccessToken("YOUR_ACCESS_TOKEN");
$ccs_1 = (new Dropbox\Sign\Model\SubCC())
->setRole("Accounting")
->setEmailAddress("accounting@dropboxsign.com");
$ccs = [
$ccs_1,
];
$signers_1 = (new Dropbox\Sign\Model\SubUnclaimedDraftTemplateSigner())
->setRole("Client")
->setName("George")
->setEmailAddress("george@example.com");
$signers = [
$signers_1,
];
$unclaimed_draft_create_embedded_with_template_request = (new Dropbox\Sign\Model\UnclaimedDraftCreateEmbeddedWithTemplateRequest())
->setClientId("b6b8e7deaf8f0b95c029dca049356d4a2cf9710a")
->setRequesterEmailAddress("jack@dropboxsign.com")
->setTemplateIds([
"61a832ff0d8423f91d503e76bfbcc750f7417c78",
])
->setTestMode(false)
->setCcs($ccs)
->setSigners($signers);
try {
$response = (new Dropbox\Sign\Api\UnclaimedDraftApi(config: $config))->unclaimedDraftCreateEmbeddedWithTemplate(
unclaimed_draft_create_embedded_with_template_request: $unclaimed_draft_create_embedded_with_template_request,
);
print_r($response);
} catch (Dropbox\Sign\ApiException $e) {
echo "Exception when calling UnclaimedDraftApi#unclaimedDraftCreateEmbeddedWithTemplate: {$e->getMessage()}";
}
```
```csharp C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using Dropbox.Sign.Api;
using Dropbox.Sign.Client;
using Dropbox.Sign.Model;
namespace Dropbox.SignSandbox;
public class UnclaimedDraftCreateEmbeddedWithTemplateExample
{
public static void Run()
{
var config = new Configuration();
config.Username = "YOUR_API_KEY";
// config.AccessToken = "YOUR_ACCESS_TOKEN";
var ccs1 = new SubCC(
role: "Accounting",
emailAddress: "accounting@dropboxsign.com"
);
var ccs = new List
{
ccs1,
};
var signers1 = new SubUnclaimedDraftTemplateSigner(
role: "Client",
name: "George",
emailAddress: "george@example.com"
);
var signers = new List
{
signers1,
};
var unclaimedDraftCreateEmbeddedWithTemplateRequest = new UnclaimedDraftCreateEmbeddedWithTemplateRequest(
clientId: "b6b8e7deaf8f0b95c029dca049356d4a2cf9710a",
requesterEmailAddress: "jack@dropboxsign.com",
templateIds: [
"61a832ff0d8423f91d503e76bfbcc750f7417c78",
],
testMode: false,
ccs: ccs,
signers: signers
);
try
{
var response = new UnclaimedDraftApi(config).UnclaimedDraftCreateEmbeddedWithTemplate(
unclaimedDraftCreateEmbeddedWithTemplateRequest: unclaimedDraftCreateEmbeddedWithTemplateRequest
);
Console.WriteLine(response);
}
catch (ApiException e)
{
Console.WriteLine("Exception when calling UnclaimedDraftApi#UnclaimedDraftCreateEmbeddedWithTemplate: " + e.Message);
Console.WriteLine("Status Code: " + e.ErrorCode);
Console.WriteLine(e.StackTrace);
}
}
}
```
```ts TypeScript
import * as fs from 'fs';
import api from "@dropbox/sign"
import models from "@dropbox/sign"
const apiCaller = new api.UnclaimedDraftApi();
apiCaller.username = "YOUR_API_KEY";
// apiCaller.accessToken = "YOUR_ACCESS_TOKEN";
const ccs1: models.SubCC = {
role: "Accounting",
emailAddress: "accounting@dropboxsign.com",
};
const ccs = [
ccs1,
];
const signers1: models.SubUnclaimedDraftTemplateSigner = {
role: "Client",
name: "George",
emailAddress: "george@example.com",
};
const signers = [
signers1,
];
const unclaimedDraftCreateEmbeddedWithTemplateRequest: models.UnclaimedDraftCreateEmbeddedWithTemplateRequest = {
clientId: "b6b8e7deaf8f0b95c029dca049356d4a2cf9710a",
requesterEmailAddress: "jack@dropboxsign.com",
templateIds: [
"61a832ff0d8423f91d503e76bfbcc750f7417c78",
],
testMode: false,
ccs: ccs,
signers: signers,
};
apiCaller.unclaimedDraftCreateEmbeddedWithTemplate(
unclaimedDraftCreateEmbeddedWithTemplateRequest,
).then(response => {
console.log(response.body);
}).catch(error => {
console.log("Exception when calling UnclaimedDraftApi#unclaimedDraftCreateEmbeddedWithTemplate:");
console.log(error.body);
});
```
```java Java
package com.dropbox.sign_sandbox;
import com.dropbox.sign.ApiException;
import com.dropbox.sign.Configuration;
import com.dropbox.sign.api.*;
import com.dropbox.sign.auth.*;
import com.dropbox.sign.JSON;
import com.dropbox.sign.model.*;
import java.io.File;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class UnclaimedDraftCreateEmbeddedWithTemplateExample
{
public static void main(String[] args)
{
var config = Configuration.getDefaultApiClient();
((HttpBasicAuth) config.getAuthentication("api_key")).setUsername("YOUR_API_KEY");
// ((HttpBearerAuth) config.getAuthentication("oauth2")).setBearerToken("YOUR_ACCESS_TOKEN");
var ccs1 = new SubCC();
ccs1.role("Accounting");
ccs1.emailAddress("accounting@dropboxsign.com");
var ccs = new ArrayList(List.of (
ccs1
));
var signers1 = new SubUnclaimedDraftTemplateSigner();
signers1.role("Client");
signers1.name("George");
signers1.emailAddress("george@example.com");
var signers = new ArrayList(List.of (
signers1
));
var unclaimedDraftCreateEmbeddedWithTemplateRequest = new UnclaimedDraftCreateEmbeddedWithTemplateRequest();
unclaimedDraftCreateEmbeddedWithTemplateRequest.clientId("b6b8e7deaf8f0b95c029dca049356d4a2cf9710a");
unclaimedDraftCreateEmbeddedWithTemplateRequest.requesterEmailAddress("jack@dropboxsign.com");
unclaimedDraftCreateEmbeddedWithTemplateRequest.templateIds(List.of (
"61a832ff0d8423f91d503e76bfbcc750f7417c78"
));
unclaimedDraftCreateEmbeddedWithTemplateRequest.testMode(false);
unclaimedDraftCreateEmbeddedWithTemplateRequest.ccs(ccs);
unclaimedDraftCreateEmbeddedWithTemplateRequest.signers(signers);
try
{
var response = new UnclaimedDraftApi(config).unclaimedDraftCreateEmbeddedWithTemplate(
unclaimedDraftCreateEmbeddedWithTemplateRequest
);
System.out.println(response);
} catch (ApiException e) {
System.err.println("Exception when calling UnclaimedDraftApi#unclaimedDraftCreateEmbeddedWithTemplate");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
```
```ruby Ruby
require "json"
require "dropbox-sign"
Dropbox::Sign.configure do |config|
config.username = "YOUR_API_KEY"
# config.access_token = "YOUR_ACCESS_TOKEN"
end
ccs_1 = Dropbox::Sign::SubCC.new
ccs_1.role = "Accounting"
ccs_1.email_address = "accounting@dropboxsign.com"
ccs = [
ccs_1,
]
signers_1 = Dropbox::Sign::SubUnclaimedDraftTemplateSigner.new
signers_1.role = "Client"
signers_1.name = "George"
signers_1.email_address = "george@example.com"
signers = [
signers_1,
]
unclaimed_draft_create_embedded_with_template_request = Dropbox::Sign::UnclaimedDraftCreateEmbeddedWithTemplateRequest.new
unclaimed_draft_create_embedded_with_template_request.client_id = "b6b8e7deaf8f0b95c029dca049356d4a2cf9710a"
unclaimed_draft_create_embedded_with_template_request.requester_email_address = "jack@dropboxsign.com"
unclaimed_draft_create_embedded_with_template_request.template_ids = [
"61a832ff0d8423f91d503e76bfbcc750f7417c78",
]
unclaimed_draft_create_embedded_with_template_request.test_mode = false
unclaimed_draft_create_embedded_with_template_request.ccs = ccs
unclaimed_draft_create_embedded_with_template_request.signers = signers
begin
response = Dropbox::Sign::UnclaimedDraftApi.new.unclaimed_draft_create_embedded_with_template(
unclaimed_draft_create_embedded_with_template_request,
)
p response
rescue Dropbox::Sign::ApiError => e
puts "Exception when calling UnclaimedDraftApi#unclaimed_draft_create_embedded_with_template: #{e}"
end
```
```python Python
import json
from datetime import date, datetime
from pprint import pprint
from dropbox_sign import ApiClient, ApiException, Configuration, api, models
configuration = Configuration(
username="YOUR_API_KEY",
# access_token="YOUR_ACCESS_TOKEN",
)
with ApiClient(configuration) as api_client:
ccs_1 = models.SubCC(
role="Accounting",
email_address="accounting@dropboxsign.com",
)
ccs = [
ccs_1,
]
signers_1 = models.SubUnclaimedDraftTemplateSigner(
role="Client",
name="George",
email_address="george@example.com",
)
signers = [
signers_1,
]
unclaimed_draft_create_embedded_with_template_request = models.UnclaimedDraftCreateEmbeddedWithTemplateRequest(
client_id="b6b8e7deaf8f0b95c029dca049356d4a2cf9710a",
requester_email_address="jack@dropboxsign.com",
template_ids=[
"61a832ff0d8423f91d503e76bfbcc750f7417c78",
],
test_mode=False,
ccs=ccs,
signers=signers,
)
try:
response = api.UnclaimedDraftApi(api_client).unclaimed_draft_create_embedded_with_template(
unclaimed_draft_create_embedded_with_template_request=unclaimed_draft_create_embedded_with_template_request,
)
pprint(response)
except ApiException as e:
print("Exception when calling UnclaimedDraftApi#unclaimed_draft_create_embedded_with_template: %s\n" % e)
```
*/}
Retrieve the `claim_url` from the API response, which will be a JSON object like the one below. This URL will be used in the same manner as the `edit_url` for template creation and editing to display the preview to the user.
```json
{
"unclaimed_draft": {
"claim_url": "https://app.hellosign.com/editor/embedded?token=1234567890abcdef",
"expires_at": 1234567890
}
}
```
Set up the frontend. Check out the [Client Side](#client-side) section below for a tutorial on how to set up the Embedded library.
Call `client.open()` with the `editUrl` you got from a previous step.
```json
client.open(editUrl, {
skipDomainVerification: true
});
```
The embedded iFrame will be displayed and the user will be given an opportunity to preview and make edits to the signature request prior to sending. Any `custom_fields` parameters supplied to the draft creation API request will be added to the document as well and these fields can also be edited and moved by the user. The user can then send the signature request by clicking "Continue" (or "Send" if the subject and message for the request have already been set).
## Client Side
We provide a client-side library that handles the authorization and display of the embedded request using an iFrame. You can use this feature by adding a few lines of JavaScript code.
If you are using a modern module bundler with [npm](https://npmjs.com/package/hellosign-embedded), simply install `hellosign-embedded`.
```bash
npm install hellosign-embedded
```
If you are not using a modern module bunder like npm, our library can be [downloaded manually](https://github.com/hellosign/hellosign-embedded/releases), [compiled from source](https://github.com/hellosign/hellosign-embedded/wiki/Compile-From-Source), or [imported from our CDN](https://github.com/hellosign/hellosign-embedded/wiki/CDN-Links).
In your app, import the `hellosign-embedded` module, instantiate a new client, then invoke `open()` with your `claimUrl` and API client ID. Note that we're using `skipDomainVerification` when calling this method. You can learn more about that in the [Domain Restriction](#domain-restriction) section below.
```bash
import HelloSign from 'hellosign-embedded';
const client = new HelloSign();
client.open(claimUrl, {
clientId: 'Your API client ID',
skipDomainVerification: true
});
```
**Note:** It's recommended that you add the following to your document's `` to avoid unexpected behavior on small screens. ``
There are a number of options you can define as part of the second argument when calling `open()`:
|
Name
|
Type
|
Description
|
requestingEmail
|
string
|
The email of the account issuing the signature request.
**Note:** This option is only necessary for **'Me and Others'** type signature requests.
**Example:**
{'{'} "requestingEmail": "[alice@example.com](mailto:alice@example.com)" {'}'}
|
locale
|
string
|
The locale code that will be used to determine which language the embedded request will be displayed in. For a list of Dropbox Sign's supported languages, visit our Languages page. If no locale is specified Dropbox Sign will attempt to determine the user's preferred language by their browser settings or fall back to English.
**Note:** Czech (`CS_CZ`) is only supported by Embedded Signing.
**Example:**
{'{'} "locale": HelloSign.locales.ZH_CN {'}'}
|
redirectTo
|
string
|
Where the user will be redirected after sending the signature request.
**Example:**
{'{'} "redirectTo": "[http://example.com](http://example.com)" {'}'}
|
allowCancel
|
boolean
|
Whether the user should be able to close the iFrame without finishing the request. **Default:** `true`.
**Example:**
{'{'} "allowCancel": false {'}'}
|
debug
|
boolean
|
Allows debug output to print to the console. **Default:** `false`.
For even more detailed debug output, run `localStorage.debug = 'hellosign-embedded:*';` in your developer console and refresh the page.
**Example:**
{'{'} "debug": true {'}'}
|
skipDomainVerification
|
boolean
|
Whether or not to skip the domain verification step. **Default:** `false`.
**Note:** This will only be honored if the signature request was created with `test_mode=1`.
**Example:**
{'{'} "skipDomainVerification": true {'}'}
|
timeout
|
number
|
How long (in milliseconds) to wait for the Dropbox Sign app to initialize before aborting. **Default:** `30000` (30 seconds).
**Example:**
{'{'} "timeout": 10000 {'}'}
|
container
|
HTMLElement
|
By default a modal will be opened, but by specifying `container` you can choose a DOM element on the page in which the iFrame will be embedded.
**Example:**
{'{'} "container": document.getElementById('sign-here') {'}'}
|
## Additional Notes
### App Approval
In order to ensure that integrations adhere to eSignature regulations and best practices, an app approval is needed prior to moving into production for all customers implementing embedded signing, embedded requesting, embedded templates, and OAuth workflows.
You will still be able to use your app in test mode until it gets approved. Only live/production activity requires approval.
Please refer to the [App Approval Section](/docs/guides/app-approval/overview) for more detailed information about getting your app approved.
### Domain Restriction
When the iFrame is loaded, it will verify the domain of the parent window and ensure it matches the domain name of the API app specified by the client ID. If the domain does not match, the page won't be loaded.
You can disable domain restriction for easier development:
```bash
client.open(signUrl, {
// ...
skipDomainVerification: true
});
```
This will allow you to use development domains, like `localhost`. See the documentation for `open()` method in the section above.
### HTTPS Required
The host page must be served over HTTPS. The iFrame is also loaded over HTTPS, and due to browser security restrictions it will not be able to communicate with the parent window if it is not HTTPS. This communication is required to enable features such as iFrame callbacks and closing the iFrame.
To make development easier, the page will still load if the parent window is served over HTTP, however an alert will be displayed to notify you of this requirement. Switch to HTTPS to prevent this alert from being displayed.
### Redirection
If a redirect url is specified, the iFrame will redirect users to it after they send the document(s). Data from the `sign` event will be appended to the url query string.
### Signature Links
Signature URLs are only valid for 60 minutes after [/embedded/sign\_url](/api/embedded/sign-url) has been called and expire as soon as they're accessed.
It is best practice to wait until your signer hits the page before generating the `sign_url` so the link doesn't expire before the signer is ready. However, since the `signature_id` itself does not expire, a fresh `sign_url` can always be generated.
### Text Tags
The embedded functionality can be used in conjunction with Dropbox Sign [Text Tags](/docs/walkthroughs/text-tags).
### Client Side Events
There are a number of events that the client may emit. To listen to these events, pass the event name and a callback function to `on()`. An string enumeration of available events can also be found under `HelloSign.events`.
```bash
client.on('sign', (data) => {
console.log('The document has been signed!');
console.log('Signature ID: ' + data.signatureId);
});
```
Here are a list of possible events:
| Event | Description | Data |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createTemplate` | Emitted when the user creates the signature request template. | {'{'}
templateId,
templateInfo {'{'}
title,
message,
signerRoles,
ccRoles
{'}'}
{'}'}
|
| `open` | Emitted when the embedded window has opened. | {'{'}
url,
iFrameUrl
{'}'}
|
| `cancel` | Emitted when the template was canceled by the user by either pressing the close button or selecting "close" from the dropdown list. | |
| `finish` | Emitted when the user has finished the embedded template flow without cancelling. | |
| `message` | Emitted when embedded has received a [cross-origin window message](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent) from the app. | {'{'}
type,
payload
{'}'}
|
| `close` | Emitted when the window has closed. | |
| `error` | Emitted when the app encounters an error. | {'{'}
signatureId,
code
{'}'}
|