Sales Operations
Workflow patterns for sales teams and revenue operations
Sales Operations Workflows
Automate deal progression, contract generation, lead routing, and pipeline management across your CRM and sales tools.
Why Automate Sales Operations?
Sales ops teams face unique challenges:
- Manual handoffs between sales stages slow deal velocity
- Contract delays while waiting for legal and document preparation
- Lead routing inefficiencies causing uneven rep workloads
- CRM data decay as reps forget to update records
- Pipeline visibility gaps requiring manual report generation
Workflow automation solves these by:
- Automating stage transitions and handoffs
- Generating contracts instantly when deals are ready
- Routing leads based on rules and rep capacity
- Keeping CRM data current automatically
- Providing real-time pipeline visibility
Common Workflow Patterns
Deal-to-Contract Automation
Trigger: Deal reaches contract stage Actions: Create contract from template, send for signature
Automatically generate and send contracts when deals reach the right stage, eliminating manual document creation.
{
"name": "Deal → Contract",
"trigger": {
"type": "webhook",
"provider": "hubspot",
"events": ["deal.propertyChange"],
"filter": {
"propertyName": { "$eq": "dealstage" },
"propertyValue": { "$eq": "contractsent" }
}
},
"steps": [
{
"id": "get-deal",
"type": "action",
"config": {
"connector": "hubspot",
"action": "getDeal",
"dealId": "{{input.objectId}}",
"associations": ["contacts", "companies"]
}
},
{
"id": "get-contact",
"type": "action",
"config": {
"connector": "hubspot",
"action": "getContact",
"contactId": "{{steps.get-deal.output.associations.contacts.results.[0].id}}"
}
},
{
"id": "get-company",
"type": "action",
"config": {
"connector": "hubspot",
"action": "getCompany",
"companyId": "{{steps.get-deal.output.associations.companies.results.[0].id}}"
}
},
{
"id": "create-contract",
"type": "action",
"config": {
"connector": "pandadoc",
"action": "createDocument",
"templateId": "CONTRACT_TEMPLATE_ID",
"name": "Contract - {{steps.get-deal.output.properties.dealname}}",
"recipients": [{
"email": "{{steps.get-contact.output.properties.email}}",
"first_name": "{{steps.get-contact.output.properties.firstname}}",
"last_name": "{{steps.get-contact.output.properties.lastname}}",
"role": "Signer"
}],
"tokens": [
{ "name": "deal_name", "value": "{{steps.get-deal.output.properties.dealname}}" },
{ "name": "deal_amount", "value": "{{steps.get-deal.output.properties.amount}}" },
{ "name": "company_name", "value": "{{steps.get-company.output.properties.name}}" }
]
}
},
{
"id": "send-contract",
"type": "action",
"config": {
"connector": "pandadoc",
"action": "sendDocument",
"documentId": "{{steps.create-contract.output.id}}",
"message": "Please review and sign your contract."
}
},
{
"id": "update-deal",
"type": "action",
"config": {
"connector": "hubspot",
"action": "updateDeal",
"dealId": "{{input.objectId}}",
"properties": {
"contract_url": "https://app.pandadoc.com/documents/{{steps.create-contract.output.id}}",
"contract_status": "Sent"
}
}
},
{
"id": "notify-sales",
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "#sales-contracts",
"text": "Contract sent for {{steps.get-deal.output.properties.dealname}} (${{steps.get-deal.output.properties.amount}}) to {{steps.get-contact.output.properties.email}}"
}
}
]
}Benefits:
- Contract sent within seconds of stage change
- No manual document assembly
- Deal always has contract link for tracking
- Team visibility into contract status
Quote Generation
Trigger: API call from CRM or form Actions: Calculate pricing, generate PDF, attach to deal
Automatically generate quotes with correct pricing and terms.
{
"name": "Generate Quote",
"trigger": {
"type": "api"
},
"steps": [
{
"id": "get-pricing",
"type": "action",
"config": {
"connector": "stripe",
"action": "getPrice",
"priceId": "{{input.price_id}}"
}
},
{
"id": "calculate-quote",
"type": "transform",
"config": {
"operation": "map",
"data": {
"unit_price": "{{steps.get-pricing.output.unit_amount | divided_by: 100}}",
"quantity": "{{input.quantity}}",
"subtotal": "{{steps.get-pricing.output.unit_amount | divided_by: 100 | multiply: input.quantity}}",
"discount": "{{#if (gt input.quantity 10)}}{{steps.get-pricing.output.unit_amount | divided_by: 100 | multiply: input.quantity | multiply: 0.1}}{{else}}0{{/if}}",
"total": "{{#if (gt input.quantity 10)}}{{steps.get-pricing.output.unit_amount | divided_by: 100 | multiply: input.quantity | multiply: 0.9}}{{else}}{{steps.get-pricing.output.unit_amount | divided_by: 100 | multiply: input.quantity}}{{/if}}"
}
}
},
{
"id": "create-quote-doc",
"type": "action",
"config": {
"connector": "pandadoc",
"action": "createDocument",
"templateId": "QUOTE_TEMPLATE_ID",
"name": "Quote - {{input.company_name}} - {{now | date: '%Y-%m-%d'}}",
"recipients": [{
"email": "{{input.contact_email}}",
"first_name": "{{input.contact_first_name}}",
"last_name": "{{input.contact_last_name}}"
}],
"tokens": [
{ "name": "company_name", "value": "{{input.company_name}}" },
{ "name": "product_name", "value": "{{steps.get-pricing.output.product.name}}" },
{ "name": "unit_price", "value": "{{steps.calculate-quote.output.unit_price}}" },
{ "name": "quantity", "value": "{{input.quantity}}" },
{ "name": "discount", "value": "{{steps.calculate-quote.output.discount}}" },
{ "name": "total", "value": "{{steps.calculate-quote.output.total}}" },
{ "name": "valid_until", "value": "{{now | dateAdd: 30, 'days' | date: '%B %d, %Y'}}" }
]
}
},
{
"id": "update-deal",
"type": "action",
"config": {
"connector": "hubspot",
"action": "updateDeal",
"dealId": "{{input.deal_id}}",
"properties": {
"quote_url": "https://app.pandadoc.com/documents/{{steps.create-quote-doc.output.id}}",
"amount": "{{steps.calculate-quote.output.total}}"
}
}
}
]
}Benefits:
- Accurate pricing every time
- Volume discounts applied automatically
- Quote linked to CRM deal
- Consistent professional documents
Lead Routing
Trigger: New lead created in CRM Actions: Enrich data, score lead, assign to rep, notify
Automatically route leads to the right sales rep based on territory, product interest, or round-robin.
{
"name": "Lead Router",
"trigger": {
"type": "webhook",
"provider": "hubspot",
"events": ["contact.creation"]
},
"steps": [
{
"id": "get-contact",
"type": "action",
"config": {
"connector": "hubspot",
"action": "getContact",
"contactId": "{{input.objectId}}",
"properties": ["email", "company", "country", "jobtitle", "hs_lead_status"]
}
},
{
"id": "determine-territory",
"type": "transform",
"config": {
"operation": "map",
"data": {
"region": "{{#if (or (eq steps.get-contact.output.properties.country 'United States') (eq steps.get-contact.output.properties.country 'Canada'))}}NA{{else if (or (eq steps.get-contact.output.properties.country 'United Kingdom') (eq steps.get-contact.output.properties.country 'Germany'))}}EMEA{{else}}APAC{{/if}}"
}
}
},
{
"id": "calculate-lead-score",
"type": "transform",
"config": {
"operation": "map",
"data": {
"score": "{{0 | plus: (if (contains steps.get-contact.output.properties.jobtitle 'VP') 30 else 0) | plus: (if (contains steps.get-contact.output.properties.jobtitle 'Director') 20 else 0) | plus: (if (contains steps.get-contact.output.properties.jobtitle 'Manager') 10 else 0) | plus: (if steps.get-contact.output.properties.company 15 else 0)}}"
}
}
},
{
"id": "assign-owner",
"type": "transform",
"config": {
"operation": "map",
"data": {
"ownerId": "{{#if (and (eq steps.determine-territory.output.region 'NA') (gt steps.calculate-lead-score.output.score 40))}}NA_ENTERPRISE_REP_ID{{else if (eq steps.determine-territory.output.region 'NA')}}NA_SMB_REP_ID{{else if (eq steps.determine-territory.output.region 'EMEA')}}EMEA_REP_ID{{else}}APAC_REP_ID{{/if}}",
"ownerEmail": "{{#if (eq steps.determine-territory.output.region 'NA')}}sales-na@company.com{{else if (eq steps.determine-territory.output.region 'EMEA')}}sales-emea@company.com{{else}}sales-apac@company.com{{/if}}"
}
}
},
{
"id": "update-contact-owner",
"type": "action",
"config": {
"connector": "hubspot",
"action": "updateContact",
"contactId": "{{input.objectId}}",
"properties": {
"hubspot_owner_id": "{{steps.assign-owner.output.ownerId}}",
"hs_lead_status": "NEW",
"lead_score": "{{steps.calculate-lead-score.output.score}}",
"sales_region": "{{steps.determine-territory.output.region}}"
}
}
},
{
"id": "notify-rep",
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "#sales-leads",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "New Lead Assigned" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Name:*\n{{steps.get-contact.output.properties.firstname}} {{steps.get-contact.output.properties.lastname}}" },
{ "type": "mrkdwn", "text": "*Company:*\n{{steps.get-contact.output.properties.company}}" },
{ "type": "mrkdwn", "text": "*Title:*\n{{steps.get-contact.output.properties.jobtitle}}" },
{ "type": "mrkdwn", "text": "*Score:*\n{{steps.calculate-lead-score.output.score}}" }
]
},
{
"type": "context",
"elements": [
{ "type": "mrkdwn", "text": "Region: {{steps.determine-territory.output.region}} | Assigned to: {{steps.assign-owner.output.ownerEmail}}" }
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": { "type": "plain_text", "text": "View in HubSpot" },
"url": "https://app.hubspot.com/contacts/YOUR_PORTAL/contact/{{input.objectId}}"
}
]
}
]
}
}
]
}Benefits:
- Instant lead assignment
- Consistent territory rules
- Lead scoring automation
- Rep notification with context
Pipeline Sync
Trigger: Scheduled hourly Actions: Sync deals between CRM and other systems
Keep multiple systems in sync with scheduled pipeline synchronization.
{
"name": "Pipeline Sync",
"trigger": {
"type": "schedule",
"cron": "0 * * * *"
},
"steps": [
{
"id": "get-updated-deals",
"type": "action",
"config": {
"connector": "hubspot",
"action": "searchDeals",
"filter": {
"lastModifiedDate": { "$gte": "{{now | dateAdd: -1, 'hours'}}" }
}
}
},
{
"id": "sync-to-salesforce",
"type": "loop",
"config": {
"items": "{{steps.get-updated-deals.output.results}}",
"step": {
"type": "action",
"config": {
"connector": "salesforce",
"action": "updateOpportunity",
"opportunityId": "{{item.properties.salesforce_opportunity_id}}",
"fields": {
"Amount": "{{item.properties.amount}}",
"StageName": "{{item.properties.dealstage}}",
"CloseDate": "{{item.properties.closedate}}"
}
}
}
}
},
{
"id": "log-sync",
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "#sales-ops",
"text": "Pipeline sync complete. {{steps.get-updated-deals.output.results.length}} deals synced."
}
}
]
}Win/Loss Analysis
Trigger: Deal closed (won or lost) Actions: Collect feedback, update analytics, notify team
Automatically capture win/loss data for analysis and reporting.
{
"name": "Win/Loss Capture",
"trigger": {
"type": "webhook",
"provider": "salesforce",
"events": ["opportunity.updated"],
"filter": {
"IsClosed": { "$eq": true }
}
},
"steps": [
{
"id": "get-opportunity",
"type": "action",
"config": {
"connector": "salesforce",
"action": "getOpportunity",
"opportunityId": "{{input.payload.Id}}"
}
},
{
"id": "get-owner",
"type": "action",
"config": {
"connector": "salesforce",
"action": "query",
"query": "SELECT Id, Name, Email FROM User WHERE Id = '{{steps.get-opportunity.output.OwnerId}}'"
}
},
{
"id": "request-feedback",
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "@{{steps.get-owner.output.records.[0].Email}}",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "{{#if steps.get-opportunity.output.IsWon}}Deal Won!{{else}}Deal Lost{{/if}}" }
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*{{steps.get-opportunity.output.Name}}*\nAmount: ${{steps.get-opportunity.output.Amount}}"
}
},
{
"type": "input",
"block_id": "win_loss_reason",
"label": { "type": "plain_text", "text": "{{#if steps.get-opportunity.output.IsWon}}What was the key factor in winning?{{else}}What was the primary reason for loss?{{/if}}" },
"element": {
"type": "static_select",
"action_id": "reason_select",
"options": [
{ "text": { "type": "plain_text", "text": "Price/Budget" }, "value": "price" },
{ "text": { "type": "plain_text", "text": "Product Fit" }, "value": "product" },
{ "text": { "type": "plain_text", "text": "Competitor" }, "value": "competitor" },
{ "text": { "type": "plain_text", "text": "Timing" }, "value": "timing" },
{ "text": { "type": "plain_text", "text": "Relationship" }, "value": "relationship" }
]
}
}
]
}
},
{
"id": "notify-leadership",
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "#sales-wins-losses",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "{{#if steps.get-opportunity.output.IsWon}}Won{{else}}Lost{{/if}}: {{steps.get-opportunity.output.Name}}" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Amount:*\n${{steps.get-opportunity.output.Amount}}" },
{ "type": "mrkdwn", "text": "*Owner:*\n{{steps.get-owner.output.records.[0].Name}}" },
{ "type": "mrkdwn", "text": "*Stage:*\n{{steps.get-opportunity.output.StageName}}" },
{ "type": "mrkdwn", "text": "*Type:*\n{{steps.get-opportunity.output.Type}}" }
]
}
]
}
}
]
}Account Executive Handoff
Trigger: Lead qualified (MQL → SQL) Actions: Create opportunity, assign AE, schedule meeting
Automate the handoff from SDR to Account Executive.
{
"name": "SDR → AE Handoff",
"trigger": {
"type": "webhook",
"provider": "hubspot",
"events": ["contact.propertyChange"],
"filter": {
"propertyName": { "$eq": "lifecyclestage" },
"propertyValue": { "$eq": "salesqualifiedlead" }
}
},
"steps": [
{
"id": "get-contact",
"type": "action",
"config": {
"connector": "hubspot",
"action": "getContact",
"contactId": "{{input.objectId}}",
"associations": ["companies"]
}
},
{
"id": "determine-ae",
"type": "transform",
"config": {
"operation": "map",
"data": {
"aeId": "AE_OWNER_ID",
"aeEmail": "ae@company.com",
"aeSlackId": "U_AE_SLACK_ID"
}
}
},
{
"id": "create-deal",
"type": "action",
"config": {
"connector": "hubspot",
"action": "createDeal",
"properties": {
"dealname": "{{steps.get-contact.output.properties.company}} - New Opportunity",
"dealstage": "qualifiedtobuy",
"hubspot_owner_id": "{{steps.determine-ae.output.aeId}}",
"pipeline": "default"
},
"associations": [{
"to": "{{input.objectId}}",
"type": "contact"
}]
}
},
{
"id": "notify-ae",
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "@{{steps.determine-ae.output.aeSlackId}}",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "New SQL Handoff" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Contact:*\n{{steps.get-contact.output.properties.firstname}} {{steps.get-contact.output.properties.lastname}}" },
{ "type": "mrkdwn", "text": "*Company:*\n{{steps.get-contact.output.properties.company}}" },
{ "type": "mrkdwn", "text": "*Title:*\n{{steps.get-contact.output.properties.jobtitle}}" },
{ "type": "mrkdwn", "text": "*Email:*\n{{steps.get-contact.output.properties.email}}" }
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": { "type": "plain_text", "text": "View Deal" },
"url": "https://app.hubspot.com/contacts/YOUR_PORTAL/deal/{{steps.create-deal.output.id}}"
},
{
"type": "button",
"text": { "type": "plain_text", "text": "Schedule Meeting" },
"url": "https://meetings.hubspot.com/ae-calendar"
}
]
}
]
}
},
{
"id": "send-intro-email",
"type": "email",
"config": {
"action": "send",
"provider": "gmail",
"to": "{{steps.get-contact.output.properties.email}}",
"from": "{{steps.determine-ae.output.aeEmail}}",
"subject": "Let's schedule a call - {{steps.get-contact.output.properties.company}}",
"body": {
"html": "<p>Hi {{steps.get-contact.output.properties.firstname}},</p><p>I'm your dedicated account executive at Company. I'd love to learn more about your needs and show you how we can help.</p><p>Would you have 30 minutes this week for a quick call?</p><p><a href='https://meetings.hubspot.com/ae-calendar'>Schedule a time that works for you</a></p>"
}
}
}
]
}Key Integrations
| Integration | Use Cases |
|---|---|
| Salesforce | CRM, opportunities, accounts, contacts |
| HubSpot | CRM, deals, contacts, companies |
| PandaDoc | Contracts, quotes, proposals |
| Slack | Notifications, approvals, team alerts |
| Stripe | Pricing, quotes, subscriptions |
| Outreach, follow-ups, introductions |
Best Practices
1. Stage-Based Triggers
Use property change events instead of polling:
{
"trigger": {
"type": "webhook",
"provider": "hubspot",
"events": ["deal.propertyChange"],
"filter": {
"propertyName": { "$eq": "dealstage" }
}
}
}2. Owner Notifications
Always notify the record owner:
{
"id": "notify-owner",
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "@{{steps.get-owner.output.slack_id}}"
}
}3. Link Back to CRM
Include CRM links in all notifications:
{
"type": "button",
"text": { "type": "plain_text", "text": "View in CRM" },
"url": "https://app.hubspot.com/contacts/PORTAL/deal/{{dealId}}"
}4. Idempotency for Contracts
Prevent duplicate contracts:
{
"metadata": {
"hubspot_deal_id": "{{input.objectId}}",
"created_at": "{{now}}"
}
}Getting Started
- Deal Sync Tutorial - Start with contract automation
- HubSpot Integration Guide - Set up your CRM connection
- PandaDoc Integration Guide - Connect document generation
- Slack Block Reference - Learn notification patterns