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_KEY environment 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
GitHub Stars
1.6K
First Seen
Feb 18, 2026
Installed on
mcpjam14
claude-code14
replit14
junie14
windsurf14
zencoder14