instantly-common-errors
Diagnose and fix Instantly.ai API v2 common errors and exceptions. Use when encountering Instantly errors, debugging failed requests, or troubleshooting campaign/account/lead issues. Trigger with phrases like "instantly error", "instantly 401", "instantly 429", "instantly api failed", "instantly debug", "instantly troubleshoot".
What this skill does
# 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
| Status | Meaning | Common Cause | Fix |
|--------|---------|-------------|-----|
| `400` | Bad Request | Malformed JSON, invalid field values | Validate request body against schema |
| `401` | Unauthorized | Invalid, expired, or revoked API key | Regenerate key in Settings > Integrations |
| `403` | Forbidden | API key missing required scope | Create key with correct scope (e.g., `campaigns:all`) |
| `404` | Not Found | Invalid campaign/lead/account ID | Verify resource exists with a GET call first |
| `422` | Unprocessable Entity | Business logic violation (duplicate lead, invalid state) | Check error body for details |
| `429` | Too Many Requests | Rate limit exceeded | Implement exponential backoff (see below) |
| `500` | Internal Server Error | Instantly server issue | Retry with backoff; check status.instantly.ai |
## Campaign Errors
### Campaign Won't Activate (Stuck in Draft)
```typescript
// 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
| Status | Label | Meaning |
|--------|-------|---------|
| `0` | Draft | Not yet activated |
| `1` | Active | Currently sending |
| `2` | Paused | Manually paused |
| `3` | Completed | All leads processed |
| `4` | Running Subsequences | Main sequence done, subsequences active |
| `-1` | Accounts Unhealthy | Sending accounts have SMTP/IMAP errors |
| `-2` | Bounce Protect | Auto-paused due to high bounce rate |
| `-99` | Suspended | Account-level suspension |
### Fix: Accounts Unhealthy (-1)
```typescript
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)
```typescript
// 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
| Status | Label | Description |
|--------|-------|-------------|
| `1` | Active | Eligible to receive emails |
| `2` | Paused | Manually paused |
| `3` | Completed | All sequence steps sent |
| `-1` | Bounced | Email bounced |
| `-2` | Unsubscribed | Lead unsubscribed |
| `-3` | Skipped | Skipped (blocklist, duplicate, etc.) |
## Rate Limit Handling
```typescript
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
| Issue | Diagnostic | Fix |
|-------|-----------|-----|
| Events not delivered | Check webhook status: `GET /webhooks` | Webhook may be paused — resume with `POST /webhooks/{id}/resume` |
| Wrong event format | Compare to expected schema | Ensure `event_type` matches: `email_sent`, `reply_received`, etc. |
| Delivery failures | Check `GET /webhook-events/summary` | Fix target URL, ensure 2xx response within 30s |
| Retries exhausting | Instantly retries 3x in 30s | Return 200 immediately, process async |
## Quick Diagnostic Script
```bash
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
| Error | Cause | Solution |
|-------|-------|----------|
| `401` after key rotation | Old key cached | Restart app / clear env cache |
| `403` on campaign activate | Missing `campaigns:update` scope | Regenerate API key with correct scopes |
| `422` duplicate lead | Lead already in workspace | Use `skip_if_in_workspace: true` |
| Campaign `-2` bounce protect | Bounce rate >5% | Clean lead list, verify emails before import |
| Warmup health dropping | Too many campaign emails too soon | Reduce daily_limit, extend warmup period |
## Resources
- [Instantly API v2 Docs](https://developer.instantly.ai/)
- [Instantly Help Center](https://help.instantly.ai)
- [API Schemas](https://developer.instantly.ai/api/v2/schemas)
## Next Steps
For structured debugging, see `instantly-debug-bundle`.
Related in Ads & Marketing
ads
IncludedMulti-platform paid advertising audit and optimization skill. Analyzes Google, Meta, YouTube, LinkedIn, TikTok, Microsoft, and Apple Ads. 250+ checks with scoring, parallel agents, industry templates, and AI creative generation.
banana
IncludedAI image generation Creative Director powered by Google Gemini Nano Banana models. Use this skill for ANY request involving image creation, editing, visual asset production, or creative direction. Triggers on: generate an image, create a photo, edit this picture, design a logo, make a banner, visual for my anything, and all /banana commands. Handles text-to-image, image editing, multi-turn creative sessions, batch workflows, and brand presets.
rpg-migration-analyzer
IncludedAnalyzes legacy RPG (Report Program Generator) programs from AS/400 and IBM i systems for migration to modern Java applications. Extracts business logic from RPG III/IV/ILE source code, identifies data structures (D-specs), file operations (F-specs), program dependencies (CALLB/CALLP), and converts RPG constructs to Java equivalents. Generates migration reports, complexity estimates, and Java implementation strategies with POJO classes, JPA entities, and service methods. Use when modernizing AS/400 or IBM i legacy systems, analyzing RPG source files (.rpg, .rpgle, .RPGLE), converting RPG to Java, mapping data specifications to Java classes, planning legacy system migration, or when user mentions RPG analysis, Report Program Generator, RPG III/IV/ILE, AS/400 modernization, IBM i migration, packed decimal conversion, or mainframe application rewrite.
brand-library-architect
IncludedBuild a complete brand library for a product — visual asset render pipeline, brand documentation set (BRAND, COPY, MANIFESTO, BIOS, FAQ, GLOSSARY, TONE, PRICING), open-source convention files (README, CONTRIBUTING, SECURITY, CODE_OF_CONDUCT), and a self-contained press kit. This skill should be used when the user asks to "build a brand library / brand kit / press kit / brand assets" for a product, "set up a brand library workflow," "create a positioning manifesto plus visual identity," or any combination of brand documentation + visual asset pipeline. Apply phase-by-phase or run end-to-end. Templates are product-agnostic and use {{TOKEN}} placeholders the skill prompts the user to fill.
writing-tech-post
IncludedAuthors engineering blog posts end-to-end: launch deep-dives, incident postmortems, architecture migrations, performance case studies, tutorials, AI/agent system writeups, security disclosures, and research-to-product translations. Picks the correct archetype, plans the abstraction ladder, enforces an evidence cadence (diagrams, benchmarks, profiles, traces, code, ablations), tunes voice against publisher house styles (Datadog, Vercel, GitHub, AWS, Meta, Cloudflare, Jane Street), and runs a pre-publish gate for narrative momentum and disclosure ethics. Use when drafting a new engineering post, restructuring a draft that feels flat, deciding which evidence form belongs where, validating that depth and product context are balanced, or preparing a postmortem, migration, or performance narrative for external publication. Do not use for API reference documentation, README authoring, marketing copy, release notes, generic SEO content, ghost-written executive thought leadership, or non-engineering long-form essays.
blog-google
IncludedGoogle API integration for blog performance: PageSpeed Insights, CrUX Core Web Vitals with 25-week history, Search Console performance, URL Inspection, Indexing API, GA4 organic traffic, NLP entity analysis for E-E-A-T, YouTube video search for embedding, and Google Ads Keyword Planner. Progressive feature availability based on credential tier (API key, OAuth/service account, GA4, Ads). Shares config with claude-seo at ~/.config/claude-seo/google-api.json. Use when user says "google data", "page speed", "core web vitals", "search console", "indexation", "GA4", "keyword research", "nlp entities", "blog performance", "youtube search", "google api setup".