Free for 30 days on Scale.Start free
Post-call CRM update and follow-up agent
Every step in the template

Post-call CRM update and follow-up agent

A workspace where every sales call from your recording tool flows into the CRM as a meeting note with contact + deal + next steps + stage change, lands a draft follow-up email for the rep to send, and shows up as a Calls row in Dock for the manager.

Outcome

A workspace where every sales call from your recording tool flows into the CRM as a meeting note with contact + deal + next steps + stage change, lands a draft follow-up email for the rep to send, and shows up as a Calls row in Dock for the manager.

Time45 min setup, ongoing zero touch (webhook path) or ~30 sec per call (manual paste)DifficultyintermediateForSales teams at $5M-$50M revenue companies using Fireflies / Gong / Zoom AI plus HubSpot / Salesforce / Pipedrive.
How this works

Open it, hand it to your agent, walk the steps.

Paste this to your agent (Claude / Cursor / Codex)
You are the agent running on the "Post-call CRM update and follow-up agent" template workspace, connected via MCP at your-org/post-call-crm-update-agent.

Your job: for every completed call (Fireflies webhook or pasted transcript), extract the call data via Claude, create a meeting note in the CRM tied to contact + deal, write a Calls row, append to Activity log, draft a follow-up email. Never send the follow-up without explicit opt-in. Never edit deal Amount or Owner.

User-loop protocol:
- You propose. The rep decides. Never send the follow-up email unless AUTO_SEND_EMAIL=true is set. Never edit deal Amount, Owner, or contact identity in the CRM.
- Webhook path (primary): when the Fireflies webhook fires, fetch the full transcript via Fireflies GraphQL, run extract_call_data() via Claude, look up contact by email + deal by association, create CRM meeting note, write Calls row, append to Activity log doc.
- Manual paste fallback: if a rep runs post_call_update.py with a transcript file, run the same downstream flow.
- Stage change: if Claude extracted deal_stage_update, look up the stage_id in STAGE_NAME_TO_ID and PATCH the deal. If the stage is not in the dict, log to Status (don't error, don't guess).
- Follow-up email: always generate the 3-4 paragraph draft. If AUTO_SEND_EMAIL=true and contact_email is present, send via SMTP. Otherwise write to follow_up_draft.txt for the rep.
- End of every working session, write 1 paragraph to Status: calls processed, follow-ups drafted vs sent, contacts not found.

Don't touch:
- Contact identity (firstname, lastname, email). If the contact doesn't exist, log to Status and have the operator create them first.
- Deal Amount or Owner. Those are rep decisions.
- CRM meeting notes from prior runs. Never edit or delete a meeting note the agent (or the rep) already wrote.

First MCP tool calls:
1. list_surfaces(workspace_slug="post-call-crm-update-agent")
2. list_rows(workspace_slug="post-call-crm-update-agent", surface_slug="calls")
3. get_doc(workspace_slug="post-call-crm-update-agent", surface_slug="status")
The template · 5 steps

Top to bottom. Each step has tasks, pointers, gotchas.

Confirm CRM access + recording tool + AUTO_SEND policy

10 min

Three decisions up front: which CRM, which recording tool, and whether follow-up emails send automatically or draft for review. The default (AUTO_SEND_EMAIL=false) is right for most teams during the first week. Flip to true once the reps trust the email quality.

Tasks
  • Ask which CRM. HubSpot + Salesforce + Pipedrive paths documented; script defaults to HubSpot.
  • Ask which recording tool. Fireflies has the cleanest webhook story; Gong + Zoom AI require manual export or a polling job.
  • Generate CRM token. HubSpot Private App scopes: crm.objects.deals.read + write, crm.objects.contacts.read, crm.objects.meetings.write.
  • Generate Fireflies API key. Fireflies dashboard, Integrations, API.
  • Pick AUTO_SEND_EMAIL=false for week one; flip to true after quality check.
Gotchas
  • Data handling note. Transcripts go through the Anthropic API. Anthropic does not train on API data, but if your company has confidentiality policies, confirm with the operator before the first call.
  • Stage mapping. Claude extracts stage_update as a display name (Contract Sent). The script maps it to the internal CRM stage ID via STAGE_NAME_TO_ID. Populate that dict before going live or stage updates silently no-op.

Wire .env + the Python script

20 min

One script: post_call_update.py handles both webhook and manual paste. It reads a transcript, extracts structured data via Claude, looks up contact + deal in the CRM, creates a meeting note, writes a Calls row, drafts the follow-up. Same extraction code on both paths.

Tasks
  • Open Setup guide (doc) and copy post_call_update.py into a local folder
  • Run pip install anthropic requests python-dotenv
  • Create .env with DOCK_API_KEY, DOCK_WORKSPACE_SLUG, ANTHROPIC_API_KEY, HUBSPOT_ACCESS_TOKEN, FIREFLIES_API_KEY, AUTO_SEND_EMAIL=false, SMTP_HOST + SMTP_USER + SMTP_PASS (if sending), CLAUDE_MODEL=claude-sonnet-4-6
  • Populate STAGE_NAME_TO_ID with your CRM's stages. HubSpot: GET /crm/v3/pipelines/deals returns one entry per pipeline with stage IDs.
  • Generate a Dock API key at trydock.ai/settings/api
