Guide

Zero‑Touch Client Onboarding: E‑Sign → Payment → Workspace → Welcome (45‑Minute Build)

Build a production‑ready, zero‑touch onboarding chain for solo agencies: signature → payment → Notion hub + Drive folder → human‑paced welcome, with idempotency, retries, and rollback so nothing double‑creates or leaks.

This is the exact, production‑tested build Jordan walks through on Headcount Zero. You’ll chain signature → payment → workspace provisioning → welcome comms with idempotency and rollback so nothing double‑creates and partial failures clean up automatically. Use this guide to configure your stack once, then let onboarding run while you sleep.

1) System overview & success criteria

  • Outcome: a signed contract becomes a paid client with a provisioned Notion hub, Google Drive folder, and a concise welcome email — typically within 30–60 minutes, zero human touch.
  • Orchestrator: Make or Zapier. Keep the flow linear with short, named routers for clarity.
  • Idempotency: the document_id from your e‑sign tool is the run’s unique key. You’ll log it first; if seen again, you stop.
  • Reliability contract:
  • Provision only after verified payment success.
  • Every asset you create must be traceable in a run log.
  • If payment later fails, compensate (archive/remove assets) and notify.
  • Success criteria to hold yourself to:
  • Duplicate‑safe (no double workspaces/charges)
  • Payment‑gated provisioning
  • Human‑paced comms (no fire hose)
  • Full audit trail in a single place

2) Prerequisites & one‑time setup

Tools you’ll need (pick equivalents if you prefer):

  • E‑sign: PandaDoc (or Dropbox Sign)
  • Payments: Stripe
  • Workspace: Notion
  • Files: Google Drive
  • Orchestrator: Make (or Zapier)
  • Email: Gmail/Google Workspace (or similar)

One‑time setup checklists:

  1. Notion — two databases
  • Clients (production data)
  • Properties: Name (title), Plan Type (select), Start Date (date), Status (select), Contract Link (url), Stripe Customer ID (text), Drive Folder (url)
  • Template: “Client Hub Template” with timeline, deliverables, comms log, resource library
  • Onboarding Runs (audit log)
  • Properties: Run ID (text), Document ID (text, unique), Client Name (text), Client Email (email), Document Name (text), Shared Contract Link (url), Status (select: Queued, Paid, Provisioned, Welcomed, Payment Failed, Error), Stripe Customer ID (text), Invoice/PI/Session ID (text), Payment Event (text), Notion Page ID (text), Drive Folder ID (text), Welcome Email Msg ID (text), Started At / Paid At / Provisioned At / Welcomed At (dates), Error Code (text), Error Message (rich text), Retries (number), Duration (number)
  1. Stripe — products & events
  • Create product(s) and prices that match your offers (e.g., “Automation Audit – Starter”, “Automation Audit – Pro”).
  • Decide per‑offer payment model:
  • Subscription/invoice: listen for invoice.payment_succeeded.
  • One‑off checkout/payment link: listen for payment_intent.succeeded or checkout.session.completed (depending on your flow).
  1. Google Drive — template folder
  • Build a single “Client Folder Template” with your subfolders/files.
  • Note: Drive can’t copy folders directly. You’ll create a new folder, then copy files into it.
  1. Email deliverability — sender auth
  • Send from a domain you control with SPF + DKIM configured and a basic DMARC policy (start with p=none, monitor, then move to quarantine).
  1. Secrets & connections
  • Connect PandaDoc/Dropbox Sign, Stripe, Notion, Drive, Gmail to your orchestrator. Store API keys in the platform vault, not in step bodies.

Naming conventions (speeds debugging):

  • Prefix all internal channels/folders with client shortname (e.g., acme‑audit‑apr‑2026).
  • In Notion Runs, set Status chips with color semantics: green=OK, yellow=retry, red=action.

3) Build step 1 — Trigger + idempotency

Trigger and dedupe pattern:

  1. Trigger: Document completed (PandaDoc) → webhook to Make/Zapier. Capture fields you’ll need: documentid, documentname, completedat, recipient email(s), sharedlink.
  2. Idempotency check (first module):
  • Search Notion → Onboarding Runs where Document ID == document_id.
  • If any record exists with Status in {Queued, Paid, Provisioned, Welcomed}: STOP. Log “Duplicate webhook ignored.”
  • If exists with Status = Payment Failed or Error: continue but set a Resume From step variable = “payments”.
  1. Create Run record (if new):
  • Insert row with Document ID, Client Name/Email, Document Name, Shared Contract Link, Status=Queued, Started At=now.

Tips:

  • Always write the Run ID (row/page ID) to context so later steps can update the same record.
  • Treat this module as your ‘commit point’: nothing else runs until the run row is written.

4) Build step 2 — Payments (gate everything on success)

Stripe sequence (branch by payment model):
A) Subscriptions / invoices

  • Find or create Customer (by email from e‑sign payload). Save customer.id to the Run.
  • Create Subscription for the right price.
  • Pause flow waiting for invoice.payment_succeeded.
  • On event receipt, verify state by fetching the latest invoice via API (don’t trust webhooks blindly). Capture hostedinvoiceurl. Update Run: Status=Paid, Paid At=now, invoice.id, payment event name.

B) One‑off checkout / payment link

  • Option 1: Generate a Payment Link ahead of time mapped from product/plan parsed out of document_name.
  • Option 2: Create an Invoice + invoice items, finalize, and let Stripe email it.
  • Wait for paymentintent.succeeded or checkout.session.completed (or invoice.paymentsucceeded if you used invoices). On receipt, fetch current truth from API, then update Run as above.

