Back to Play 5 Resources
Play 5: Client Onboarding

Play 5 Complete Implementation Guide

Full walkthrough: e-signature webhook, new/existing client paths, welcome email, folder creation.

Play 5 Complete Implementation Guide

Client onboarding automation separates firms that scale from firms that stall. This guide walks you through building a production-grade onboarding system that triggers the moment a client signs your engagement letter.

You'll configure e-signature webhooks

, route new versus returning clients, automate welcome sequences, and provision folder structures. No theory. Just the exact steps to deploy this week.

Prerequisites

Before you start, confirm you have:

  • Admin access to your e-signature platform (DocuSign, PandaDoc, or HelloSign)
  • API credentials for your CRM
    (Clio, Practice Panther, Salesforce, or HubSpot)
  • Webhook receiver endpoint (Make.com, Zapier, or custom server)
  • File storage admin rights (Google Drive, SharePoint, or Dropbox Business)
  • SMTP credentials or email automation tool (SendGrid, Mailgun, or Gmail API
    )

E-Signature Webhook
Configuration

DocuSign Setup

Step 1: Access Connect Settings

Log into DocuSign as an admin. Navigate to Settings > Connect > Add Configuration. Select "Custom" as the configuration type.

Step 2: Configure the Webhook

URL

Enter your webhook

receiver URL. For Make.com, this looks like: https://hook.us1.make.com/abc123xyz. For Zapier: https://hooks.zapier.com/hooks/catch/123456/abc123/.

Step 3: Select Trigger Events

Enable only these events:

  • Envelope Sent
  • Envelope Completed
  • Recipient Completed

Disable all others to reduce noise.

Step 4: Set Delivery Mode

Choose "Aggregate Messages" with a 5-minute interval. This batches multiple events and prevents webhook

flooding during high-volume periods.

Step 5: Configure Authentication

Under "Basic Authentication", generate a username and password. Store these in your webhook

receiver as environment variables. DocuSign will send these credentials in the Authorization header of every webhook
request.

Step 6: Enable Logging

Turn on "Log Sent Messages" for 30 days. This creates an audit trail you can reference when debugging failed deliveries.

Step 7: Test the Connection

Click "Test Connection". DocuSign sends a sample payload to your endpoint. Verify your receiver logs the incoming request with a 200 status code.

PandaDoc Setup

Step 1: Navigate to Webhooks

Go to Settings > Developers > Webhooks

> Create Webhook
.

Step 2: Enter Endpoint URL

Paste your webhook

receiver URL. PandaDoc supports HTTPS only.

Step 3: Select Events

Enable:

  • document.completed
  • document.sent

Step 4: Add Shared Secret

PandaDoc generates a shared secret automatically. Copy this value. Your webhook

receiver must validate the X-PandaDoc-Signature header against this secret using HMAC-SHA256.

Validation example (Python):

import hmac
import hashlib

def validate_pandadoc_webhook(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Step 5: Test Delivery

Send a test document to yourself. Complete it. Check your webhook

receiver logs for the incoming POST request.

HelloSign Setup

Step 1: Access API

Settings

Navigate to Settings > API

> Callbacks.

Step 2: Add Callback URL

Enter your webhook

endpoint. HelloSign calls this a "callback" instead of a webhook
.

Step 3: Generate API

Key

Under "API

Key", click "Reveal" and copy your key. Store this securely. HelloSign includes this in the event.event_hash field for validation.

Step 4: Enable Events

Select:

  • signature_request_sent
  • signature_request_signed
  • signature_request_all_signed

Step 5: Verify Event Hash

HelloSign sends an event_hash with each callback. Validate it by computing: HMAC-SHA256(event_time + event_type, api_key).

Validation example (Node.js):

const crypto = require('crypto');

function validateHelloSign(eventTime, eventType, eventHash, apiKey) {
  const data = eventTime + eventType;
  const expected = crypto
    .createHmac('sha256', apiKey)
    .update(data)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(eventHash)
  );
}

New Client Workflow

Step 1: Receive and Parse Webhook

Your webhook

receiver gets a POST request when a client completes signing. Extract these fields from the payload:

DocuSign:

  • envelopeId
  • recipients[0].email
  • recipients[0].name
  • status (should equal "completed")

PandaDoc:

  • data.id
  • data.recipients[0].email
  • data.recipients[0].first_name + data.recipients[0].last_name
  • data.status (should equal "document.completed")