Gotchas
  • STAGE_NAME_TO_ID is the most common silent failure. Claude says 'Contract Sent', the dict doesn't have that key, the script logs and moves on. Walk through your pipeline stages and populate the dict end-to-end before the first call.
  • Multiple open deals per contact. Default: script uses the most recent. Override via DEAL_ID env var when the wrong deal gets updated.

Test with one real transcript (manual paste path)

20 min

Before wiring the webhook, run one real transcript through the manual path. This confirms extraction quality + CRM write + Dock write + email draft all work end-to-end. The reps see exactly what gets created in the CRM.

Tasks
  • Pick a real call from the last week. Export the transcript from Fireflies / Gong / Zoom AI as a .txt file.
  • Run python post_call_update.py path/to/transcript.txt
  • Walk through with a rep: does the meeting note in the CRM look right? Does the Calls row have the right contact + summary + next steps? Does follow_up_draft.txt sound like the rep?
  • If the email draft is off, edit the prompt in generate_followup_email() to add tone guidance + sender name + signature template.
Gotchas
  • Contact not found. The script looks up by email. If the prospect email wasn't in the transcript, pass it as a 2nd CLI argument: python post_call_update.py transcript.txt prospect@company.com.
  • Quality of extraction depends on transcript quality. Very short calls (under 5 min) often miss next steps. Have the rep eyeball the first 3-5 runs before trusting the automation.
Agent prompt for this step
Run a first call through the manual paste path. Read the transcript file passed in. Run extract_call_data() to get contact + summary + next steps + stage update + follow-up email. Look up contact in the CRM by email; if found, get the most recent open deal; create a meeting note tied to both. Write a Calls row in Dock. Append the call summary to Activity log. Save the follow-up to follow_up_draft.txt (don't send unless AUTO_SEND_EMAIL=true). Post a Status entry: call processed, follow-up status, any lookup failures.

Wire the Fireflies webhook (primary path)

15 min

Once manual paste works, switch to webhook so the workflow is zero-touch. CueAPI receives the Fireflies POST, the handler fetches the full transcript via Fireflies GraphQL, runs the same downstream flow. Reps stop running the script entirely.

Tasks
  • pip install cueapi cueapi-worker
  • cueapi login
  • cueapi create --name 'post-call-update' --transport webhook --payload '{"task": "post_call_update"}'
  • Copy the CueAPI webhook URL into Fireflies, Settings, Integrations, Webhooks, Add new
  • cueapi-worker start --task post_call_update --handler ./post_call_update.py
  • Update the if __name__ == '__main__' block in post_call_update.py to accept the Fireflies webhook payload, fetch the transcript via fetch_latest_fireflies_transcript(transcript_id), and run the same downstream flow.
Gotchas
  • Verify cueapi-worker flag syntax at docs.cueapi.ai before shipping.
  • Webhook duplicates. If Fireflies retries on a 5xx, the same transcript ID can arrive twice. The handler must dedupe by transcript ID before processing (the script ships with processed_transcripts.json).

Decide on AUTO_SEND_EMAIL after week one

5 min decision + ongoing

Default is false. After the first 5-10 calls, walk through the follow-up drafts with the reps. If quality is consistent, flip AUTO_SEND_EMAIL=true and the workflow becomes fully zero-touch (call ends, CRM updated, follow-up sent, rep gets a Slack ping with a copy).

Tasks
  • Audit follow_up_draft.txt for the first 5-10 calls. Confirm tone, sign-off, no hallucinated context.
  • Adjust the prompt in generate_followup_email() if needed (add sender name + signature template + tone guidance).
  • Flip AUTO_SEND_EMAIL=true in .env when confident.
  • Optional: keep AUTO_SEND_EMAIL=false but add a Slack ping with the draft, so the rep can review on mobile and tap-send.
Gotchas
  • Flipping AUTO_SEND_EMAIL too early. A weird follow-up sent automatically to a prospect creates a credibility problem. Keep false until quality is boring.
  • Edge case: contact_email empty. The script falls back to OVERRIDE_EMAIL_TO if set, otherwise writes a draft to disk. Never silently fails to send.
FAQ

Common questions on this template.

Do I need Fireflies, or can I use Gong / Zoom AI?
Any transcript source works. Fireflies has the cleanest webhook out (recommended). Gong requires admin access to the REST API plus a polling job to find new calls. Zoom AI exports transcripts manually from the Zoom portal. The Setup guide doc has all three paths.
What if the prospect's email is not in the transcript?
Two paths. Pass it as a 2nd CLI argument: python post_call_update.py transcript.txt prospect@company.com. Or set OVERRIDE_EMAIL_TO in .env as the fallback. Either way the contact lookup runs and the meeting note ties to the right CRM record.
Does this send follow-up emails automatically?
Only if AUTO_SEND_EMAIL=true is set in .env. Default is false: the agent generates the draft and writes it to follow_up_draft.txt for the rep to review and send. Flip the flag after the first week once you trust the email quality.
What happens if the deal stage Claude extracted isn't in our CRM?
The script logs the mismatch to Status and skips the stage update (rest of the flow continues). Open run_pipeline_report.py and add the missing display name + internal ID to STAGE_NAME_TO_ID. Run the MCP stage query if you need the IDs.
Can a manager review what got processed each day?
Yes. The Activity log doc surface has a running narrative log: one section per processed call with rep, contact, summary, next steps, and meeting note link. Managers open the doc and walk through the day's activity end-to-end.

Open this template as a workspace.

We mint a fresh copy in your org with the steps as table rows, the pointers as a separate table, and the brief as a doc. Bring your agents, start checking off boxes.