# 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](/docs/esignature-api/authentication/) 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"`.

#### Python

### Using the Python SDK

```python
from blueink.client import Client

client = Client(api_key="your_api_key_here")

# Define bundle details
bundle_data = {
    "label": "Embedded Signature Request",
    "is_test": True,
    "packets": [
        {
            "key": "signer-1",
            "name": "John Doe",
            "email": "john.doe@example.com",
            "deliver_via": "embed"  # This enables embedded signing
        }
    ],
    "documents": [
        {
            "key": "contract-doc",
            "file_index": 0,
            "filename": "contract.pdf"
        }
    ]
}

# Open the file and send
with open("path/to/document.pdf", "rb") as f:
    files = [{"file": f, "filename": "contract.pdf"}]
    response = client.bundles.create(data=bundle_data, files=files)

if response.status == 201:
    packet_id = response.data.packets[0].id
    print(f"✅ Envelope created! Packet ID: {packet_id}")
```

#### JavaScript

### Using the JavaScript SDK

```javascript
const { Client } = require('@blueink360/blueink-client-js');
const fs = require('fs');

const client = new Client('your_api_key_here');

const bundleData = {
    label: 'Embedded Signature Request',
    is_test: true,
    packets: [
        {
            key: 'signer-1',
            name: 'John Doe',
            email: 'john.doe@example.com',
            deliver_via: 'embed'
        }
    ],
    documents: [
        {
            key: 'contract-doc',
            file_index: 0,
            filename: 'contract.pdf'
        }
    ]
};

const files = [
    {
        file: fs.createReadStream('path/to/document.pdf'),
        filename: 'contract.pdf'
    }
];

client.bundles.create(bundleData, files)
    .then(response => {
        const packetId = response.data.packets[0].id;
        console.log(`✅ Envelope created! Packet ID: ${packetId}`);
    });
```

#### PHP

### Using the PHP SDK

```php
<?php
use Blueink\ClientSDK\Client;

$client = new Client("your_api_key_here");

$bundleData = [
    "label" => "Embedded Signature Request",
    "is_test" => true,
    "packets" => [
        [
            "key" => "signer-1",
            "name" => "John Doe",
            "email" => "john.doe@example.com",
            "deliver_via" => "embed"
        ]
    ],
    "documents" => [
        [
            "key" => "contract-doc",
            "file_index" => 0,
            "filename" => "contract.pdf"
        ]
    ]
];

$files = [
    [
        "file" => fopen("path/to/document.pdf", "r"),
        "filename" => "contract.pdf"
    ]
];

$response = $client->bundles->create($bundleData, $files);

if ($response->status === 201) {
    $packetId = $response->data->packets[0]->id;
    echo "✅ Envelope created! Packet ID: " . $packetId;
}
```

## 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.

#### Python

### Using the Python SDK

```python
from blueink.client import Client

client = Client(api_key="your_api_key_here")

# Get embedded signing URL for a specific packet
response = client.packets.embed_url(packet_id="packet-id-here")

if response.status == 200:
    print(f"✅ Embedded URL: {response.data.url}")
```

#### JavaScript

### Using the JavaScript SDK

```javascript
const { Client } = require('@blueink360/blueink-client-js');
const client = new Client('your_api_key_here');

client.packets.embed_url('packet-id-here')
    .then(response => {
        console.log(`✅ Embedded URL: ${response.data.url}`);
    });
```

#### PHP

### Using the PHP SDK

```php
<?php
use Blueink\ClientSDK\Client;

$client = new Client("your_api_key_here");

$response = $client->packets->embedUrl("packet-id-here");

if ($response->status === 200) {
    echo "✅ Embedded URL: " . $response->data->url;
}
```

## API Response Examples

### Envelope Creation Response

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

```json
{
    "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": "john.doe@example.com",
            "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:

```json
{
    "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:

```html
<!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

```jsx
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)**
   ```json
   {
       "detail": "Packet not found."
   }
   ```

2. **Authentication Error (401 Unauthorized)**
   ```json
   {
       "detail": "Invalid token."
   }
   ```

3. **Packet Not Ready for Embedding (400 Bad Request)**
   ```json
   {
       "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:

- **[Send Envelope with Uploaded PDF](/docs/guides/send-envelope-with-uploaded-pdf/)** - How to create envelopes by uploading PDF files
- **[Send Envelope with Templates](/docs/guides/send-envelope-with-templates/)** - How to use templates for embedded signing
- **[API Reference](/docs/api/)** - Complete API documentation for all endpoints and operations
- **[Webhook Integration](/docs/esignature-api/webhook/)** - How to receive real-time notifications about signing events

## Need Help?

If you encounter issues or have questions:

- Check the [API Reference](/docs/api/) for detailed endpoint documentation
- Visit our [Support Center](https://help.blueink.com) 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.
