Why Build Custom Sales Workflows with the API?
The AutoReach UI provides a powerful workflow builder, but some teams need more. Custom API-built workflows let you chain operations with conditional logic, integrate with external data sources, trigger workflows from events in other systems, and build multi-step processes that go beyond what a UI can offer.
If you are a developer or have a developer on your team, the API opens up possibilities that standard UI-based workflows cannot match: real-time CRM syncing, custom scoring models, multi-platform orchestration, and event-driven prospecting.
Architecture of a Custom Workflow
The Basic Pattern
A custom API workflow follows this pattern:
- Trigger — Something initiates the workflow (schedule, webhook, manual)
- Source — Prospects are identified or received
- Process — Prospects move through stages (research, qualify, contact)
- Route — Conditional logic determines next steps
- Output — Results are delivered (CRM update, notification, email sent)
Example: Event-Driven Prospecting Pipeline
``
New signup on your website
→ Webhook triggers AutoReach API
→ Research the company (research_company)
→ Qualify the lead (qualify_lead)
→ If score > 70: Add to "High Priority" workflow
→ If score 40-70: Add to "Nurture" workflow
→ If score < 40: Log and skip
→ Sync result to CRM
→ Notify sales team via Slack
`
Building Blocks
Block 1: Prospect Sourcing
Pull prospects from multiple sources via API:
From a CSV or database: `javascript
// Read prospects from your database
const prospects = await db.query(
'SELECT * FROM signups WHERE created_at > NOW() - INTERVAL 24 HOURS'
);
// Add each to an AutoReach workflow
for (const prospect of prospects) {
await autoreach.post('/api/leads', {
workflowId: WORKFLOW_ID,
company: prospect.company_name,
website: prospect.website,
contactName: prospect.name,
contactEmail: prospect.email
});
}
`
From a webhook:
`javascript
// Express webhook handler
app.post('/webhooks/new-signup', async (req, res) => {
const { company, email, website } = req.body;
// Add to AutoReach
await autoreach.post('/api/leads', {
workflowId: WORKFLOW_ID,
company,
website,
contactEmail: email
});
res.status(200).send('OK');
});
`
From another API:
`javascript
// Pull from LinkedIn Sales Navigator export
const linkedinLeads = await linkedinApi.getExportedLeads();
const autoreachLeads = linkedinLeads.map(lead => ({
company: lead.companyName,
website: lead.companyWebsite,
contactName: lead.fullName,
contactEmail: lead.email,
contactTitle: lead.title
}));
await autoreach.post('/api/leads/bulk', {
workflowId: WORKFLOW_ID,
leads: autoreachLeads
});
`
Block 2: Conditional Routing
Use qualification scores to route leads to different workflows:
`javascript
async function routeLead(leadId) {
// Get lead with qualification data
const lead = await autoreach.get(\/api/leads/\${leadId}\);
if (lead.qualityScore >= 80) {
// High priority: fast-track to outreach
await autoreach.post(\
/api/leads/\${leadId}/move\, {
workflowId: HIGH_PRIORITY_WORKFLOW
});
await notifySlack(\High-priority lead: \${lead.company} (Score: \${lead.qualityScore})\);
} else if (lead.qualityScore >= 50) {
// Medium priority: standard workflow
await autoreach.post(\/api/leads/\${leadId}/move\, {
workflowId: STANDARD_WORKFLOW
});
} else {
// Low priority: nurture or skip
await autoreach.put(\/api/leads/\${leadId}\, {
status: 'nurture',
notes: 'Low qualification score - added to nurture track'
});
}
}
`
Block 3: CRM Synchronization
Keep your CRM in sync with AutoReach data:
`javascript
// Webhook handler for qualified leads
app.post('/webhooks/autoreach/lead-qualified', async (req, res) => {
const { leadId, company, contactEmail, qualityScore, closeValue } = req.body;
// Create or update in Salesforce
await salesforce.upsert('Lead', {
Email: contactEmail,
Company: company,
LeadScore__c: qualityScore,
EstimatedValue__c: closeValue,
LeadSource: 'AutoReach',
Status: qualityScore >= 70 ? 'Qualified' : 'Working'
});
res.status(200).send('OK');
});
`
Block 4: Multi-Step Sequences
Build complex sequences that span multiple tools:
`javascript
async function executeProspectingSequence(companyWebsite) {
// Step 1: Research the company
const research = await autoreach.post('/api/research', {
website: companyWebsite
});
// Step 2: Qualify based on research
const qualification = await autoreach.post('/api/qualify', {
researchData: research.data
});
// Step 3: Route based on qualification
if (qualification.score < 50) return { action: 'skipped', reason: 'Low score' };
// Step 4: Generate personalized email
const email = await autoreach.post('/api/draft-email', {
leadId: research.leadId,
tone: 'professional',
length: 'short'
});
// Step 5: Queue for sending during business hours
const scheduledTime = getNextBusinessHour(research.data.timezone);
await autoreach.post('/api/send-email', {
leadId: research.leadId,
emailDraft: email.data,
scheduledAt: scheduledTime
});
// Step 6: Log to CRM
await crm.createActivity({
type: 'outreach',
company: research.data.companyName,
scheduledAt: scheduledTime
});
return { action: 'contacted', scheduledAt: scheduledTime };
}
`
Webhook Integration Patterns
Pattern 1: Fire and Forget
Send the webhook event to AutoReach and do not wait for a result. Good for logging and non-critical updates.
Pattern 2: Request-Response
Send the webhook and wait for AutoReach to process and return a result. Good for real-time qualification or research.
Pattern 3: Event Chain
AutoReach receives a webhook, processes data, and sends its own webhook to the next service in the chain. Good for complex multi-service workflows.
Webhook Security
Always verify webhook signatures:
`javascript
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
`
Error Handling and Resilience
Retry Logic
API calls can fail for transient reasons. Implement retries:
`javascript
async function apiCallWithRetry(fn, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries) throw error;
if (error.status === 429) {
// Rate limited: wait the specified time
const waitTime = error.headers['retry-after'] * 1000;
await sleep(waitTime);
} else if (error.status >= 500) {
// Server error: exponential backoff
await sleep(Math.pow(2, attempt) * 1000);
} else {
// Client error: do not retry
throw error;
}
}
}
}
``
Dead Letter Queues
For critical workflows, implement a dead letter queue for failed operations:
- If an API call fails after all retries, write the failed request to a queue
- Alert your team about the failure
- Process the queue manually or with a separate retry job
- Log all failures for debugging
"In production API workflows, assume everything can fail. Build retry logic, dead letter queues, and alerting from day one. It is much easier than debugging a silent failure weeks later." — AutoReach Team
FAQ
Can I build workflows in any programming language?
Yes. The AutoReach API is language-agnostic. Any language that can make HTTP requests works. We provide code examples in JavaScript and Python, but Ruby, Go, Java, PHP, and others all work.
How do I test custom workflows without spending credits?
Use sandbox mode with a development API key. Sandbox returns realistic mock data without consuming credits or sending real emails.
Can I schedule custom workflows to run automatically?
Yes. Use cron jobs, scheduled tasks, or serverless functions (AWS Lambda, Google Cloud Functions) to trigger your workflow code on a schedule.
What is the maximum batch size for bulk operations?
The bulk lead import endpoint accepts up to 1,000 leads per request. For larger imports, batch your requests into chunks of 1,000.
Can I combine API workflows with UI workflows?
Absolutely. Leads created via API appear in the UI, and UI-created workflows can be managed via API. The two interfaces are complementary.
Getting Started with Custom Workflows
- Plan your workflow logic on paper first
- Set up a development environment with a sandbox API key
- Start with a simple two-step workflow (source + process)
- Add conditional routing once the basics work
- Implement error handling and retries
- Test thoroughly in sandbox mode
- Switch to a production API key when ready
- Monitor and iterate