instantly-webhooks-events
SKILL.md
Instantly Webhooks & Events
Overview
Handle Instantly webhooks for real-time email outreach event notifications. Instantly fires webhooks when emails are sent, opened, replied to, bounced, or when leads change status.
Prerequisites
- Instantly account with API access enabled
- Instantly API key stored in
INSTANTLY_API_KEYenvironment variable - HTTPS endpoint for receiving webhook deliveries
- Active email campaigns configured in Instantly
Webhook Event Types
| Event | Trigger | Payload |
|---|---|---|
email.sent |
Email delivered | Lead email, campaign ID, step |
email.opened |
Recipient opens email | Lead email, open count, timestamp |
email.replied |
Recipient replies | Lead email, reply text, sentiment |
email.bounced |
Email bounced | Lead email, bounce type, reason |
email.unsubscribed |
Recipient unsubscribes | Lead email, campaign |
lead.interested |
Lead marked interested | Lead data, campaign context |
lead.meeting_booked |
Meeting scheduled | Lead data, calendar details |
Instructions
Step 1: Configure Webhook Endpoint
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhooks/instantly", async (req, res) => {
const apiKey = req.headers["x-api-key"] as string;
if (apiKey !== process.env.INSTANTLY_WEBHOOK_SECRET) {
return res.status(401).json({ error: "Unauthorized" }); # HTTP 401 Unauthorized
}
const { event_type, data, timestamp } = req.body;
res.status(200).json({ received: true }); # HTTP 200 OK
await handleInstantlyEvent(event_type, data);
});
Step 2: Route and Process Events
async function handleInstantlyEvent(eventType: string, data: any) {
switch (eventType) {
case "email.replied":
await handleReply(data);
break;
case "email.opened":
await handleOpen(data);
break;
case "email.bounced":
await handleBounce(data);
break;
case "lead.interested":
await handleInterestedLead(data);
break;
case "lead.meeting_booked":
await handleMeetingBooked(data);
break;
}
}
async function handleReply(data: any) {
const { lead_email, campaign_id, reply_text, reply_sentiment } = data;
console.log(`Reply from ${lead_email} (sentiment: ${reply_sentiment})`);
// Sync to CRM
await crmClient.updateLead(lead_email, {
status: reply_sentiment === "positive" ? "interested" : "replied",
lastActivity: new Date(),
lastReply: reply_text,
});
// Notify sales team for positive replies
if (reply_sentiment === "positive") {
await slackNotify("#sales-leads", {
text: `Positive reply from ${lead_email}!\nCampaign: ${campaign_id}`,
});
}
}
async function handleBounce(data: any) {
const { lead_email, bounce_type, reason } = data;
// Remove hard bounces from all campaigns
if (bounce_type === "hard") {
await fetch("https://api.instantly.ai/api/v1/lead/delete", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.INSTANTLY_API_KEY}`,
},
body: JSON.stringify({
email: lead_email,
delete_from_all_campaigns: true,
}),
});
}
}
Step 3: Register Webhook via API
set -euo pipefail
curl -X POST https://api.instantly.ai/api/v1/webhooks \
-H "Authorization: Bearer $INSTANTLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://api.yourapp.com/webhooks/instantly",
"event_types": ["email.replied", "email.bounced", "lead.interested"],
"secret": "your-webhook-secret"
}'
Step 4: Track Campaign Analytics
async function handleOpen(data: any) {
const { lead_email, campaign_id, open_count } = data;
await analyticsDb.trackEvent({
event: "email_opened",
campaignId: campaign_id,
leadEmail: lead_email,
openCount: open_count,
timestamp: new Date(),
});
}
async function handleMeetingBooked(data: any) {
const { lead_email, meeting_time, calendar_link } = data;
await crmClient.createDeal({
contactEmail: lead_email,
stage: "meeting_scheduled",
meetingTime: meeting_time,
});
}
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Missing events | Webhook not registered | Verify webhook URL in Instantly dashboard |
| Duplicate replies | Retry delivery | Deduplicate by lead_email + timestamp |
| Invalid API key | Key expired | Regenerate in Instantly settings |
| High bounce rate | Bad lead list | Clean list with email verification service |
Examples
Campaign Performance Dashboard
async function getCampaignStats(campaignId: string) {
const response = await fetch(
`https://api.instantly.ai/api/v1/analytics/campaign?campaign_id=${campaignId}`,
{ headers: { "Authorization": `Bearer ${process.env.INSTANTLY_API_KEY}` } }
);
return response.json();
}
Resources
Next Steps
For deployment setup, see instantly-deploy-integration.
Output
- Configuration files or code changes applied to the project
- Validation report confirming correct implementation
- Summary of changes made and their rationale
Weekly Installs
14
Repository
jeremylongshore…s-skillsGitHub Stars
1.6K
First Seen
Feb 18, 2026
Security Audits
Installed on
mcpjam14
claude-code14
replit14
junie14
windsurf14
zencoder14