---
title: Direct Links
description: Share a URL or embed an iframe to let users sign documents without email invitations.
---

import { Callout } from 'fumadocs-ui/components/callout';
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';

## What Are Direct Links?

Direct links are unique URLs tied to a template that allow anyone to:

{/* prettier-ignore */}
<Steps>
  <Step>
    View and sign a document without receiving an email invitation
  </Step>
  <Step>
    Enter their own name and email address
  </Step>
  <Step>
    Complete signature fields and submit the document
  </Step>
</Steps>

When someone uses a direct link, Documenso creates a new document from the template with that person as the signer.

### When to Use Direct Links

- Collecting signatures from unknown recipients (forms, waivers, petitions)
- Embedding signing in your website or application
- Self-service contracts where customers initiate signing
- Public-facing agreements that anyone can sign

### Limitations

- Only work with templates, not individual documents
- Each link is tied to one recipient role in the template
- Recipients enter their own information (you cannot prefill recipient details)

## Creating Direct Link Templates

Before embedding, you need a template with direct links enabled.

### Via the Dashboard

{/* prettier-ignore */}
<Steps>
<Step>
Go to **Templates** and create or select a template

![Team templates](/embedding/team-templates.png)

</Step>
<Step>
Click the three-dot menu and select **Direct link**
</Step>
<Step>
Click **Enable direct link signing**
</Step>
<Step>
Choose which recipient in your template will use the direct link

![Enable direct link](/embedding/enable-direct-link.png)

</Step>
<Step>
Copy the generated URL
</Step>
</Steps>

### Via the API

Create a direct link for an existing template:

<Tabs items={['curl', 'TypeScript']}>
<Tab value="curl">
```bash
# Create direct link for template
curl -X POST "https://app.documenso.com/api/v2/template/direct/create" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123,
    "directRecipientId": 1
  }'
```
</Tab>
<Tab value="TypeScript">
```typescript
const API_TOKEN = process.env.DOCUMENSO_API_TOKEN;
const BASE_URL = 'https://app.documenso.com/api/v2';

const response = await fetch(`${BASE_URL}/template/direct/create`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    directRecipientId: 1, // Optional: specific recipient to use
  }),
});

const directLink = await response.json();
console.log('Direct link token:', directLink.token);
// URL: https://app.documenso.com/d/{token}
````
</Tab>
</Tabs>

### Response

```json
{
  "id": 456,
  "token": "abc123xyz",
  "templateId": 123,
  "directTemplateRecipientId": 1,
  "enabled": true,
  "createdAt": "2025-01-15T10:00:00.000Z"
}
````

The direct link URL format is:

```
https://app.documenso.com/d/{token}
```

![Copy recipient token](/embedding/copy-recipient-token.png)

---

## Embedding in an iframe

Embed the signing experience directly in your application using an iframe.

### Basic iframe Embedding

```html
<iframe
  src="https://app.documenso.com/embed/direct/abc123xyz"
  width="100%"
  height="800"
  frameborder="0"
  allow="clipboard-write"
></iframe>
```

### Responsive iframe

```html
<div style="position: relative; width: 100%; padding-bottom: 75%; height: 0; overflow: hidden;">
  <iframe
    src="https://app.documenso.com/embed/direct/abc123xyz"
    style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;"
    allow="clipboard-write"
  ></iframe>
</div>
```

### React Component Example

```tsx
function DocumentSigner({ token }: { token: string }) {
  return (
    <div className="h-[800px] w-full">
      <iframe
        src={`https://app.documenso.com/embed/direct/${token}`}
        className="h-full w-full border-0"
        allow="clipboard-write"
        title="Sign Document"
      />
    </div>
  );
}
```

<Callout type="info">
  The embed URL uses `/embed/direct/{token}` instead of `/d/{token}`. The embed version is optimized
  for iframe embedding with reduced navigation.
</Callout>

---

## Embedding with Redirect

Instead of an iframe, redirect users to the signing page and bring them back after completion.

### Simple Redirect

```typescript
function redirectToSigning(token: string) {
  window.location.href = `https://app.documenso.com/d/${token}`;
}
```

### With Return URL

Configure a redirect URL in your template settings to return users to your application after signing:

{/* prettier-ignore */}
<Steps>
  <Step>
    Edit your template
  </Step>
  <Step>
    Go to **Advanced Settings**
  </Step>
  <Step>
    Set **Redirect URL** to your desired return URL (e.g., `https://yourapp.com/signed`)
  </Step>
</Steps>

Or set it via API when creating the template:

```typescript
const response = await fetch(`${BASE_URL}/template/update`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    meta: {
      redirectUrl: 'https://yourapp.com/signing-complete',
    },
  }),
});
```

After signing completes, users are automatically redirected to the specified URL.

---

## URL Parameters

Pass additional data through the direct link URL using query parameters.

### External ID

Track which document belongs to which transaction in your system:

```
https://app.documenso.com/d/abc123xyz?externalId=order-12345
```

The external ID is stored with the created document and included in webhook payloads.

### Example: Dynamic External ID

```typescript
function getSigningUrl(token: string, orderId: string) {
  const params = new URLSearchParams({
    externalId: orderId,
  });

  return `https://app.documenso.com/d/${token}?${params.toString()}`;
}

