agentsclimarketplace

Instantly common errors

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/instantly-pack/skills/instantly-common-errors

'Diagnose and fix Instantly.ai API v2 common errors and exceptions.From its SKILL.md

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

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

7.8 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it

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.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,144. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.