Product mapping:

  • Parse the e‑sign documentname to select the correct Stripe priceid (e.g., contains “Pro” → pricepro123). Keep a small lookup table in your orchestrator or a Notion “Prices” DB.

Guardrails:

  • Never provision on subscription.created or invoice.created.
  • If payment fails (e.g., invoice.payment_failed), set Status=Payment Failed, store the failure code/message, and branch to compensation logic (see Section 7).

5) Build step 3 — Provisioning (Notion + Drive)

After Status=Paid, provision assets.

A) Notion client hub

  1. Create Page in Clients DB using template_id of “Client Hub Template”. Set properties: Client Name, Plan Type, Start Date=today, Contract Link, Stripe Customer ID.
  2. Wait 2–3 seconds (template content applies asynchronously) or poll child blocks until >0.
  3. Update Run with Notion Page ID and set Status=Provisioned (temporary) if Drive is next.

B) Google Drive folder

  1. Create a new folder named “[Client] – [Plan] – [YYYY‑MM]”. Save folder.id.
  2. List files in your “Client Folder Template”. For each file, files.copy into the new folder (parents=[newfolderid]).
  3. Share the new folder with client email via permissions.create (writer or commenter). Add a 5–10s delay for permission propagation.
  4. Optional: lightweight permission test using a service account with similar rights; if fail, retry 2–3 times with 5s backoff, then flag Run as Warning and continue.

C) Finalize provisioning state

  • Update the Clients DB page with Drive Folder (url) and any internal relations.
  • Update Run: Drive Folder ID, Provisioned At=now.

Gotchas to avoid:

  • Notion: relations can be set; rollups are read‑only (computed). Don’t try to write rollups.
  • Drive: folders can’t be copied; you must copy files. Large templates need pacing to stay under API quotas.

6) Build step 4 — Welcome comms (timing matters)

Human‑paced sequence (feels personal, still automated):

  • T+0 min after signature: Short confirmation
  • “Contract received — setting up your workspace now. You’ll get access shortly.”
  • T+15 min after payment confirmation: Full welcome
  • Include 4 scannable sections with emoji headers:
  • Your Workspace → Notion link + 1‑sentence description
  • Your Files → Drive folder link
  • Your Invoice → hosted invoice/receipt link
  • Next Step → schedule kickoff link
  • Keep it under ~150 words. Plain‑text part included. Links use your primary domain where possible.
  • Next business day AM: “Getting Started” checklist
  • T+7 days: “Quick check‑in — have you accessed everything?”

Implementing in the flow:

  • Draft the welcome email with merge fields from your Run + Clients page.
  • Send from your authenticated domain. Log the email Message ID back to the Run.
  • Update Run: Status=Welcomed, Welcomed At=now. Duration = Welcomed At − Started At (mins).

7) Reliability: error handling, rollback, and retries

Design for things going wrong and recovering cleanly.

Per‑stage error handlers:

  • Payments: if failure event arrives after provisioning began, set Status=Payment Failed and run compensation.
  • Notion: on API error, retry once; if still failing, set Status=Error with code/message, notify yourself, and stop.
  • Drive: continue on non‑critical copy failures but flag Run; on share failure, retry with backoff before giving up.

Compensation (payment failed after partial provisioning):

  1. Update Run with failure code/message.
  2. Notion: archive the Client page (move to “Failed Onboardings” DB) — don’t hard delete for 30 days.
  3. Drive: remove client permissions from the folder; optionally move folder to an internal “Quarantine” root.
  4. Slack/Email yourself a concise alert with client email, failure reason, and direct links to the Run + Stripe customer.
  5. Send client a friendly “update payment method” email with a secure link.

Out‑of‑order webhooks (common with Stripe):

  • Treat webhooks as signals. After each, fetch current truth via API before mutating state.

Idempotent re‑runs:

  • If you reprocess the same document_id and the Run’s Status is Payment Failed, resume at payments; if Provisioned, skip to welcome; if Welcomed, stop. Keep this logic in a single router so behavior is predictable.

8) Monitoring, costs, and variants

Monitoring & proof:

  • Daily 9:00 AM job queries Onboarding Runs for any Status not in {Welcomed} in last 24h. Send a one‑line Slack summary with where each got stuck.
  • Add a simple dashboard view in Notion (group by Status, sorted by Started At). This becomes your audit trail for clients and receipts.

Costs & latency (sanity checks):

  • Make: ~15 operations/run is typical for this chain; costs are negligible at small volume.
  • Zapier: branching (Filters/Formatter/Paths) is cost‑efficient; expect single‑digit tasks/run for a lean build.
  • Manual baseline: 35+ minutes per client of admin time. Your automation should land in 30–60 minutes elapsed time end‑to‑end with zero human minutes.

Swap‑ins and variants:

  • E‑sign: Dropbox Sign events (all‑signed) work the same; just feed its signaturerequestid as the Document ID.
  • Orchestrator: Zapier in place of Make (use Storage or a DB step for the Run log if you don’t use Notion).
  • PM tools: add an optional “Kickoff Task” in your task system after provisioning.
  • Slack Connect: avoid auto‑invites; include instructions in the welcome email if clients want a shared channel.

Go‑live checklist:

  • Test duplicate webhook handling (send the same completion twice).
  • Force a payment failure after Notion create to verify compensation.
  • Click every link in the welcome email from a non‑admin account.
  • Screenshot your Run row as proof when you hand off to clients (“everything’s live — here are the timestamps”).