Skip to main content

How to Implement Embedded Signing

This guide demonstrates how to create envelopes with embedded signing and generate iframe URLs for seamless integration into your application. You'll learn how to create a single signer envelope that delivers via embed and how to retrieve the embedded signing URL.

Overview

Embedded signing allows you to integrate the signing experience directly into your application without redirecting users to external pages:

  1. Create an envelope with deliver_via: "embed" for the signer
  2. Retrieve the embedded URL using the packet ID
  3. Embed the signing interface in your application using an iframe

Envelopes are automatically sent in the background after creation, though they initially show pending status while processing.

Prerequisites

Before you begin, ensure you have:

  • A Blueink account with API access
  • Your API key (available in the Blueink Dashboard under Apps)
  • A PDF file or document template for signing
  • Basic knowledge of HTTP requests and your chosen programming language
  • Understanding of iframe integration in web applications
tip

If you don't have an API key yet, visit the Authentication guide to learn how to obtain one.

Test Mode Email Restrictions

When using is_test: true, envelopes can only be sent to email addresses that belong to users in your Blueink account. Make sure the signer email addresses match existing users in your account when testing.

Step 1: Prepare Your Environment

Authentication Setup

All requests to the Blueink API require authentication using your API key in the Authorization header:

Authorization: Token YOUR_API_KEY_HERE

Required Information

For this guide, you'll need:

  • PDF file path: The local path to your PDF file (or template ID)
  • Signer information: Name and email address of the person who will sign
  • Embed configuration: Setting up the packet for embedded delivery

Step 2: Create Envelope with Embedded Signing

Create an envelope with a single signer configured for embedded delivery using deliver_via: "embed".

import requests
import json

# Configuration
API_KEY = "your_api_key_here"
BASE_URL = "https://api.blueink.com/api/v2"
PDF_FILE_PATH = "path/to/your/document.pdf"

# Headers for authentication
headers = {
"Authorization": f"Token {API_KEY}"
}

# Bundle request data for embedded signing
bundle_request = {
"label": "Embedded Signature Request",
"is_test": True, # Set to False for production
# "status": "dr", # Uncomment to create as draft (default is pending)
"packets": [
{
"key": "signer-1",
"name": "John Doe",
"email": "[email protected]",
"deliver_via": "embed" # This enables embedded signing
}
],
"documents": [
{
"key": "contract-doc",
"file_index": "0", # References the uploaded file
"filename": "contract.pdf"
}
]
}

# Prepare multipart form data
try:
with open(PDF_FILE_PATH, 'rb') as pdf_file:
files = {
'files[0]': ('contract.pdf', pdf_file, 'application/pdf')
}

data = {
'bundle_request': json.dumps(bundle_request)
}

# Create the envelope with embedded signing
response = requests.post(
f"{BASE_URL}/bundles/",
headers=headers,
files=files,
data=data
)

if response.status_code == 201:
bundle = response.json()
print(f"✅ Envelope created successfully!")
print(f"Bundle ID: {bundle['id']}")
print(f"Status: {bundle['status']}")
print(f"📧 Envelope will be automatically sent to signers by background processes.")
print(f"Packet ID: {bundle['packets'][0]['id']}") # We'll need this for the embed URL

# Store the packet ID for the next step
packet_id = bundle['packets'][0]['id']

else:
print(f"❌ Error creating envelope: {response.status_code}")
print(f"Response: {response.text}")

except Exception as e:
print(f"❌ Error: {e}")

Step 3: Retrieve the Embedded Signing URL

Once the envelope is created, use the packet ID to retrieve the embedded signing URL that can be used in an iframe.

def get_embedded_signing_url(packet_id):
"""Retrieve the embedded signing URL for a packet"""
try:
response = requests.post(
f"{BASE_URL}/packets/{packet_id}/embed_url/",
headers=headers
)

if response.status_code == 200:
embed_data = response.json()
embed_url = embed_data['url']
print(f"✅ Embedded URL retrieved successfully!")
print(f"Embed URL: {embed_url}")
return embed_url
else:
print(f"❌ Error retrieving embed URL: {response.status_code}")
print(f"Response: {response.text}")
return None

except Exception as e:
print(f"❌ Error retrieving embed URL: {e}")
return None

# Usage (continuing from Step 2)
if 'packet_id' in locals():
embed_url = get_embedded_signing_url(packet_id)

if embed_url:
print(f"\n🎯 Integration Instructions:")
print(f"Use this URL in an iframe:")
print(f'<iframe src="{embed_url}" width="100%" height="600px" frameborder="0"></iframe>')

API Response Examples

Envelope Creation Response

When successful, the envelope creation returns a 201 Created status with the envelope details:

