instantly-common-errors

快速诊断并修复 Instantly 集成中常见的认证失败、速率限制超限及网络超时等问题,通过日志分析、环境变量检查与配置调整等手段定位根因,提供可直接执行的验证和修复方案。

快捷安装

在终端运行此命令,即可一键安装该 Skill 到您的 Claude 中

npx skills add jeremylongshore/claude-code-plugins-plus-skills --skill "instantly-common-errors"

Instantly Common Errors

Overview

Diagnostic reference for Instantly API v2 errors. Covers HTTP status codes, campaign state errors, account health issues, lead operation failures, and webhook delivery problems.

Prerequisites

  • Completed instantly-install-auth setup
  • Access to Instantly dashboard for verification
  • API key with appropriate scopes

HTTP Status Codes

StatusMeaningCommon CauseFix
400Bad RequestMalformed JSON, invalid field valuesValidate request body against schema
401UnauthorizedInvalid, expired, or revoked API keyRegenerate key in Settings > Integrations
403ForbiddenAPI key missing required scopeCreate key with correct scope (e.g., campaigns:all)
404Not FoundInvalid campaign/lead/account IDVerify resource exists with a GET call first
422Unprocessable EntityBusiness logic violation (duplicate lead, invalid state)Check error body for details
429Too Many RequestsRate limit exceededImplement exponential backoff (see below)
500Internal Server ErrorInstantly server issueRetry with backoff; check status.instantly.ai

Campaign Errors

Campaign Won’t Activate (Stuck in Draft)

// Diagnosis: check campaign requirements
async function diagnoseCampaign(campaignId: string) {
  const campaign = await instantly<Campaign>(`/campaigns/${campaignId}`);

  const issues: string[] = [];

  // Check sequences
  if (!campaign.sequences?.length || !campaign.sequences[0]?.steps?.length) {
    issues.push("No email sequences — add at least one step with subject + body");
  }

  // Check schedule
  if (!campaign.campaign_schedule?.schedules?.length) {
    issues.push("No sending schedule — add schedule with timing and days");
  }

  // Check sending accounts
  const mappings = await instantly(`/account-campaign-mappings/${campaignId}`);
  if (!Array.isArray(mappings) || mappings.length === 0) {
    issues.push("No sending accounts assigned — add via PATCH /campaigns/{id} with email_list");
  }

  // Check for leads
  const leads = await instantly<Lead[]>("/leads/list", {
    method: "POST",
    body: JSON.stringify({ campaign: campaignId, limit: 1 }),
  });
  if (leads.length === 0) {
    issues.push("No leads — add leads via POST /leads");
  }

  if (issues.length === 0) {
    console.log("Campaign looks ready to activate");
  } else {
    console.log("Issues preventing activation:");
    issues.forEach((i) => console.log(`  - ${i}`));
  }
}

Campaign Status Codes

StatusLabelMeaning
0DraftNot yet activated
1ActiveCurrently sending
2PausedManually paused
3CompletedAll leads processed
4Running SubsequencesMain sequence done, subsequences active
-1Accounts UnhealthySending accounts have SMTP/IMAP errors
-2Bounce ProtectAuto-paused due to high bounce rate
-99SuspendedAccount-level suspension

Fix: Accounts Unhealthy (-1)

async function fixUnhealthyAccounts(campaignId: string) {
  // 1. Get accounts assigned to campaign
  const accounts = await instantly<Account[]>("/accounts?limit=100");

  // 2. Test vitals for each
  const vitals = await instantly("/accounts/test/vitals", {
    method: "POST",
    body: JSON.stringify({ accounts: accounts.map((a) => a.email) }),
  });

  // 3. Identify and fix broken accounts
  for (const v of vitals as any[]) {
    if (v.smtp_status !== "ok" || v.imap_status !== "ok") {
      console.log(`BROKEN: ${v.email} — SMTP=${v.smtp_status}, IMAP=${v.imap_status}`);
      // Pause the broken account
      await instantly(`/accounts/${encodeURIComponent(v.email)}/pause`, { method: "POST" });
      console.log(`  Paused ${v.email}. Fix credentials, then resume.`);
    }
  }
}

Lead Errors

Duplicate Lead (422)

// Prevent duplicates by setting skip flags
await instantly("/leads", {
  method: "POST",
  body: JSON.stringify({
    campaign: campaignId,
    email: "[email protected]",
    first_name: "Jane",
    skip_if_in_workspace: true,   // skip if email exists anywhere in workspace
    skip_if_in_campaign: true,    // skip if already in this campaign
  }),
});

Lead Status Reference

StatusLabelDescription
1ActiveEligible to receive emails
2PausedManually paused
3CompletedAll sequence steps sent
-1BouncedEmail bounced
-2UnsubscribedLead unsubscribed
-3SkippedSkipped (blocklist, duplicate, etc.)

Rate Limit Handling

async function withBackoff<T>(
  operation: () => Promise<T>,
  maxRetries = 5
): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (err: any) {
      if (err.status === 429 && attempt < maxRetries) {
        const wait = Math.pow(2, attempt) * 1000;
        console.warn(`429 Rate Limited. Waiting ${wait}ms (attempt ${attempt + 1}/${maxRetries})`);
        await new Promise((r) => setTimeout(r, wait));
        continue;
      }
      throw err;
    }
  }
  throw new Error("Unreachable");
}

Webhook Errors

IssueDiagnosticFix
Events not deliveredCheck webhook status: GET /webhooksWebhook may be paused — resume with POST /webhooks/{id}/resume
Wrong event formatCompare to expected schemaEnsure event_type matches: email_sent, reply_received, etc.
Delivery failuresCheck GET /webhook-events/summaryFix target URL, ensure 2xx response within 30s
Retries exhaustingInstantly retries 3x in 30sReturn 200 immediately, process async

Quick Diagnostic Script

set -euo pipefail
echo "=== Instantly Health Check ==="

# Test auth
curl -s -o /dev/null -w "Auth: HTTP %{http_code}\n" \
  https://api.instantly.ai/api/v2/campaigns?limit=1 \
  -H "Authorization: Bearer $INSTANTLY_API_KEY"

# Count campaigns by status
curl -s https://api.instantly.ai/api/v2/campaigns?limit=100 \
  -H "Authorization: Bearer $INSTANTLY_API_KEY" | \
  jq 'group_by(.status) | map({status: .[0].status, count: length})'

# Check account health
curl -s https://api.instantly.ai/api/v2/accounts?limit=100 \
  -H "Authorization: Bearer $INSTANTLY_API_KEY" | \
  jq '[.[] | {email, status, warmup_status}] | .[:5]'

Error Handling

ErrorCauseSolution
401 after key rotationOld key cachedRestart app / clear env cache
403 on campaign activateMissing campaigns:update scopeRegenerate API key with correct scopes
422 duplicate leadLead already in workspaceUse skip_if_in_workspace: true
Campaign -2 bounce protectBounce rate >5%Clean lead list, verify emails before import
Warmup health droppingToo many campaign emails too soonReduce daily_limit, extend warmup period

Resources

Next Steps

For structured debugging, see instantly-debug-bundle.