How to Upload a PDF Template
This guide walks you through the complete process of creating a template and uploading a PDF file to use as your document template in Legalesign.
What You'll Learn
By the end of this guide, you'll know how to:
- Create a new template in your Legalesign group
- Get the template ID needed for upload
- Upload your PDF file to the template
- Verify the upload was successful
Prerequisites
Before you start, make sure you have:
- A Legalesign account with API access
- Your authentication credentials (see our authentication guide)
- A PDF file ready to upload (maximum 50MB)
- Your group ID (the workspace where you want to create the template)
The Complete Process
Step 1: Create a Template
First, you need to create an empty template in Legalesign. This gives you a template ID that you'll use for the PDF upload. To do this you'll need to run a GraphQL mutation, if you haven't done this before see the Introduction to GraphQL.
What is a Template?
A template is a reusable document structure in Legalesign. Once you upload a PDF to a template, you can:
- Add signature fields and form fields
- Send it to multiple recipients
- Reuse it for different signers
GraphQL Mutation
mutation CreateTemplate($input: templateCreateInput!) {
createTemplate(input: $input) {
template {
id
title
groupId
created
}
}
}
Input Variables
{
"input": {
"groupId": "grpYourGroupAPIId",
"title": "Employment Contract Template"
}
}
Parameters Explained
- groupId: The base 64 ID of your group/workspace (you can grab this from the URL in Console [https://console.legalesign.com/])
- title: A descriptive name for your template (you can change this later)
Step 2: Extract the Template ID
The mutation returns a template object. You need to save the id field - this is what you'll use to upload your PDF.
Example response:
{
"data": {
"createTemplate": {
"template": {
"title": "Employment Contract Template",
"groupId": "grpYourGroupId"
}
}
}
}
The template ID is a Base64-encoded string. Save this ID - you'll need it for the next step.
Step 3: Request Upload Permission
Now that you have a template ID, request a pre-signed URL to upload your PDF.
query GetUploadUrl {
upload(
id: "dHBsYjQ5YTg5NWQtYWRhMy0xMWYwLWIxZGMtMDY5NzZlZmU0MzIx",
uploadType: TEMPLATE,
extension: "pdf"
) {
url
}
}
Parameters
- id: The template ID from Step 2
- uploadType: Must be
TEMPLATEfor PDF templates - extension: Must be
"pdf"for template files
The response will contain a pre-signed URL:
{
"data": {
"upload": {
"url": "https://s3.amazonaws.com/bucket/path?signature=..."
}
}
}
This URL is only valid for 15 minutes. If it expires, simply request a new one.
Step 4: Upload Your PDF
Use the pre-signed URL to upload your PDF file directly to S3. This will be different
depending on your development stack. In our javascript example we've used fetch but
you can use other libraries including aws-amplify.
Complete Working Examples
- JavaScript
- Python
- C#
import fs from 'fs';
import { AuthenticationDetails, CognitoUser, CognitoUserPool } from 'amazon-cognito-identity-js';
// Get authentication token from AWS Cognito
const getToken = (username, password, pool = 'eu-west-2_NUPAjABy7', appClientId = '38kn0eb9mf2409t6mci98eqdvt') => {
const authenticationDetails = new AuthenticationDetails({
Username: username,
Password: password
});
const userData = {
Username: username,
Pool: new CognitoUserPool({
UserPoolId: pool,
ClientId: appClientId
})
};
const cognitoUser = new CognitoUser(userData);
return new Promise((resolve, reject) =>
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: result => resolve(result.getAccessToken().getJwtToken()),
onFailure: err => reject(err)
})
);
};
const uploadPdfTemplate = async (username, password, groupId, title, pdfFilePath) => {
const graphqlEndpoint = 'https://graphql.uk.legalesign.com/graphql';
// Get authentication token
console.log('Authenticating...');
const authToken = await getToken(username, password);
// Step 1: Create the template
console.log('Creating template...');
const createResponse = await fetch(graphqlEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`
},
body: JSON.stringify({
query: `
mutation CreateTemplate($input: templateCreateInput!) {
createTemplate(input: $input) {
template {
id
title
}
}
}
`,
variables: {
input: {
groupId: groupId,
title: title
}
}
})
});
const createResult = await createResponse.json();
const templateId = createResult.data.createTemplate.template.id;
console.log('Template created with ID:', templateId);
// Step 2: Get upload URL
console.log('Requesting upload URL...');
const uploadUrlResponse = await fetch(graphqlEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`
},
body: JSON.stringify({
query: `
query GetUploadUrl($id: ID!) {
upload(
id: $id,
uploadType: TEMPLATE,
extension: "pdf"
) {
url
}
}
`,
variables: {
id: templateId
}
})
});
const uploadUrlResult = await uploadUrlResponse.json();
const uploadUrl = uploadUrlResult.data.upload.url;
console.log('Upload URL received');
// Step 3: Upload the PDF
console.log('Uploading PDF...');
const fileData = fs.readFileSync(pdfFilePath);
const uploadResponse = await fetch(uploadUrl, {
method: 'PUT',
body: fileData,
headers: {
'Content-Type': 'application/pdf'
}
});
if (!uploadResponse.ok) {
throw new Error(`Upload failed: ${uploadResponse.statusText}`);
}
console.log('PDF uploaded successfully!');
return {
success: true,
templateId: templateId,
title: title
};
};
// Usage example
uploadPdfTemplate(
'your-email@example.com',
'your-password',
'grpYourGroupId',
'Employment Contract',
'./contract.pdf'
).then(result => {
console.log('Complete!', result);
}).catch(error => {
console.error('Error:', error);
});
Install dependencies:
npm install amazon-cognito-identity-js
import requests
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport
def upload_pdf_template(graphql_endpoint, auth_token, group_id, title, pdf_file_path):
# Setup GraphQL client
transport = RequestsHTTPTransport(
url=graphql_endpoint,
headers={'Authorization': auth_token}
)
client = Client(transport=transport, fetch_schema_from_transport=True)
# Step 1: Create the template
print('Creating template...')
create_mutation = gql('''
mutation CreateTemplate($input: templateCreateInput!) {
createTemplate(input: $input) {
template {
id
title
}
}
}
''')
create_result = client.execute(
create_mutation,
variable_values={
'input': {
'groupId': group_id,
'title': title
}
}
)
template_id = create_result['createTemplate']['template']['id']
print(f'Template created with ID: {template_id}')
# Step 2: Get upload URL
print('Requesting upload URL...')
upload_query = gql(f'''
query {{
upload(
id: "{template_id}",
uploadType: TEMPLATE,
extension: "pdf"
) {{
url
}}
}}
''')
upload_result = client.execute(upload_query)
upload_url = upload_result['upload']['url']
print('Upload URL received')
# Step 3: Upload the PDF
print('Uploading PDF...')
with open(pdf_file_path, 'rb') as f:
file_data = f.read()
response = requests.put(
upload_url,
data=file_data,
headers={'Content-Type': 'application/pdf'}
)
if response.status_code != 200:
raise Exception(f'Upload failed: {response.status_code}')
print('PDF uploaded successfully!')
return {
'success': True,
'templateId': template_id,
'title': title
}
# Usage example
if __name__ == '__main__':
result = upload_pdf_template(
'https://graphql.uk.legalesign.com/graphql',
'Bearer YOUR_TOKEN',
'grpYourGroupId',
'Employment Contract',
'./contract.pdf'
)
print('Complete!', result)
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using GraphQL;
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.Newtonsoft;
using Newtonsoft.Json.Linq;
public class PdfTemplateUploader
{
private readonly GraphQLHttpClient graphQLClient;
public PdfTemplateUploader(string graphqlEndpoint, string authToken)
{
graphQLClient = new GraphQLHttpClient(graphqlEndpoint, new NewtonsoftJsonSerializer());
graphQLClient.HttpClient.DefaultRequestHeaders.Add("Authorization", authToken);
}
public async Task<UploadResult> UploadPdfTemplate(
string groupId,
string title,
string pdfFilePath)
{
// Step 1: Create the template
Console.WriteLine("Creating template...");
var createMutation = new GraphQLRequest
{
Query = @"
mutation CreateTemplate($input: templateCreateInput!) {
createTemplate(input: $input) {
template {
id
title
}
}
}
",
Variables = new
{
input = new
{
groupId = groupId,
title = title
}
}
};
var createResponse = await graphQLClient.SendMutationAsync<dynamic>(createMutation);
string templateId = createResponse.Data.createTemplate.template.id;
Console.WriteLine($"Template created with ID: {templateId}");
// Step 2: Get upload URL
Console.WriteLine("Requesting upload URL...");
var uploadQuery = new GraphQLRequest
{
Query = $@"
query {{
upload(
id: ""{templateId}"",
uploadType: TEMPLATE,
extension: ""pdf""
) {{
url
}}
}}
"
};
var uploadResponse = await graphQLClient.SendQueryAsync<dynamic>(uploadQuery);
string uploadUrl = uploadResponse.Data.upload.url;
Console.WriteLine("Upload URL received");
// Step 3: Upload the PDF
Console.WriteLine("Uploading PDF...");
using var httpClient = new HttpClient();
var fileBytes = await File.ReadAllBytesAsync(pdfFilePath);
var content = new ByteArrayContent(fileBytes);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
var putResponse = await httpClient.PutAsync(uploadUrl, content);
if (!putResponse.IsSuccessStatusCode)
{
throw new Exception($"Upload failed: {putResponse.StatusCode}");
}
Console.WriteLine("PDF uploaded successfully!");
return new UploadResult
{
Success = true,
TemplateId = templateId,
Title = title
};
}
}
public class UploadResult
{
public bool Success { get; set; }
public string TemplateId { get; set; }
public string Title { get; set; }
}
// Usage example
class Program
{
static async Task Main(string[] args)
{
var uploader = new PdfTemplateUploader(
"https://graphql.uk.legalesign.com/graphql",
"Bearer YOUR_TOKEN"
);
var result = await uploader.UploadPdfTemplate(
"grpYourGroupId",
"Employment Contract",
"./contract.pdf"
);
Console.WriteLine($"Complete! Template ID: {result.TemplateId}");
}
}
What Happens After Upload?
Once your PDF is uploaded, Legalesign automatically:
- Scans for viruses - Ensures the file is safe
- Validates the PDF - Checks it's a valid PDF format
- Extracts page information - Gets page count and dimensions
- Processes the file - Optimizes it for viewing and signing
- Stores it securely - Moves it to permanent storage
This process usually takes a few seconds. Once complete, your template is ready to use!
Next Steps
Now that you have a template with a PDF, you can:
- Add signature fields - Use the
createTemplateElementmutation to add fields - Create roles - Define who will sign the document
- Send for signing - Use the
sendmutation to send to recipients - Use the Document Viewer - Integrate our Document Viewer component for a visual editor
Common Issues and Solutions
"No permission" Error
Problem: You don't have access to the group or template.
Solution:
- Verify your group ID is correct
- Ensure you're authenticated with the right account
- Check you have permission to create templates in this group
"File too large" Error
Problem: Your PDF exceeds the 50MB limit.
Solution:
- Compress your PDF using a tool like Adobe Acrobat or online compressors
- Remove unnecessary images or reduce image quality
- Split large documents into multiple templates
Upload URL Expired
Problem: The pre-signed URL expired (after 15 minutes).
Solution:
- Request a new upload URL by running the upload query again
- Upload your file immediately after receiving the URL
- For large files, ensure your internet connection is stable
"Invalid PDF" Error
Problem: The file isn't a valid PDF or is corrupted.
Solution:
- Open the PDF in a PDF reader to verify it's valid
- Re-export or re-save the PDF
- Ensure the file extension is
.pdf
Best Practices
- Validate PDFs before upload - Open them in a PDF reader first
- Use descriptive titles - Makes templates easier to find later
- Keep PDFs under 10MB - Faster uploads and better performance
- Handle errors gracefully - Always check for errors at each step
- Store template IDs - Save them in your database for future reference
Security Considerations
- Never expose authentication tokens - Keep them server-side
- Validate file types - Only upload PDFs for templates
- Check file sizes - Prevent users from uploading huge files
- Use HTTPS - All uploads are encrypted in transit
- Audit uploads - Keep logs of who uploaded what
Related Documentation
- File Upload Overview - General file upload guide
- Create Template Mutation - Full mutation reference
- Document Viewer Component - Visual template editor
- Authentication Guide - How to get access tokens