{
"id": "lL7g5Hn2Ni",
"created": "2025-09-04T23:18:57.615334Z",
"sent": null,
"completed_at": null,
"label": "Embedded Signature Request",
"in_order": false,
"is_test": true,
"status": "pe",
"custom_key": null,
"custom_text": "",
"packets": [
{
"id": "a6v1qN4z8T",
"key": "signer-1",
"name": "John Doe",
"email": "[email protected]",
"phone": "",
"auth_sms": false,
"auth_selfie": false,
"auth_secrets": null,
"auth_id": false,
"person_id": "db600721-d8e7-42d3-8ebe-a180b4864eb8",
"status": "ne",
"deliver_via": "embed",
"completed_at": null,
"last_accessed_at": null,
"order": 1,
"signing_complete_redirect": "",
"suppress_all": false,
"suppress_docs_ready": false,
"suppress_signing": false,
"suppress_reminder": false
}
],
"documents": [
{
"id": "doc456",
"key": "contract-doc",
"filename": "contract.pdf",
"status": "pr"
}
],
"errors": null,
"cc_emails": [],
"email_message": "",
"email_subject": "",
"team": null,
"tags": [],
"send_reminders": false,
"reminder_offset": 0,
"reminder_interval": 0,
"reminder_expires": 0,
"expires": null,
"sms_message": "",
"requester_name": "",
"requester_email": "",
"payment": null
}

Embedded URL Response

The embed URL endpoint returns a 200 OK status with the signing URL:

{
"url": "https://app.blueink.com/packets/a6v1qN4z8T/embed/?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}

Frontend Integration

HTML iframe Integration

Once you have the embedded URL, integrate it into your web application:

<!DOCTYPE html>
<html>
<head>
<title>Document Signing</title>
<style>
.signing-container {
width: 100%;
height: 600px;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
}

.signing-iframe {
width: 100%;
height: 100%;
border: none;
}
</style>
</head>
<body>
<div class="signing-container">
<iframe
id="signing-iframe"
class="signing-iframe"
src="EMBED_URL_HERE"
title="Document Signing">
</iframe>
</div>

<script>
// Optional: Listen for signing completion events
window.addEventListener('message', function(event) {
if (event.origin !== 'https://app.blueink.com') {
return;
}

if (event.data.type === 'signing_complete') {
console.log('Document signed successfully!');
// Handle signing completion
window.location.href = '/success';
}
});
</script>
</body>
</html>

React Integration Example

import React, { useEffect, useState } from 'react';

const EmbeddedSigning = ({ packetId }) => {
const [embedUrl, setEmbedUrl] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
const getEmbedUrl = async () => {
try {
const response = await fetch(`/api/packets/${packetId}/embed_url/`, {
method: 'POST',
headers: {
'Authorization': `Token ${process.env.REACT_APP_API_KEY}`,
'Content-Type': 'application/json'
}
});

if (response.ok) {
const data = await response.json();
setEmbedUrl(data.url);
} else {
setError('Failed to load signing interface');
}
} catch (err) {
setError('Network error occurred');
} finally {
setLoading(false);
}
};

if (packetId) {
getEmbedUrl();
}
}, [packetId]);

const handleMessage = (event) => {
if (event.origin !== 'https://app.blueink.com') {
return;
}

if (event.data.type === 'signing_complete') {
console.log('Document signed successfully!');
// Handle signing completion
}
};

useEffect(() => {
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, []);

if (loading) {
return <div>Loading signing interface...</div>;
}

if (error) {
return <div>Error: {error}</div>;
}

return (
<div style={{ width: '100%', height: '600px', border: '1px solid #ddd' }}>
<iframe
src={embedUrl}
width="100%"
height="100%"
frameBorder="0"
title="Document Signing"
/>
</div>
);
};

export default EmbeddedSigning;

Error Handling and Best Practices

Common Error Scenarios

  1. Packet Not Found (404 Not Found)

    {
    "detail": "Packet not found."
    }
  2. Authentication Error (401 Unauthorized)

    {
    "detail": "Invalid token."
    }
  3. Packet Not Ready for Embedding (400 Bad Request)

    {
    "detail": "Packet is not configured for embedded delivery."
    }

Best Practices

  1. Security Considerations

    • Never expose your API key in frontend code
    • Use server-side endpoints to generate embed URLs
    • Implement proper CORS policies
    • Validate packet ownership before generating URLs
  2. User Experience

    • Provide loading states while generating embed URLs
    • Handle iframe loading errors gracefully
    • Implement responsive iframe sizing
    • Listen for completion events to redirect users
  3. Error Handling

    • Always check response status codes
    • Implement retry logic for transient failures
    • Provide meaningful error messages to users
    • Log errors for debugging purposes
  4. Performance

    • Cache embed URLs when appropriate (they have limited lifetime)
    • Preload signing interfaces when possible
    • Optimize iframe dimensions for your layout

Security and Compliance

iframe Security

  • Content Security Policy: Configure CSP headers to allow Blueink domains
  • X-Frame-Options: Ensure your application allows iframe embedding
  • HTTPS Required: Embedded signing requires HTTPS for security

Data Protection

  • Embedded signing maintains the same security standards as regular signing
  • All data transmission is encrypted
  • Audit trails are preserved for embedded signatures
  • Compliance certifications apply to embedded workflows

Next Steps

Now that you've learned how to implement embedded signing, you might want to explore:

Need Help?

If you encounter issues or have questions:

  • Check the API Reference for detailed endpoint documentation
  • Visit our Support Center for additional resources
  • Contact our support team through the Blueink Dashboard

Embedded signing provides a seamless user experience by keeping users within your application throughout the signing process. By following this guide, you can integrate professional e-signature capabilities directly into your workflow.