HelloSign:

  • signature_request.signature_request_id
  • signature_request.signatures[0].signer_email_address
  • signature_request.signatures[0].signer_name
  • event.event_type (should equal "signature_request_all_signed")

Step 2: Check for Existing Client

Query your CRM

before creating a new record. Use email as the unique identifier.

Clio API

example:

curl -X GET "https://app.clio.com/api/v4/contacts.json?query=john.doe@example.com" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Salesforce SOQL example:

SELECT Id, Name, Email FROM Contact 
WHERE Email = 'john.doe@example.com' 
LIMIT 1

If the query returns a record, route to the existing client workflow. If empty, continue to Step 3.

Step 3: Create Client Record

Insert a new contact or matter in your CRM

.

Clio API

example:

curl -X POST "https://app.clio.com/api/v4/contacts.json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "name": "John Doe",
      "email_addresses": [{"name": "Work", "address": "john.doe@example.com"}],
      "type": "Company"
    }
  }'

Practice Panther API

example:

curl -X POST "https://api.practicepanther.com/v1/contacts" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "John Doe",
    "email": "john.doe@example.com",
    "contact_type": "client"
  }'

Store the returned client ID. You'll need it for folder creation and future API

calls.

Step 4: Send Welcome Email

Use a transactional email service for reliable delivery and tracking.

SendGrid API

example:

curl -X POST "https://api.sendgrid.com/v3/mail/send" \
  -H "Authorization: Bearer YOUR_SENDGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "personalizations": [{
      "to": [{"email": "john.doe@example.com", "name": "John Doe"}],
      "dynamic_template_data": {
        "client_name": "John",
        "firm_name": "Smith & Associates",
        "portal_url": "https://portal.smithlaw.com/login"
      }
    }],
    "from": {"email": "welcome@smithlaw.com", "name": "Smith & Associates"},
    "template_id": "d-abc123xyz"
  }'

Email Template Structure:

Subject: Your engagement with [FIRM_NAME] starts now

Body:

Hi [CLIENT_FIRST_NAME],

Your engagement letter is signed. Here's what happens next:

1. Your dedicated team lead will email you within 24 hours to schedule a kickoff call
2. You'll receive login credentials for our client portal at [PORTAL_URL]
3. We'll send a detailed project timeline by end of week

Access your client portal: [PORTAL_URL]

Questions? Reply to this email or call [PHONE_NUMBER].

[PARTNER_NAME]
[FIRM_NAME]

Step 5: Create Folder Structure

Provision a standardized folder hierarchy in your file storage system.

Google Drive API

example (Python):

from googleapiclient.discovery import build

def create_client_folders(client_name, parent_folder_id):
    service = build('drive', 'v3', credentials=creds)
    
    # Create root client folder
    root_folder = service.files().create(body={
        'name': client_name,
        'mimeType': 'application/vnd.google-apps.folder',
        'parents': [parent_folder_id]
    }).execute()
    
    # Create subfolders
    subfolders = [
        '01_Engagement_Letters',
        '02_Work_Product',
        '03_Client_Communications',
        '04_Invoices_and_Billing',
        '05_Source_Documents'
    ]
    
    for folder_name in subfolders:
        service.files().create(body={
            'name': folder_name,
            'mimeType': 'application/vnd.google-apps.folder',
            'parents': [root_folder['id']]
        }).execute()
    
    return root_folder['id']

SharePoint API

example (PowerShell):

$clientName = "John Doe"
$siteUrl = "https://yourfirm.sharepoint.com/sites/ClientMatters"

Connect-PnPOnline -Url $siteUrl -Interactive

$rootFolder = Add-PnPFolder -Name $clientName -Folder "Shared Documents"

$subfolders = @(
    "01_Engagement_Letters",
    "02_Work_Product",
    "03_Client_Communications",
    "04_Invoices_and_Billing",
    "05_Source_Documents"
)

foreach ($folder in $subfolders) {
    Add-PnPFolder -Name $folder -Folder "$($rootFolder.ServerRelativeUrl)"
}

Step 6: Move Signed Document

Download the completed engagement letter from your e-signature platform and upload it to the client's folder.

DocuSign document download:

curl -X GET "https://demo.docusign.net/restapi/v2.1/accounts/ACCOUNT_ID/envelopes/ENVELOPE_ID/documents/combined" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -o "engagement_letter.pdf"

Upload to Google Drive:

