Skip to main content

Create an Embedded Signing Experience

Embedding the eSign experience directly into your application provides a seamless, white-labeled signing interface that keeps users within your workflow. Instead of redirecting signers to their email or an external page, you can integrate the complete signing experience right into your application using iframes.

This guide walks you through creating an embedded signing experience from start to finish.


Why Use Embedded Signing?

Benefits of embedding the signing experience:

  • Seamless user experience - Users never leave your application
  • Complete branding control - Customize colors, fonts, and styling to match your brand
  • Higher conversion rates - Reduce friction in the signing process
  • Additional security - Control access within your authenticated sessions

Overview

Creating an embedded signing experience involves four main steps:

  1. Upload a PDF document to the system
  2. Create an eSign transaction with participants and tags
  3. Generate a customized iframe URL with your branding
  4. Embed the signing interface in your application

Prerequisites

Before you begin, ensure you have:

  • A valid Bearer token (JWT) for authentication
  • At least one PDF document ready for upload
  • Basic HTML/JavaScript knowledge for embedding
  • Familiarity with eSign transactions

All API requests must include the following header:

Authorization: Bearer <your_access_token>
Content-Type: application/json

Step 1: Upload Your Document

First, upload your PDF file to the system.

Endpoint

POST /documents/upload

Request (multipart/form-data)

curl -X POST "https://api.sign.stewart.com/documents/upload" \
-H "Authorization: Bearer <token>" \
-F "files=@EmploymentContract.pdf"

Successful Response

[
{
"file": "EmploymentContract.pdf",
"status": "uploaded",
"StoragePath": "org-uuid/EmploymentContract.pdf"
}
]
tip

Save the StoragePath from the response — you'll need it to create your transaction in the next step.


Step 2: Create an eSign Transaction

Once your document is uploaded, create a transaction that defines participants, documents, and signing fields (tags).

Endpoint

POST /transactions

Important: Generate UUIDs

Before making the request, generate unique UUIDs for:

  • Each document's id field
  • Each participant's id field

You can generate UUIDs using online tools, programming libraries, or command-line utilities:

# Generate UUID
uuidgen

# Example output: 391866a6-8ebb-4533-b6ab-c7bb4d6fbd38

Example Request

curl -X POST "https://api.sign.stewart.com/transactions" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"notifyParticipants": {
"email": false // disable email sends from the system (optional)
},
"documents": [
{
"id": "391866a6-8ebb-4533-b6ab-c7bb4d6fbd38",
"StoragePath": "org-uuid/EmploymentContract.pdf",
"title": "Employment Agreement",
"description": "Please review and sign your employment agreement",
"sessionType": "esign",
"readOnly": false,
"tags": [
{
"type": "SIGNHERETAGTEMPLATEANNOTATION",
"x": 100,
"y": 150,
"width": 150,
"height": 34,
"page": 0,
"signerId": "37da192e-6420-4b9c-9951-a979eeaf8889",
"required": true
},
{
"type": "DATETEMPLATE",
"x": 270,
"y": 150,
"width": 100,
"height": 20,
"page": 0,
"signerId": "37da192e-6420-4b9c-9951-a979eeaf8889",
"dateFormat": "MM/DD/YYYY"
},
{
"type": "FULLNAMETEMPLATE",
"x": 100,
"y": 190,
"width": 150,
"height": 20,
"page": 0,
"signerId": "37da192e-6420-4b9c-9951-a979eeaf8889"
}
]
}
],
"participants": [
{
"id": "37da192e-6420-4b9c-9951-a979eeaf8889",
"email": "jane.smith@example.com",
"firstName": "Jane",
"lastName": "Smith",
"type": "signer"
}
],
"status": "esign_pending"
}'

Example Successful Response

{
"id": "transaction-uuid-here",
"esignId": "357aa7c7-16fd-4a2c-bd58-23da1f76fdd5",
"documents": [
{
"id": "391866a6-8ebb-4533-b6ab-c7bb4d6fbd38",
"title": "Employment Agreement",
"StoragePath": "org-uuid/EmploymentContract.pdf",
"sessionType": "esign"
}
],
"participants": [
{
"id": "37da192e-6420-4b9c-9951-a979eeaf8889",
"email": "jane.smith@example.com",
"firstName": "Jane",
"lastName": "Smith",
"type": "signer"
}
],
"status": "esign_pending"
}
info

Save both the esignId and the participant id from the response. You'll need these values to generate the iframe URL in the next step.

For more details on tags and transaction creation, see:


Step 3: Generate the iFrame URL

Generate a customized iframe URL that matches your brand's look and feel.

Endpoint

POST /iframe-request

Request Body

The iframe request accepts two main sections:

  • type: Set to "esign" for eSignature workflows
  • style: Customize colors, fonts, and appearance
  • data: Specify the transaction and participant(s)

Style Customization Options

PropertyTypeDescriptionExample
primaryColorHex ColorMain brand color for buttons and highlights#006837
secondaryColorHex ColorBackground color for secondary elements#f5f5f5
fontTypeFont FamilyCustom font (must be web-safe or loaded)Arial, sans-serif
textColorHex ColorMain text color#333333
backgroundHex ColorPage background color#ffffff
successColorHex ColorSuccess message color#28a745
errorColorHex ColorError message color#dc3545
infoColorHex ColorInfo message color#17a2b8