// Usage
const url = getSigningUrl('abc123xyz', 'order-12345');
// https://app.documenso.com/d/abc123xyz?externalId=order-12345
```

### Embed URL Parameters

The embed URL supports the same parameters:

```
https://app.documenso.com/embed/direct/abc123xyz?externalId=order-12345
```

---

## Security Considerations

### Access Authentication

Direct links can require authentication before signing. Configure this in your template settings:

| Auth Type | Description                                    |
| --------- | ---------------------------------------------- |
| None      | Anyone with the link can sign                  |
| Account   | Signer must be logged into a Documenso account |

To require authentication, set `globalAccessAuth` when creating or updating the template:

```typescript
const response = await fetch(`${BASE_URL}/template/update`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    data: {
      globalAccessAuth: ['ACCOUNT'], // Require login
    },
  }),
});
```

### Disabling Direct Links

Temporarily disable a direct link without deleting it:

<Tabs items={['curl', 'TypeScript']}>
<Tab value="curl">
```bash
curl -X POST "https://app.documenso.com/api/v2/template/direct/toggle" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123,
    "enabled": false
  }'
```
</Tab>
<Tab value="TypeScript">
```typescript
const response = await fetch(`${BASE_URL}/template/direct/toggle`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    enabled: false,
  }),
});
```
</Tab>
</Tabs>

Re-enable later by setting `enabled: true`. The URL remains the same.

### Deleting Direct Links

Permanently remove a direct link:

```bash
curl -X POST "https://app.documenso.com/api/v2/template/direct/delete" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123
  }'
```

<Callout type="warn">
  Deleting a direct link invalidates the URL permanently. If you enable direct links again, a new
  URL will be generated.
</Callout>

---

## Styling and Customization

### Branding

The signing experience uses your organisation's branding settings:

- Logo
- Primary color
- Email customization

Configure branding in **Settings** > **Branding** or via team settings.

### Signature Options

Control which signature input methods are available:

```typescript
const response = await fetch(`${BASE_URL}/template/update`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    meta: {
      typedSignatureEnabled: true, // Allow typed signatures
      drawSignatureEnabled: true, // Allow drawn signatures
      uploadSignatureEnabled: false, // Disable uploaded signatures
      qrSignatureEnabled: true, // Allow QR code handoff to a mobile device
    },
  }),
});
```

### White-labeling

Enterprise plans support white-label embedding with the "Powered by Documenso" badge removed. [Contact sales](mailto:support@documenso.com) for details.

---

## Handling Completion

### Webhook Notifications

Set up webhooks to receive notifications when documents are signed:

```json
{
  "event": "DOCUMENT_SIGNED",
  "payload": {
    "id": 123,
    "externalId": "order-12345",
    "title": "contract.pdf",
    "status": "COMPLETED",
    "Recipient": [
      {
        "email": "signer@example.com",
        "name": "John Doe",
        "signingStatus": "SIGNED",
        "signedAt": "2024-01-15T10:30:00.000Z"
      }
    ]
  },
  "createdAt": "2024-01-15T10:30:00.000Z",
  "webhookEndpoint": "https://your-endpoint.com/webhook"
}
```

See [Webhooks](/docs/developers/webhooks) for setup instructions.

### Polling for Status

If webhooks aren't suitable, poll the document status:

```typescript
async function checkDocumentStatus(externalId: string) {
  const response = await fetch(`${BASE_URL}/envelope?source=TEMPLATE_DIRECT_LINK`, {
    headers: { Authorization: API_TOKEN },
  });

  const { data } = await response.json();

  return data.find((doc) => doc.externalId === externalId);
}
```

---

## Complete Example

This example shows a complete workflow for embedding direct link signing:

```typescript
const API_TOKEN = process.env.DOCUMENSO_API_TOKEN;
const BASE_URL = 'https://app.documenso.com/api/v2';

// 1. Get template with direct link
async function getDirectLinkTemplate(templateId: number) {
  const response = await fetch(`${BASE_URL}/template/${templateId}`, {
    headers: { Authorization: API_TOKEN },
  });

  return response.json();
}

// 2. Create direct link if not exists
async function ensureDirectLink(templateId: number, recipientId: number) {
  const template = await getDirectLinkTemplate(templateId);

  if (template.directLink?.enabled) {
    return template.directLink.token;
  }

  const response = await fetch(`${BASE_URL}/template/direct/create`, {
    method: 'POST',
    headers: {
      Authorization: API_TOKEN,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      templateId,
      directRecipientId: recipientId,
    }),
  });

  const directLink = await response.json();
  return directLink.token;
}

// 3. Generate signing URL with tracking
function getEmbedUrl(token: string, orderId: string) {
  const params = new URLSearchParams({ externalId: orderId });
  return `https://app.documenso.com/embed/direct/${token}?${params}`;
}

// Usage
const token = await ensureDirectLink(123, 1);
const embedUrl = getEmbedUrl(token, 'order-12345');

// Embed in your page
document.getElementById('signer-frame').src = embedUrl;
```

---

## See Also

- [SDKs](/docs/developers/embedding/sdks) - Framework SDK integration
- [Templates API](/docs/developers/api/templates) - Template management
- [Webhooks](/docs/developers/webhooks) - Event notifications
- [Direct Links (User Guide)](/docs/users/documents/direct-links) - End-user documentation
