DEV Community

Viet Automation
Viet Automation

Posted on

Closed-Won to Kickoff in One Workflow: A Client Onboarding Handoff Automation in n8n (2026)

Closed-Won to Kickoff in One Workflow

Short answer: trigger on the CRM stage change to won, key everything on the deal id so a retried webhook can't create a second client, generate a handoff brief from the deal notes with one LLM call, create the client record, folder and task checklist, then put the welcome email and kickoff invite in a review queue instead of sending them blind. Track each step in a onboarding_runs table so a failure halfway resumes instead of starting over.

Why this keeps coming up

Automation communities keep asking the same two questions: what should go into the handoff when a deal closes, and should a small business build dashboards or automations first?

The recurring complaints: sales knows things delivery never hears, the welcome email goes out twice when the CRM retries, someone forgets to create the shared folder, and a half-failed run leaves a client in three systems but missing from the fourth.

What goes into the handoff

Step Output Idempotency key
1. Intake Deal id, company, contacts, value, notes deal_id
2. Handoff brief Goals, scope, promises sales made, risks, open questions deal_id:brief
3. Client record Row in your client table or project tool deal_id:client
4. Shared folder Drive/Notion page from a template deal_id:folder
5. Task checklist Kickoff, access requests, invoice, first deliverable deal_id:tasks
6. Welcome email + kickoff invite Draft for review, not auto-sent deal_id:welcome
7. Internal ping One Slack/Teams message with the brief deal_id:ping

Schema

CREATE TABLE onboarding_runs (
  deal_id TEXT PRIMARY KEY,
  status TEXT NOT NULL DEFAULT 'started',   -- started | done | failed
  steps_done TEXT[] NOT NULL DEFAULT '{}',
  brief JSONB,
  started_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

Claim the deal once:

INSERT INTO onboarding_runs (deal_id) VALUES ($1)
ON CONFLICT (deal_id) DO NOTHING
RETURNING deal_id;
Enter fullscreen mode Exit fullscreen mode

No row back means another run already owns this deal, so the workflow only resumes the steps missing from steps_done.

Mark a step done right after it succeeds:

UPDATE onboarding_runs
SET steps_done = array_append(steps_done, $2), updated_at = NOW()
WHERE deal_id = $1 AND NOT ($2 = ANY(steps_done));
Enter fullscreen mode Exit fullscreen mode

The handoff brief prompt (one call, structured output)

Ask the model for strict JSON with these fields: goals, in_scope, out_of_scope, promises_made, deadlines, stakeholders, risks, open_questions. Tell it to write "unknown" instead of guessing. The promises_made field is the one delivery teams thank you for.

Workflow outline (n8n)

  1. Webhook or CRM trigger filtered to stage = won.
  2. Postgres claims deal_id; an IF node routes new deals to the full path and existing ones to resume.
  3. LLM node writes the brief, stored in brief.
  4. Each creation step runs behind an IF that checks steps_done, then appends its step name.
  5. Welcome email and kickoff invite are saved as drafts for a human to approve.
  6. A daily schedule trigger lists runs stuck in started for more than 2 hours.

Dashboards first or automations first?

Automate the handoff first. It is the step where information is lost, and the onboarding_runs table becomes your first dashboard for free: deals won, onboarding started, stuck runs.

Where to run it

  • Self-host n8n plus Postgres on Railway or start on n8n Cloud.
  • In a visual builder, the same keys work in Make using a Data Store keyed by deal_id.

FAQ

What if the CRM sends "won" twice after someone reopens the deal? The deal_id claim blocks a second onboarding. If you want re-onboarding, key on deal_id plus the close date.
Should the welcome email ever auto-send? Only after you trust the template; even then, keep the deal_id:welcome step check in front of the send so retries can't double-send.
Where does the brief live? Store it in the run row and paste it into the client folder, so delivery reads it before kickoff.

If you'd rather build this in a visual builder, you can start free on Make.


Disclosure: Some links are affiliate links — I may earn a commission at no extra cost to you.

Top comments (0)