E-Signature Webhook Setup Guide (PandaDoc)
Same for PandaDoc.
E-Signature Webhook Setup Guide (PandaDoc)
PandaDoc webhooks webhooksClick to read the full definition in our AI & Automation Glossary. eliminate manual status checks and data entry after clients sign engagement letters. When a document gets signed, PandaDoc sends a POST request to your endpoint. Your system receives it, updates the CRM CRMCustomer Relationship Management software. The system of record for contacts, deals, and client communication. Examples: HubSpot, Salesforce, Pipedrive., triggers the welcome sequence, and provisions access - all without human intervention.
This guide covers the complete setup: creating the webhook in PandaDoc, building a secure endpoint, handling the payload, and testing the integration.
What You Need Before Starting
PandaDoc Account with API Access
Business or Enterprise plans include webhook functionality. Standard plans do not. Check your plan at Settings > Billing. If you're on Standard, upgrade or use Zapier as a workaround (covered below).
Webhook Receiver
You need a publicly accessible HTTPS endpoint that accepts POST requests. Three options:
- Zapier: No coding required. $20/month for the Starter plan gets you webhook triggers.
- Make (formerly Integromat): Similar to Zapier. Free tier includes webhooks.
- Custom endpoint: Your own server or serverless function (AWS Lambda, Azure Functions, Cloudflare Workers).
System to Update
Identify where signed document data should flow: Salesforce, HubSpot, Clio, practice management system, or a database. You'll need API APIApplication Programming Interface. The connection point that lets two pieces of software exchange data. How n8n talks to your CRM. credentials for that system.
Step 1: Create the Webhook in PandaDoc
- Log into PandaDoc and go to Settings > Integrations > Webhooks.
- Click Create Webhook.
- Enter a name: "Client Onboarding - Document Signed".
- Paste your webhook URL. For Zapier, you'll get this in Step 2. For custom endpoints, use your server URL (must start with
https://). - Select events to monitor:
document_state_changed: Fires when status changes (sent, viewed, completed, voided).recipient_completed: Fires when a specific recipient finishes signing.document_completed: Fires when all recipients sign.
For client onboarding, use document_completed. This ensures you only trigger downstream actions after everyone signs.
- Under Authentication, choose Shared Secret.
- Generate a random 32-character string (use a password manager or
openssl rand -hex 16). Save this - you'll use it to verify webhook authenticity. - Paste the secret into the Shared Secret field.
- Click Save.
Do not click "Test Webhook" yet. Your endpoint doesn't exist.
Step 2: Build Your Webhook Endpoint
Option A: Zapier (No-Code)
- In Zapier, create a new Zap.
- For the trigger, search for Webhooks by Zapier and select Catch Hook.
- Copy the webhook URL Zapier provides.
- Go back to PandaDoc and edit your webhook. Paste the Zapier URL into the Webhook URL field. Save.
- Return to Zapier and click Test Trigger. In PandaDoc, send a test document to yourself and complete it. Zapier should catch the payload.
- Add an action step. Search for your CRM (Salesforce, HubSpot, etc.) and select Update Record or Create Record.
- Map fields:
data.name→ Document Titledata.recipients[0].email→ Contact Emaildata.status→ Status Fielddata.id→ PandaDoc Document ID (store this for reference)
- Add a second action: Gmail or SendGrid to send a welcome email.
- Test the Zap end-to-end. Turn it on.
Zapier Limitation: You cannot verify the shared secret in Zapier's free webhook trigger. Upgrade to a paid plan and use Code by Zapier to add signature verification (see custom endpoint code below for logic).
Option B: Custom Endpoint (Node.js Example)
This example uses Express.js and runs on any Node server or AWS Lambda.
Install dependencies:
npm install express body-parser crypto
Create webhook-handler.js:
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const app = express();
app.use(bodyParser.json());
const PANDADOC_SECRET = 'your_32_char_secret_here';
const PORT = process.env.PORT || 3000;
// Verify PandaDoc signature
function verifySignature(payload, signature) {
const hash = crypto
.createHmac('sha256', PANDADOC_SECRET)
.update(JSON.stringify(payload))
.digest('hex');
return hash === signature;
}
app.post('/webhooks/pandadoc', async (req, res) => {
const signature = req.headers['x-pandadoc-signature'];
if (!signature || !verifySignature(req.body, signature)) {
console.error('Invalid signature');
return res.status(401).send('Unauthorized');
}
const event = req.body;
const eventType = event.event;
const document = event.data;
console.log(`Received event: ${eventType} for document ${document.id}`);
if (eventType === 'document_completed') {
const recipientEmail = document.recipients[0].email;
const documentName = document.name;
// Update CRM
await updateCRM(recipientEmail, {
engagement_letter_signed: true,
pandadoc_document_id: document.id,
signed_date: new Date().toISOString()
});
// Send welcome email
await sendWelcomeEmail(recipientEmail, documentName);
// Provision client portal access
await provisionPortalAccess(recipientEmail);
}
res.status(200).send('OK');
});
async function updateCRM(email, data) {
// Replace with your CRM API call
// Example: Salesforce REST API, HubSpot API, etc.
console.log(`Updating CRM for ${email}:`, data);
}
async function sendWelcomeEmail(email, documentName) {
// Replace with your email service
// Example: SendGrid, AWS SES, Postmark
console.log(`Sending welcome email to ${email}`);
}
async function provisionPortalAccess(email) {
// Replace with your portal provisioning logic
console.log(`Provisioning portal access for ${email}`);
}
app.listen(PORT, () => {
console.log(`Webhook server running on port ${PORT}`);
});
Deploy this code:
- AWS Lambda: Use the Serverless Framework or AWS SAM. Add API Gateway to expose the endpoint.
- Azure Functions: Use the Azure Functions Core Tools.
- Heroku: Push to a Git repo and deploy.
- Your own server: Run with
node webhook-handler.jsbehind Nginx with SSL.
Critical: Your endpoint must use HTTPS. PandaDoc rejects HTTP URLs. Use Let's Encrypt for free SSL certificates or deploy to a platform that provides HTTPS by default.
Step 3: Configure Webhook Security
PandaDoc includes an x-pandadoc-signature header in every webhook request. This is an HMAC-SHA256 hash of the payload using your shared secret.
Verification logic (already in the code above):
const hash = crypto
.createHmac('sha256', PANDADOC_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
return hash === signature;
If the signature doesn't match, reject the request with a 401 status. This prevents attackers from sending fake webhook payloads to your endpoint.
Additional security measures:
- Whitelist PandaDoc's IP addresses in your firewall (contact PandaDoc support for the current list).
- Rate-limit the endpoint to 100 requests per minute.
- Log all webhook attempts (successful and failed) for audit purposes.
Step 4: Handle Webhook Payload
PandaDoc sends a JSON payload. Here's a sample document_completed event:
{
"event": "document_completed",
"data": {
"id": "AbCdEfGh123456",
"name": "Engagement Letter - Smith & Associates",
"status": "document.completed",
"date_created": "2025-01-15T10:30:00Z",
"date_completed": "2025-01-15T14:22:00Z",
"recipients": [
{
"email": "john.smith@smithassociates.com",
"first_name": "John",
"last_name": "Smith",
"has_completed": true
}
],
"metadata": {
"client_id": "12345",
"matter_type": "Tax Preparation"
}
}
}
Key fields to extract:
data.id: PandaDoc document ID (store this in your CRM for reference).data.name: Document title.data.recipients[0].email: Signer's email (use this to look up the contact in your CRM).data.metadata: Custom fields you added when creating the document. Use these to pass client ID, matter type, or other identifiers.
Handling multiple recipients:
If your engagement letter requires two signatures (e.g., managing partner and client), loop through data.recipients and check has_completed for each. Only proceed when all recipients have has_completed: true.
Step 5: Test the Integration
Test 1: Send a Test Webhook from PandaDoc
- In PandaDoc, go to Settings > Integrations > Webhooks.
- Click the three dots next to your webhook and select Send Test Event.
- Choose
document_completed. - Check your endpoint logs. You should see the test payload arrive.
Test 2: Complete a Real Document
- Create a new document in PandaDoc using a test template.
- Send it to your own email address.
- Open the email and sign the document.
- Within 30 seconds, check your endpoint logs. You should see the
document_completedevent. - Verify that your CRM updated correctly and the welcome email sent.
Test 3: Simulate a Signature Mismatch
- Modify your endpoint code to use a wrong secret.
- Send another test webhook from PandaDoc.
- Confirm your endpoint rejects it with a 401 status.
- Restore the correct secret.
Test 4: Check PandaDoc's Webhook Logs
- In PandaDoc, go to Settings > Integrations > Webhooks.
- Click your webhook name.
- View the Recent Deliveries tab.
- Confirm all deliveries show a 200 status. If you see 4xx or 5xx errors, click the delivery to see the response body and debug.
Troubleshooting Common Issues
Webhook not firing:
Check that you selected the correct event (document_completed, not document_state_changed). Verify your PandaDoc plan includes webhooks.
401 Unauthorized errors:
Your signature verification is failing. Print the expected hash and the received signature to compare. Ensure you're hashing the raw request body, not a parsed object.
Duplicate events:
PandaDoc may retry webhooks if your endpoint doesn't respond within 10 seconds. Make your endpoint idempotent: check if the document ID already exists in your CRM before updating.
Webhook delays:
PandaDoc typically delivers webhooks within 5-10 seconds. If you see delays over 1 minute, check PandaDoc's status page or contact support.
Next Steps
Once your webhook is stable, extend it:
- Add a
document_viewedevent to log when clients open the engagement letter (useful for follow-up). - Store the signed PDF in your document management system (use PandaDoc's API to download the file).
- Trigger a Slack notification to the engagement team when a high-value client signs.
- Create a dashboard that shows signing velocity (time from send to completion).
PandaDoc webhooks turn document signing from a manual checkpoint into an automated trigger. Build this once, and every signed engagement letter becomes the starting gun for your onboarding process.
Related Resources
E-Signature Webhook Setup Guide (Adobe Sign)
Same for Adobe Sign.
E-Signature Webhook Setup Guide (DocuSign)
Configuring DocuSign completion webhook to trigger n8n.
Onboarding Process Mapping Worksheet
Step-by-step template to map current onboarding steps, owners, and automation candidates.
The full system, end to end.
Looking to build your AI workforce? Get the comprehensive guide for professional services - the 12 plays, the frameworks, and the field-tested playbooks.
Buy on Amazon
Reviewed by Revenue Institute
This guide is actively maintained and reviewed by the implementation experts at Revenue Institute. As the creators of The AI Workforce Playbook, we test and deploy these exact frameworks for professional services firms scaling without new headcount.
Get the Book
Need help turning this guide into reality?
Revenue Institute builds and implements the AI workforce for professional services firms.
Work with Revenue Institute