CtrlK
BlogDocsLog inGet started
Tessl Logo

instantly-debug-bundle

Collect Instantly.ai debug evidence for support tickets and troubleshooting. Use when encountering persistent issues, preparing support tickets, or auditing campaign/account state. Trigger with phrases like "instantly debug", "instantly support ticket", "instantly diagnostic", "instantly audit", "collect instantly evidence".

80

Quality

77%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Optimize this skill with Tessl

npx tessl skill review --optimize ./plugins/saas-packs/instantly-pack/skills/instantly-debug-bundle/SKILL.md
SKILL.md
Quality
Evals
Security

Instantly Debug Bundle

Overview

Collect a comprehensive debug bundle from your Instantly workspace: campaign state, account health, warmup metrics, lead stats, webhook delivery status, and recent errors. Output is a JSON report suitable for support tickets or internal audits.

Prerequisites

  • Completed instantly-install-auth setup
  • API key with all:read scope (or individual read scopes for each resource)

Instructions

Step 1: Collect Full Debug Bundle

import { instantly } from "./src/instantly";
import { writeFileSync } from "fs";

interface DebugBundle {
  timestamp: string;
  workspace: unknown;
  campaigns: unknown[];
  accounts: unknown[];
  warmup_analytics: unknown[];
  webhooks: unknown[];
  webhook_event_summary: unknown;
  background_jobs: unknown[];
  lead_count_by_campaign: Record<string, number>;
  errors: string[];
}

async function collectDebugBundle(): Promise<DebugBundle> {
  const bundle: DebugBundle = {
    timestamp: new Date().toISOString(),
    workspace: null,
    campaigns: [],
    accounts: [],
    warmup_analytics: [],
    webhooks: [],
    webhook_event_summary: null,
    background_jobs: [],
    lead_count_by_campaign: {},
    errors: [],
  };

  // Workspace info
  try {
    bundle.workspace = await instantly("/workspaces/current");
  } catch (e: any) {
    bundle.errors.push(`workspace: ${e.message}`);
  }

  // All campaigns with status
  try {
    bundle.campaigns = await instantly("/campaigns?limit=100");
  } catch (e: any) {
    bundle.errors.push(`campaigns: ${e.message}`);
  }

  // All email accounts
  try {
    bundle.accounts = await instantly("/accounts?limit=100");
  } catch (e: any) {
    bundle.errors.push(`accounts: ${e.message}`);
  }

  // Warmup analytics for all accounts
  try {
    const accounts = bundle.accounts as Array<{ email: string }>;
    if (accounts.length > 0) {
      bundle.warmup_analytics = await instantly("/accounts/warmup-analytics", {
        method: "POST",
        body: JSON.stringify({ emails: accounts.map((a) => a.email) }),
      });
    }
  } catch (e: any) {
    bundle.errors.push(`warmup_analytics: ${e.message}`);
  }

  // Webhooks
  try {
    bundle.webhooks = await instantly("/webhooks?limit=50");
  } catch (e: any) {
    bundle.errors.push(`webhooks: ${e.message}`);
  }

  // Webhook event delivery summary
  try {
    bundle.webhook_event_summary = await instantly("/webhook-events/summary");
  } catch (e: any) {
    bundle.errors.push(`webhook_events: ${e.message}`);
  }

  // Recent background jobs
  try {
    bundle.background_jobs = await instantly("/background-jobs?limit=20");
  } catch (e: any) {
    bundle.errors.push(`background_jobs: ${e.message}`);
  }

  // Lead counts per campaign
  for (const c of (bundle.campaigns as Array<{ id: string; name: string }>).slice(0, 10)) {
    try {
      const analytics = await instantly<{ total_leads: number }>(
        `/campaigns/analytics?id=${c.id}`
      );
      bundle.lead_count_by_campaign[c.name] = analytics.total_leads;
    } catch {
      bundle.lead_count_by_campaign[c.name] = -1; // error
    }
  }

  return bundle;
}

Step 2: Save and Analyze

