Recipes: sales & CRM
Three pipelines that turn CRM data into timely action: reply to leads first, walk into every meeting prepared, and never let a deal go quiet.
Speed-to-lead
The second a lead comes in, create the CRM contact, draft a personalized first-touch email, and drop it in the rep’s Slack to send — responding first wins the deal.
The shape:
lead (webhook)
├─ lead-contact (hubspot)
└─ lead-draft (claude-api) → notify-rep (slack)# jobs/sales/lead.yaml — your form POSTs { email, name, company, message } here
id: lead
name: Inbound lead
group: sales
type: webhook
hookId: inbound_lead_0123456789abcdef# jobs/sales/lead-contact.yaml
id: lead-contact
name: Create CRM contact
group: sales
type: hubspot
credential: hubspot
operation: updateContact
contactId: '{{ $parent.json.email }}'
idProperty: email
email: '{{ $parent.json.email }}'
firstname: '{{ $parent.json.name }}'
company: '{{ $parent.json.company }}'
schedule:
- { kind: afterParent, parent: lead, on: succeeded }# jobs/sales/draft.yaml
id: lead-draft
name: Draft first-touch
group: sales
type: claude-api
credential: anthropic
maxTokens: 400
system: You write short, warm, non-pushy B2B first-touch emails. Sign off as {{ $vars.repName }}.
prompt: |
Write a first-touch email to {{ $parent.json.name }} at {{ $parent.json.company }}.
They said: "{{ $parent.json.message }}". Keep it to 5 sentences and end with a soft call booking.
schedule:
- { kind: afterParent, parent: lead, on: succeeded }# jobs/sales/notify-rep.yaml
id: notify-rep
name: Notify rep
group: sales
type: slack
credential: slack_bot
channel: '{{ $vars.repSlackChannel }}'
message: |
:zap: New lead — draft ready to send:
{{ $parent.text }}
schedule:
- { kind: afterParent, parent: lead-draft, on: succeeded }Why not auto-send? A human sending the first reply protects your domain reputation and lets the rep add a personal line. Flip it to a
gmailsendMessageonce you trust the drafts.
Meeting-ready briefs
~30 minutes before each meeting, generate a quick prep — likely purpose, smart questions, what to have ready — and send it to you.
The shape:
upcoming-meeting (calendar-watch) → meeting-brief (claude-api) → brief-send (slack)A calendar-watch trigger fires as each event approaches (its pollSeconds must be
shorter than leadMinutes × 60).
# jobs/prep/upcoming-meeting.yaml
id: upcoming-meeting
name: Upcoming meeting
group: prep
type: calendar-watch
credential: google_sa
calendarId: '{{ $vars.calendarId }}'
leadMinutes: 30
pollSeconds: 300
schedule: []# jobs/prep/brief.yaml
id: meeting-brief
name: Meeting brief
group: prep
type: claude-api
credential: anthropic
maxTokens: 400
system: You are an executive assistant. Be concise and practical.
prompt: |
My next meeting: "{{ $parent.json.summary }}" at {{ $parent.json.start }} ({{ $parent.json.location }}).
Give me a 5-line prep: likely purpose, 3 smart questions to ask, and anything to have ready.
schedule:
- { kind: afterParent, parent: upcoming-meeting, on: succeeded }# jobs/prep/brief-send.yaml
id: brief-send
name: Send brief
group: prep
type: slack
credential: slack_bot
channel: '{{ $vars.mySlackChannel }}'
message: |
:calendar: Prep for *{{ $parent.json.summary }}*
{{ $parent.text }}
schedule:
- { kind: afterParent, parent: meeting-brief, on: succeeded }Enrich it. Insert a
hubspot/salesforcelookup between the trigger and the brief (search by the meeting title) so the brief includes the live CRM record.
Stale-deal nudger
Each morning, find open deals with no recent activity and draft a re-engagement nudge for each — pipeline hygiene without the manual combing. Shown with Salesforce; HubSpot and Pipedrive work the same via their search APIs.
The shape:
stale-deals (salesforce, daily) → stale-nudges (claude-api) → nudge-digest (slack)# jobs/sales/stale-deals.yaml
id: stale-deals
name: Stale deals
group: sales
type: salesforce
credential: salesforce
operation: query
soql: >
SELECT Id, Name, Amount, StageName, LastActivityDate FROM Opportunity
WHERE IsClosed = false AND (LastActivityDate < LAST_N_DAYS:7 OR LastActivityDate = null)
ORDER BY Amount DESC LIMIT 25
schedule:
- { kind: daily, time: '08:00' }# jobs/sales/nudges.yaml
id: stale-nudges
name: Draft nudges
group: sales
type: claude-api
credential: anthropic
maxTokens: 600
system: You are a sales coach. For each deal, write ONE short, specific re-engagement line.
prompt: |
These open deals have gone quiet. Draft a one-line nudge for each (name it):
{{ $parent.json.records }}
schedule:
- { kind: afterParent, parent: stale-deals, on: succeeded }# jobs/sales/nudge-digest.yaml
id: nudge-digest
name: Nudge digest
group: sales
type: slack
credential: slack_bot
channel: '{{ $vars.aeSlackChannel }}'
message: |
:wave: Deals worth a nudge today:
{{ $parent.text }}
schedule:
- { kind: afterParent, parent: stale-nudges, on: succeeded }