Documenso

Direct Links

Share a URL or embed an iframe to let users sign documents without email invitations.

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

View and sign a document without receiving an email invitation

Enter their own name and email address

Complete signature fields and submit the document

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

  • 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)

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

Via the Dashboard

Go to Templates and create or select a template

Team templates

Click the three-dot menu and select Direct link

Click Enable direct link signing

Choose which recipient in your template will use the direct link

Enable direct link

Copy the generated URL

Via the API

Create a direct link for an existing template:

# 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
  }'
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}

Response

{
  "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 in an iframe

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

Basic iframe Embedding

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

Responsive iframe

<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

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>
  );
}

The embed URL uses /embed/direct/{token} instead of /d/{token}. The embed version is optimized for iframe embedding with reduced navigation.


Embedding with Redirect

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

Simple Redirect

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:

Edit your template

Go to Advanced Settings

Set Redirect URL to your desired return URL (e.g., https://yourapp.com/signed)

Or set it via API when creating the template:

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

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 TypeDescription
NoneAnyone with the link can sign
AccountSigner must be logged into a Documenso account

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

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
    },
  }),
});

Temporarily disable a direct link without deleting it:

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
  }'
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,
  }),
});

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

Permanently remove a direct link:

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

Deleting a direct link invalidates the URL permanently. If you enable direct links again, a new URL will be generated.


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:

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
    },
  }),
});

White-labeling

Enterprise plans support white-label embedding with the "Powered by Documenso" badge removed. Contact sales for details.


Handling Completion

Webhook Notifications

Set up webhooks to receive notifications when documents are signed:

{
  "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 for setup instructions.

Polling for Status

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

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:

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

On this page