async function main() {
  console.log("Collecting Instantly debug bundle...\n");
  const bundle = await collectDebugBundle();

  // Save to file
  const filename = `instantly-debug-${Date.now()}.json`;
  writeFileSync(filename, JSON.stringify(bundle, null, 2));
  console.log(`Saved debug bundle to ${filename}`);

  // Print summary
  const campaigns = bundle.campaigns as Array<{ name: string; status: number }>;
  const accounts = bundle.accounts as Array<{ email: string; status: number }>;

  console.log("\n=== Debug Summary ===");
  console.log(`Campaigns: ${campaigns.length}`);
  console.log(`  Active: ${campaigns.filter((c) => c.status === 1).length}`);
  console.log(`  Paused: ${campaigns.filter((c) => c.status === 2).length}`);
  console.log(`  Unhealthy: ${campaigns.filter((c) => c.status === -1).length}`);
  console.log(`  Bounce Protected: ${campaigns.filter((c) => c.status === -2).length}`);

  console.log(`\nAccounts: ${accounts.length}`);
  console.log(`Webhooks: ${(bundle.webhooks as any[]).length}`);
  console.log(`Background Jobs: ${(bundle.background_jobs as any[]).length}`);

  if (bundle.errors.length > 0) {
    console.log(`\nErrors during collection:`);
    bundle.errors.forEach((e) => console.log(`  - ${e}`));
  }
}

main().catch(console.error);

Step 3: Account Vitals Deep Dive

async function accountVitalsDiagnostic() {
  const accounts = await instantly<Array<{ email: string }>>(
    "/accounts?limit=100"
  );

  const vitals = await instantly("/accounts/test/vitals", {
    method: "POST",
    body: JSON.stringify({ accounts: accounts.map((a) => a.email) }),
  }) as Array<{ email: string; smtp_status: string; imap_status: string; dns_status: string }>;

  console.log("\n=== Account Vitals ===");
  const broken = vitals.filter((v) => v.smtp_status !== "ok" || v.imap_status !== "ok");
  const healthy = vitals.filter((v) => v.smtp_status === "ok" && v.imap_status === "ok");

  console.log(`Healthy: ${healthy.length} | Broken: ${broken.length}`);
  for (const v of broken) {
    console.log(`  BROKEN: ${v.email} — SMTP=${v.smtp_status} IMAP=${v.imap_status} DNS=${v.dns_status}`);
  }
}

Step 4: Curl-Based Quick Diagnostic

set -euo pipefail
echo "=== Instantly Quick Diagnostic ==="
echo "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)"

echo -e "\n--- Campaigns ---"
curl -s https://api.instantly.ai/api/v2/campaigns?limit=100 \
  -H "Authorization: Bearer $INSTANTLY_API_KEY" | \
  jq '[.[] | {name, status, id}] | length as $total |
    {total: $total,
     active: [.[] | select(.status==1)] | length,
     paused: [.[] | select(.status==2)] | length,
     unhealthy: [.[] | select(.status==-1)] | length}'

echo -e "\n--- Accounts ---"
curl -s https://api.instantly.ai/api/v2/accounts?limit=100 \
  -H "Authorization: Bearer $INSTANTLY_API_KEY" | \
  jq 'length as $total | {total: $total, accounts: [.[:5][] | {email, status}]}'

echo -e "\n--- Webhooks ---"
curl -s https://api.instantly.ai/api/v2/webhooks?limit=50 \
  -H "Authorization: Bearer $INSTANTLY_API_KEY" | \
  jq '[.[] | {name, event_type, target_hook_url}]'

echo -e "\n--- Recent Background Jobs ---"
curl -s https://api.instantly.ai/api/v2/background-jobs?limit=5 \
  -H "Authorization: Bearer $INSTANTLY_API_KEY" | \
  jq '[.[] | {id, status, timestamp_created}]'

Output

  • instantly-debug-{timestamp}.json — full debug bundle
  • Console summary with campaign/account/webhook counts
  • Broken account identification with SMTP/IMAP status
  • Errors collected during diagnostic

Error Handling

ErrorCauseSolution
403 on workspace endpointKey missing workspace scopeAdd all:read scope to API key
Empty warmup analyticsNo accounts have warmup enabledEnable warmup first
Partial bundleSome endpoints failedCheck errors array in bundle output
Large bundle (>10MB)100+ campaigns and accountsReduce limits or collect per-campaign

Resources

  • Instantly Help Center
  • Instantly API v2 Docs
  • Background Jobs API

Next Steps

For error resolution patterns, see instantly-common-errors.

Repository
jeremylongshore/claude-code-plugins-plus-skills
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.