Example Request

curl -X POST "https://api.sign.stewart.com/iframe-request" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"type": "esign",
"style": {
"primaryColor": "#006837",
"secondaryColor": "#f5f5f5",
"fontType": "Arial, sans-serif",
"textColor": "#333333",
"background": "#ffffff",
"successColor": "#28a745",
"errorColor": "#dc3545",
"infoColor": "#17a2b8"
},
"data": {
"esignId": "357aa7c7-16fd-4a2c-bd58-23da1f76fdd5",
"participantIds": [
"37da192e-6420-4b9c-9951-a979eeaf8889"
]
}
}'

Example Response

{
"url": "https://enlapp.page.link/c7u1E2jiYtCs65KCA"
}
Branding Tips
  • Extract colors from your existing brand guidelines
  • Ensure sufficient color contrast for accessibility (WCAG 2.1 compliance)

Step 4: Embed the iFrame in Your Application

Now that you have the iframe URL, you can embed it in your application.

Basic HTML Example

Here's a simple HTML page that embeds the signing experience:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign Your Document</title>
<style>
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
}
.header {
background-color: #006837;
color: white;
padding: 20px;
text-align: center;
}
.iframe-container {
width: 100%;
max-width: 1200px;
margin: 20px auto;
background: white;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
border-radius: 8px;
overflow: hidden;
}
#signing-iframe {
border: none;
width: 100%;
height: 800px;
display: block;
}
</style>
</head>
<body>
<div class="header">
<h1>Complete Your Document Signature</h1>
</div>

<div class="iframe-container">
<iframe
id="signing-iframe"
src="https://enlapp.page.link/c7u1E2jiYtCs65KCA"
allow="camera *; microphone *"
allowfullscreen>
</iframe>
</div>
</body>
</html>

Important iFrame Attributes

AttributePurposeRequired
allow="camera *; microphone *"Enables camera/microphone access for identity verification (if configured)Recommended
allowfullscreenAllows the iframe to enter fullscreen modeRecommended
style="border: none"Removes default iframe border for seamless integrationOptional

Monitoring Signing Completion

Set up a webhook endpoint to receive real-time notifications when signing is complete.

Example esign-completed webhook payload:

{
"event": "esign-completed",
"entity": "esign",
"data": {
"notificationId": "a8b9c7d6-e5f4-3210-9876-543210fedcba",
"entity_id": "357aa7c7-16fd-4a2c-bd58-23da1f76fdd5",
"transaction_id": "transaction-uuid-here"
}
}

Key fields:

  • event: Always "esign-completed" for completed eSign sessions
  • entity: Always "esign" for eSign events
  • data.notificationId: Unique ID for this webhook notification (use for idempotency)
  • data.entity_id: The eSignId from your transaction
  • data.transaction_id: The transaction ID

For webhook setup details and all available events, see Webhook Events.

iFrame Events

The iFrame also publishes UX events to the parent frame which can be utilized for custom actions. Reach out to support for more details on available iframe events.


Best Practices

Security

  • Generate iframe URLs server-side and pass only the URL to your frontend
  • Validate participant access before generating iframe URLs
  • Use HTTPS only for all communication
  • Implement session timeouts for added security

User Experience

  • Show loading states while the iframe is loading
  • Provide clear instructions before displaying the iframe
  • Handle errors gracefully with user-friendly messages

Troubleshooting

Common Issues and Solutions

Camera/Microphone Permissions Not Working

Issue: User can't access camera or microphone for identity verification.

Solution: Ensure the allow attribute is properly set:

<iframe allow="camera *; microphone *" ...></iframe>

Also verify your page is served over HTTPS, as camera/microphone access requires a secure context.


iFrame Not Loading

Possible causes and solutions:

  1. Invalid or expired URL

    • Generate a fresh iframe URL
    • Check that the esignId and participantIds are correct
  2. CORS or security errors

    • Verify your page is served over HTTPS
    • Check browser console for specific error messages
  3. Incorrect iframe attributes

    • Ensure src attribute is set correctly
    • Verify no ad blockers are interfering

Custom Styling Not Applied

Issue: Colors or fonts don't appear as expected.

Solutions:

  • Verify hex color format is correct (e.g., #006837 not 006837)
  • Check that the style object was included in the iframe request
// ❌ Incorrect
{
"style": {
"primaryColor": "006837" // Missing #
}
}

// ✅ Correct
{
"style": {
"primaryColor": "#006837"
}
}

Participant Cannot Access Signing

Issue: Signer sees an error when accessing the iframe.

Possible causes:

  • Participant ID doesn't match the transaction
  • Transaction status is already completed or cancelled
  • Transaction was deleted or expired

Solution: Verify the transaction details:

curl -X GET "https://api.sign.stewart.com/transactions/{transactionId}" \
-H "Authorization: Bearer <token>"


💬 Need Help?

Contact the Stewart Sign Support Team for technical assistance or integration guidance.