Working with Box Sign Templates

Rui Barbosa
Box Developer Blog
Published in
6 min readDec 5, 2023

--

In this article we are going to explore how to electronically sign a document from a template using the Box Platform.

Box Sign templates are a form of structured documents where the signers and their roles are known, and the signature and other properties placement are already present in the template.

In a previous article we explored not only the many features of the signature request common to the use of templates, but also how to use the Box Sign for unstructured documents. You can read it here:

In later articles we’ll focus on structured documents and complex use cases.

You can follow along this workshop with complete code samples via this GitHub Repo. We are using the Box Platform Next Gen Python SDK.

Box Sign templates

A Box Sign template is a special type of document that not only contains the text, but also the signature requirements and placement.

Essentially a Box Sign template is a document that is prepared for signing in advanced, and as such can be sent directly to the signer.

Required fields include the signature pad, the full name, the date, and many more options.

These fields have an owner, meaning they are populated by the signer and can not be shared between them. They can be mandatory or optional , and be pre-populated by your application. However even if pre-populated, they can always be changed by the signer.

Lets start by creating a template.

Creating a template

From the Box app navigate to the sign menu on the left, then select templates.

Navigating to templates unde Box Sign

Then, click on the New Template button, chose or upload document, from box.

In this exercise we have a document prepared, navigate to workshops/sign/docs , select Simple-PDF.pdf and click Next. Alternatively select or upload a test document.

Selecting a document when creating a template

Drag and drop a date, a name and a signature pad to the template, like so:

Adding the signature, name, and date to the template

Save the template.

Identify the template

In order to work with templates in the Box Sign API we are going to need the template_id . Consider this method to list all the templates available to the user:

def sign_templates_list(client: Client):
"""List all sign templates"""
sign_templates = client.sign_templates.get_sign_templates()
print(f"\nSign templates: {len(sign_templates.entries)}")
for sign_template in sign_templates.entries:
print(f" {sign_template.id} - {sign_template.name}")

And a simple main method:

def main():
"""Simple script to demonstrate how to use the Box SDK"""
conf = ConfigOAuth()
client = get_client_oauth(conf)

user = client.users.get_user_me()
print(f"\nHello, I'm {user.name} ({user.login}) [{user.id}]")

sign_templates_list(client)


if __name__ == "__main__":
main()

Returns something similar to:

Hello, I'm Rui Barbosa [18622116055]

Sign templates: 1
94e3815b-f7f5-4c2c-8a26-e9ba5c486031 - Simple-PDF.pdf

Creating a signature request from a template

The big advantage of using templates is that we do not need to worry about document preparation. We only need a signer email, the template, and the folder to put the signed document.

Consider this example:

def create_sign_request(client: Client, template_id: str, signer_email: str):
"""Create sign request from template"""
parent_folder = FolderMini(
id=SIGN_DOCS_FOLDER, type=FolderBaseTypeField.FOLDER
)

signer = SignRequestCreateSigner(
email=signer_email,
)

sign_request = client.sign_requests.create_sign_request(
signers=[signer],
parent_folder=parent_folder,
template_id=template_id,
)

return sign_request

And use it on our main:

def main():
...

# Create sign request from template
sign_request = create_sign_request(client, TEMPLATE_SIMPLE, SIGNER_A)
check_sign_request(sign_request)

Resulting in:

Simple sign request: b25674a2-540b-4201-ae18-a78f05ef1a9a
Status: created
Signers: 2
final_copy_reader: ...@gmail.com
signer: YOUR_EMAIL+a@gmail.com
Prepare url: None

Go to the inbox of the sender and complete the signature request.

Notice that there was no document preparation required, since the template already had the signature requirements, but the date was automatically populated with the current date.

But what if we want to pre-populate the name?

Pre-populate the signature attributes

From a usability perspective, it is a good idea to pre-populate the inputs you require from your users, to reduce some of the friction.

Please note that some inputs maybe intentionally left unpopulated. For example, suppose your legal department specifies that the “Yes, I agree” must be explicitly set by the signer .

Using the Box app sign template editor, we can assign external_id's to each of the inputs, and have our app populate them from any data source.

Let’s implement this for the name.

Go back to the template design and add an id to the name field, like so:

Assigning a tag id to a signature property input

Save the template.

Let’s create a new method to pre-populate the name:

def create_sign_request_name_default(
client: Client, template_id: str, signer_name, signer_email: str
):
"""Create sign request from template"""
parent_folder = FolderMini(
id=SIGN_DOCS_FOLDER, type=FolderBaseTypeField.FOLDER
)

signer = SignRequestCreateSigner(
email=signer_email,
)

# tags
tag_full_name = SignRequestPrefillTag(
document_tag_id="signer_full_name",
text_value=signer_name,
)

sign_request = client.sign_requests.create_sign_request(
signers=[signer],
parent_folder=parent_folder,
prefill_tags=[tag_full_name],
template_id=template_id,
)

return sign_request

And use it on our main:

def main():
...

# Create sign request from template with name
sign_request_name = create_sign_request_name_default(
client, TEMPLATE_SIMPLE, "Signer A", SIGNER_A
)
check_sign_request(sign_request_name)

Resulting in:

Simple sign request: adab1740-eeba-4392-a3f5-defddc79c946
Status: created
Signers: 2
final_copy_reader: ...@gmail.com
signer: ...+a@gmail.com
Prepare url: None

Open the signer inbox and complete the sign request.

Signing the document

Notice that the name is now pre-populated. However the signer can still change it.

Get more information about a template

We’ve seen that we can list the templates available to a user.

But we can also get more information about a specific template.

Let’s create a method that returns basic information of a template, but details all the signature requirements:

def sign_template_print_info(client: Client, template_id: str):
sign_template = client.sign_templates.get_sign_template_by_id(template_id)
print(f"\nSign template: {sign_template.id} - {sign_template.name}")
print(f" Signers: {len(sign_template.signers)}")
for signer in sign_template.signers:
print(f" {signer.role.value}")
if len(signer.inputs) > 0:
print(" Tag ID\t Type\t Required")
for input in signer.inputs:
print(
f" {input.document_tag_id} {input.type.value} {input.is_required}"
)

And use it on our main:

def main():
...

# Print sign template details
sign_template_print_info(client, TEMPLATE_SIMPLE)

Resulting in:

Sign template: 94e3815b-f7f5-4c2c-8a26-e9ba5c486031 - Simple-PDF.pdf
Signers: 2
final_copy_reader
signer
Tag ID Type Required
None date True
signer_full_name text True
None signature True

Notice that the signer_full_name is the tag id we used to pre-populate the name.

Final thoughts

Templates are a form of signing structured documents where the signature requirements are already defined, and placed on the document.

This not only keeps your contract management team happy, but it also creates a consistent and low level of effort process for your users.

Finally if your document signature requirements have a lot of options, you can pre-populate these from another data source and save the user some time.

Just remember that the user who owns these properties can always change them.

There is no API entry point to create a template, so you will have to create and manage them manually from the Box app.

However there is a workaround for that, stay tuned.

Documents and references

Thoughts? Comments? Feedback?

Drop us a line on our community forum.

--

--