file_metadata = {
    'name': 'Engagement_Letter_Signed.pdf',
    'parents': [engagement_letters_folder_id]
}
media = MediaFileUpload('engagement_letter.pdf', mimetype='application/pdf')
service.files().create(body=file_metadata, media_body=media).execute()

Existing Client Workflow

Step 1: Receive Webhook

Parse the incoming webhook

payload exactly as in the new client workflow.

Step 2: Retrieve Client Record

Query your CRM

using the email address from the webhook
.

HubSpot API

example:

curl -X GET "https://api.hubapi.com/contacts/v1/contact/email/john.doe@example.com/profile" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

If no record exists, fall back to the new client workflow.

Step 3: Update Client Status

Mark the client as "Active" or "Re-engaged" in your CRM

.

Salesforce API

example:

curl -X PATCH "https://yourinstance.salesforce.com/services/data/v57.0/sobjects/Contact/CONTACT_ID" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "Status__c": "Active",
    "Last_Engagement_Date__c": "2024-01-15"
  }'

Step 4: Send Welcome Back Email

Use a different template that acknowledges the prior relationship.

Subject: Welcome back to [FIRM_NAME]

Body:

Hi [CLIENT_FIRST_NAME],

Great to work with you again. Your new engagement letter is signed and filed.

What's changed since we last worked together:

- New client portal with real-time project tracking: [PORTAL_URL]
- Expanded service offerings in [PRACTICE_AREA]
- Faster turnaround times (average 3 business days)

Your team lead will reach out within 24 hours to discuss your current needs.

Access your portal: [PORTAL_URL]

[PARTNER_NAME]
[FIRM_NAME]

Step 5: Create New Matter Folder

Add a new subfolder under the existing client's root folder. Use a naming convention that includes the matter number and date.

Folder name format: [MATTER_NUMBER]_[MATTER_NAME]_[YYYY-MM]

Example: 2024-003_Estate_Planning_2024-01

Google Drive example:

matter_folder = service.files().create(body={
    'name': '2024-003_Estate_Planning_2024-01',
    'mimeType': 'application/vnd.google-apps.folder',
    'parents': [existing_client_folder_id]
}).execute()

# Create standard subfolders within the matter folder
matter_subfolders = [
    '01_Engagement_Letters',
    '02_Work_Product',
    '03_Correspondence',
    '04_Source_Documents'
]

for folder_name in matter_subfolders:
    service.files().create(body={
        'name': folder_name,
        'mimeType': 'application/vnd.google-apps.folder',
        'parents': [matter_folder['id']]
    }).execute()

Error Handling and Monitoring

Webhook
Delivery Failures

E-signature platforms retry failed webhooks

3-5 times with exponential backoff. If your endpoint is down, you'll miss events.

Solution: Implement a dead letter queue. When your webhook

receiver fails to process an event, write it to a separate queue for manual review.

Make.com: Add an error handler route that writes failed scenarios to a Google Sheet.

Zapier: Enable "Error Notifications" in Zap settings. Failed runs email you with the full payload.

Custom server: Use a message queue like AWS SQS or RabbitMQ.

Duplicate Client Prevention

If your CRM

query fails but the client exists, you'll create a duplicate record.

Solution: Add a secondary check using phone number or company name. If email query returns empty but phone query returns a match, route to existing client workflow.

Folder Creation Conflicts

If two webhooks

fire simultaneously for the same client, you might create duplicate folders.

Solution: Implement idempotency. Before creating a folder, search for existing folders with the same name. If found, use that folder ID instead of creating a new one.

Google Drive search:

query = f"name='{client_name}' and mimeType='application/vnd.google-apps.folder' and '{parent_folder_id}' in parents"
results = service.files().list(q=query, fields='files(id, name)').execute()
if results.get('files'):
    return results['files'][0]['id']

Email Deliverability

Welcome emails might land in spam if your domain lacks proper authentication.

Solution: Configure SPF, DKIM, and DMARC records for your sending domain. Use a dedicated subdomain like mail.yourfirm.com for transactional emails.

SPF record example:

v=spf1 include:sendgrid.net ~all

DKIM: Your email provider generates this. Add the provided TXT record to your DNS.

DMARC record example:

v=DMARC1; p=quarantine; rua=mailto:dmarc@yourfirm.com
Revenue Institute

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.

Revenue Institute

Need help turning this guide into reality? Revenue Institute builds and implements the AI workforce for professional services firms.

RevenueInstitute.com