How to Upload Files to the Legalesign Platform
Many tasks require you to provide a file for the Legalesign platform to use, such as a file to use as a template or an image to use for a signature.
The platform requires you to place this file in the correct sub-folder of our clearing system. This will vet your file for possible security issues and pass it on to the correct location for its purpose.
What You'll Learn​
This guide will walk you through uploading files to Legalesign. Don't worry if you're new to APIs or cloud storage - we'll explain each step clearly.
What is a Pre-Signed URL?​
A pre-signed URL is like a temporary access pass. Instead of giving you permanent access to our storage, we give you a special URL that:
- Only works for a short time (15 minutes)
- Only allows you to upload one specific file
- Keeps your files secure
Think of it like a valet parking ticket - it gives temporary, limited access for a specific purpose.
What is S3?​
S3 (Simple Storage Service) is Amazon's cloud file storage. It's where we safely store your documents, logos, and other files. You don't need to understand S3 in detail - just know that it's a secure place to store files in the cloud.
Overview​
The upload process follows these steps:
- Request a pre-signed upload URL from the GraphQL API (ask for permission to upload)
- Upload your file to S3 using the provided URL (actually send the file)
- The platform automatically processes and validates the file (we check it's safe)
- The file is moved to its final destination (we put it in the right place)
Why This Two-Step Process?​
You might wonder why we don't just let you upload directly. This two-step process:
- Ensures you have permission to upload
- Prevents unauthorized file uploads
- Allows us to scan files for viruses
- Keeps track of who uploaded what
Step 1: Request Upload URL​
First, you need to ask Legalesign for permission to upload your file. You do this by sending a GraphQL query.
What is GraphQL?​
GraphQL is a way to request data from an API. Think of it like filling out a form - you specify what you want, and the server responds with exactly that information.
Use the upload query to obtain a pre-signed URL for your file upload (in this case a PDF). See our authentication guide for more information on how to get started running GraphQL queries.
query {
upload(
id: "<BASE64_OBJECT_ID>",
uploadType: TEMPLATE,
extension: "pdf"
) {
url
}
}
Parameters Explained​
-
id: Base64-encoded object ID (e.g., template ID, experience ID)
- This is a unique identifier for your template or document
- It looks like a random string of letters and numbers
- You'll get this ID when you create a template through the API
-
uploadType: The type of file being uploaded
- This tells us what you're uploading so we can process it correctly
- See upload types below
-
extension: File extension (pdf, png, jpg)
- This is the file type (the part after the dot in a filename)
- Examples: "pdf" for document.pdf, "png" for logo.png
Upload Types​
TEMPLATE- PDF files for document templatesLOGO- Images for signing page brandingEMAILLOGO- Images for email brandingATTACHMENT- Additional files to attach to documents
Step 2: Upload to S3​
Once you receive the pre-signed URL from Step 1, you can now upload your actual file.
How Does This Work?​
The query returns a special URL (the pre-signed URL we mentioned earlier). You then send your file to this URL using an HTTP PUT request.
What is an HTTP PUT Request?​
HTTP PUT is a method for sending data to a server. Think of it like:
- GET = asking for something ("Can I see that file?")
- PUT = giving something ("Here's my file, please store it")
Here's a simple example:
const response = await fetch(url, {
method: 'PUT',
body: fileData,
headers: {
'Content-Type': 'application/pdf' // or appropriate MIME type
}
});
Step 3: Automatic Processing​
Once uploaded, the platform:
- Scans the file for viruses and security threats
- Validates the file format and content
- Processes the file (e.g., extracts page dimensions for PDFs)
- Moves it to the final storage location with appropriate permissions
Complete Example​
Here's a complete working example in three popular programming languages. Each example does the same thing:
- Connects to the Legalesign API
- Requests permission to upload (gets the pre-signed URL)
- Uploads the file to S3
- Confirms success
Before You Start​
You'll need:
- Your Legalesign account credentials (username and password)
- The file you want to upload
- The object ID (template ID or experience ID) where the file should be attached
Understanding the Code​
Each example follows the same pattern:
- Import libraries: Load the tools we need
- Set up authentication: Prove who you are
- Get upload URL: Request permission to upload
- Upload file: Send the actual file
- Handle errors: Deal with problems if they occur
- JavaScript
- Python
- C#
import { generateClient } from 'aws-amplify/api';
const uploadFile = async (objectId, file) => {
const client = generateClient();
const extension = file.name.split('.').pop();
// Step 1: Get upload URL
const result = await client.graphql({
query: `
query {
upload(
id: "${objectId}",
uploadType: TEMPLATE,
extension: "${extension}"
) {
url
}
}
`
});
const uploadUrl = result.data.upload.url;
// Step 2: Upload file
const response = await fetch(uploadUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type
}
});
if (!response.ok) {
throw new Error('Upload failed');
}
return { success: true };
};
import requests
import base64
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport
def upload_file(graphql_endpoint, auth_token, object_id, file_path):
# Get file extension
extension = file_path.split('.')[-1]
# Step 1: Get upload URL
transport = RequestsHTTPTransport(
url=graphql_endpoint,
headers={'Authorization': auth_token}
)
client = Client(transport=transport, fetch_schema_from_transport=True)
query = gql(f'''
query {{
upload(
id: "{object_id}",
uploadType: TEMPLATE,
extension: "{extension}"
) {{
url
}}
}}
''')
result = client.execute(query)
upload_url = result['upload']['url']
# Step 2: Upload file
with open(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('Upload failed')
return {'success': True}
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;
public class FileUploader
{
public async Task<bool> UploadFile(string graphqlEndpoint, string authToken,
string objectId, string filePath)
{
var extension = Path.GetExtension(filePath).TrimStart('.');
// Step 1: Get upload URL
var graphQLClient = new GraphQLHttpClient(
graphqlEndpoint,
new NewtonsoftJsonSerializer()
);
graphQLClient.HttpClient.DefaultRequestHeaders.Add("Authorization", authToken);
var query = new GraphQLRequest
{
Query = $@"
query {{
upload(
id: ""{objectId}"",
uploadType: TEMPLATE,
extension: ""{extension}""
) {{
url
}}
}}
"
};
var response = await graphQLClient.SendQueryAsync<dynamic>(query);
string uploadUrl = response.Data.upload.url;
// Step 2: Upload file
using var httpClient = new HttpClient();
var fileBytes = await File.ReadAllBytesAsync(filePath);
var content = new ByteArrayContent(fileBytes);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
var uploadResponse = await httpClient.PutAsync(uploadUrl, content);
if (!uploadResponse.IsSuccessStatusCode)
{
throw new Exception("Upload failed");
}
return true;
}
}
Path Format​
Understanding File Paths​
When files are stored, they follow a specific naming pattern. This helps organize files and ensures they go to the right place.
Files must follow this naming convention:
<uploadType>/<userId>/<base64ObjectId>.<extension>
Breaking Down the Path​
- uploadType: What kind of file (template, logo, etc.)
- userId: Your unique user identifier (automatically added)
- base64ObjectId: The ID of the template or object (the "id" parameter from Step 1)
- extension: File type (pdf, png, jpg)
Real Example​
Example:
template/usr123abc/dHBsYjQ5YTg5NWQtYWRhMy0xMWYwLWIxZGMtMDY5NzZlZmU0MzIx.pdf
This means:
- It's a template file
- Uploaded by user usr123abc
- For template ID dHBsYjQ5YTg5NWQtYWRhMy0xMWYwLWIxZGMtMDY5NzZlZmU0MzIx
- It's a PDF file
You don't need to create this path yourself - the API handles it automatically when you provide the correct parameters.
Supported File Types​
Templates​
- PDF files only
- Maximum size: 50MB
Logos and Email Logos​
- PNG, JPG, JPEG
- Maximum size: 5MB
- Recommended dimensions: 200x200px (logos), 600x200px (email logos)
Attachments​
- PDF, DOC, DOCX, XLS, XLSX, PNG, JPG
- Maximum size: 25MB
Error Handling​
What Can Go Wrong?​
Sometimes uploads fail. Here are the most common reasons and what they mean:
-
No permission: The object ID doesn't belong to your account or group
- What this means: You're trying to upload to a template you don't own
- How to fix: Check that you're using the correct object ID and that you have access to it
-
Invalid extension: File type not supported for this upload type
- What this means: You're trying to upload the wrong type of file (e.g., a Word doc as a template)
- How to fix: Convert your file to the correct format or use a different upload type
-
File too large: Exceeds maximum size limit
- What this means: Your file is bigger than we allow
- How to fix: Compress your file or reduce its size
-
Virus detected: File failed security scan
- What this means: Our security system found something suspicious in your file
- How to fix: Scan your file with antivirus software and try again with a clean file
Security Notes​
How We Keep Your Files Safe​
-
Pre-signed URLs expire after 15 minutes
- This means if someone intercepts your upload URL, they can't use it later
- If your upload takes longer than 15 minutes, you'll need to request a new URL
-
Files are scanned for viruses before processing
- Every file goes through security checks
- Infected files are rejected and never stored
-
Only users with appropriate permissions can upload files
- You can only upload to templates and objects you own or have access to
- This prevents unauthorized access to other users' data
-
Files are isolated during processing in the clearing bucket
- Uploaded files are kept separate until they pass all security checks
- Only after approval are they moved to permanent storage
Best Practices​
- Always check file size before uploading - Save time by verifying your file meets size requirements
- Use the correct file format - Convert files to supported formats before uploading
- Handle errors gracefully - Always check for errors and provide helpful messages to users
- Don't reuse pre-signed URLs - Request a new URL for each upload
- Keep your credentials secure - Never share your authentication tokens or embed them in client-side code