IN

instantly-sdk-patterns

Provides standardized coding patterns for Instantly.ai API requests including retry logic and type-safe clients.

Install

mkdir -p .claude/skills/instantly-sdk-patterns && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/3373" && unzip -o skill.zip -d .claude/skills/instantly-sdk-patterns && rm skill.zip

Installs to .claude/skills/instantly-sdk-patterns

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Apply production-ready Instantly.ai API client patterns for TypeScript
70 charsno explicit “when” trigger
Intermediate

Key capabilities

  • Implement type-safe Instantly API clients in TypeScript
  • Implement Instantly API clients in Python
  • Classify API errors for retry logic
  • Handle pagination for large datasets
  • Support multi-tenant Instantly integrations

How it works

This skill provides production-ready code patterns for Instantly API v2 integrations, including a type-safe client, error classification, pagination, and multi-tenant support for TypeScript and Python.

Inputs & outputs

You give it
Instantly API key and base URL
You get back
Type-safe API client with error classification, pagination, and multi-tenant support

When to use instantly-sdk-patterns

  • Creating a type-safe client wrapper for Instantly API
  • Implementing retry logic for API stability
  • Establishing standard patterns for multi-tenant API calls

About this skill

Instantly SDK Patterns

Overview

Production-ready patterns for Instantly API v2 integrations. Instantly has no official SDK — all integrations use direct REST calls to https://api.instantly.ai/api/v2/. These patterns provide type safety, retry logic, pagination, and multi-tenant support.

Prerequisites

  • Completed instantly-install-auth setup
  • Familiarity with async/await and TypeScript generics
  • Understanding of REST API pagination patterns

Instructions

Step 1: Type-Safe Client with Error Classification

// src/instantly/client.ts
import "dotenv/config";

export class InstantlyClient {
  private baseUrl: string;
  private apiKey: string;

  constructor(options?: { apiKey?: string; baseUrl?: string }) {
    this.apiKey = options?.apiKey || process.env.INSTANTLY_API_KEY || "";
    this.baseUrl = options?.baseUrl || "https://api.instantly.ai/api/v2";
    if (!this.apiKey) throw new Error("INSTANTLY_API_KEY is required");
  }

  async request<T>(path: string, options: RequestInit = {}): Promise<T> {
    const url = `${this.baseUrl}${path}`;
    const res = await fetch(url, {
      ...options,
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${this.apiKey}`,
        ...options.headers,
      },
    });

    if (!res.ok) {
      const body = await res.text();
      throw new InstantlyApiError(res.status, path, body);
    }

    return res.json() as Promise<T>;
  }

  // Typed convenience methods
  async getCampaigns(params?: { limit?: number; status?: number; search?: string }) {
    const qs = new URLSearchParams();
    if (params?.limit) qs.set("limit", String(params.limit));
    if (params?.status !== undefined) qs.set("status", String(params.status));
    if (params?.search) qs.set("search", params.search);
    return this.request<Campaign[]>(`/campaigns?${qs}`);
  }

  async getCampaign(id: string) {
    return this.request<Campaign>(`/campaigns/${id}`);
  }

  async createCampaign(data: CreateCampaignInput) {
    return this.request<Campaign>("/campaigns", {
      method: "POST",
      body: JSON.stringify(data),
    });
  }

  async activateCampaign(id: string) {
    return this.request<void>(`/campaigns/${id}/activate`, { method: "POST" });
  }

  async pauseCampaign(id: string) {
    return this.request<void>(`/campaigns/${id}/pause`, { method: "POST" });
  }

  async getAccounts(params?: { limit?: number; status?: number }) {
    const qs = new URLSearchParams();
    if (params?.limit) qs.set("limit", String(params.limit));
    if (params?.status !== undefined) qs.set("status", String(params.status));
    return this.request<Account[]>(`/accounts?${qs}`);
  }

  async addLead(data: CreateLeadInput) {
    return this.request<Lead>("/leads", {
      method: "POST",
      body: JSON.stringify(data),
    });
  }

  async listLeads(filter: ListLeadsInput) {
    return this.request<Lead[]>("/leads/list", {
      method: "POST",
      body: JSON.stringify(filter),
    });
  }

  async getCampaignAnalytics(ids: string[]) {
    const qs = ids.map((id) => `ids=${id}`).join("&");
    return this.request<CampaignAnalytics[]>(`/campaigns/analytics?${qs}`);
  }
}

// Error classification
export class InstantlyApiError extends Error {
  public retryable: boolean;

  constructor(public status: number, public path: string, public body: string) {
    super(`Instantly ${status} on ${path}: ${body}`);
    this.name = "InstantlyApiError";
    this.retryable = status === 429 || status >= 500;
  }
}

Step 2: TypeScript Interfaces

// src/instantly/types.ts
export interface Campaign {
  id: string;
  name: string;
  status: number; // 0=Draft,1=Active,2=Paused,3=Completed,4=Running Subsequences
  campaign_schedule: CampaignSchedule;
  sequences: Sequence[];
  daily_limit: number | null;
  stop_on_reply: boolean;
  email_gap: number;
  timestamp_created: string;
}

export interface CampaignSchedule {
  start_date: string | null;
  end_date: string | null;
  schedules: Array<{
    name: string;
    timing: { from: string; to: string };
    days: Record<string, boolean>;
    timezone: string;
  }>;
}

export interface Sequence {
  steps: SequenceStep[];
}

export interface SequenceStep {
  type: "email";
  delay: number;
  delay_unit?: "minutes" | "hours" | "days";
  variants: Array<{ subject: string; body: string; v_disabled?: boolean }>;
}

export interface Account {
  email: string;
  first_name: string;
  last_name: string;
  status: number;
  warmup_status: string;
  daily_limit: number | null;
  provider_code: number;
  warmup: { limit: number; increment: string; advanced: Record<string, unknown> };
}

export interface Lead {
  id: string;
  email: string | null;
  first_name: string | null;
  last_name: string | null;
  company_name: string | null;
  status: number; // 1=Active,2=Paused,3=Completed,-1=Bounced,-2=Unsubscribed,-3=Skipped
  campaign: string | null;
  email_open_count: number;
  email_reply_count: number;
}

export interface CreateCampaignInput {
  name: string;
  campaign_schedule: CampaignSchedule;
  sequences: Sequence[];
  daily_limit?: number;
  stop_on_reply?: boolean;
  email_gap?: number;
  open_tracking?: boolean;
  link_tracking?: boolean;
}

export interface CreateLeadInput {
  campaign?: string;
  list_id?: string;
  email: string;
  first_name?: string;
  last_name?: string;
  company_name?: string;
  custom_variables?: Record<string, string>;
  skip_if_in_workspace?: boolean;
  verify_leads_on_import?: boolean;
}

export interface ListLeadsInput {
  campaign?: string;
  list_id?: string;
  limit?: number;
  starting_after?: string;
}

export interface CampaignAnalytics {
  campaign_id: string;
  total_leads: number;
  emails_sent: number;
  emails_opened: number;
  emails_replied: number;
  emails_bounced: number;
}

Step 3: Retry with Exponential Backoff

// src/instantly/retry.ts
export async function withRetry<T>(
  operation: () => Promise<T>,
  maxRetries = 3,
  baseDelayMs = 1000
): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (err) {
      if (attempt === maxRetries) throw err;
      if (err instanceof InstantlyApiError && !err.retryable) throw err;

      const delay = baseDelayMs * Math.pow(2, attempt);
      const jitter = Math.random() * delay * 0.1;
      console.warn(`Retry ${attempt + 1}/${maxRetries} in ${delay}ms...`);
      await new Promise((r) => setTimeout(r, delay + jitter));
    }
  }
  throw new Error("Unreachable");
}

// Usage
const campaigns = await withRetry(() => client.getCampaigns({ limit: 50 }));

Step 4: Cursor-Based Pagination

// src/instantly/paginate.ts
export async function* paginate<T extends { id: string }>(
  client: InstantlyClient,
  path: string,
  pageSize = 100
): AsyncGenerator<T[], void, void> {
  let startingAfter: string | undefined;

  while (true) {
    const qs = new URLSearchParams({ limit: String(pageSize) });
    if (startingAfter) qs.set("starting_after", startingAfter);

    const page = await client.request<T[]>(`${path}?${qs}`);
    if (page.length === 0) break;

    yield page;
    startingAfter = page[page.length - 1].id;

    if (page.length < pageSize) break;
  }
}

// Usage — iterate all campaigns
for await (const batch of paginate<Campaign>(client, "/campaigns")) {
  for (const campaign of batch) {
    console.log(campaign.name, campaign.status);
  }
}

Step 5: Multi-Tenant Factory (Agency Pattern)

// src/instantly/factory.ts
const clients = new Map<string, InstantlyClient>();

export function getClientForWorkspace(workspaceId: string, apiKey: string): InstantlyClient {
  if (!clients.has(workspaceId)) {
    clients.set(workspaceId, new InstantlyClient({ apiKey }));
  }
  return clients.get(workspaceId)!;
}

// Usage — agency managing multiple client workspaces
const clientA = getClientForWorkspace("acme", process.env.ACME_API_KEY!);
const clientB = getClientForWorkspace("globex", process.env.GLOBEX_API_KEY!);

Python Client

# instantly/client.py
import os, time, httpx
from dataclasses import dataclass
from typing import Optional

@dataclass
class InstantlyClient:
    api_key: str = ""
    base_url: str = "https://api.instantly.ai/api/v2"

    def __post_init__(self):
        self.api_key = self.api_key or os.getenv("INSTANTLY_API_KEY", "")
        self._client = httpx.Client(
            base_url=self.base_url,
            headers={"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"},
            timeout=30.0,
        )

    def get(self, path: str, params: Optional[dict] = None):
        r = self._client.get(path, params=params)
        r.raise_for_status()
        return r.json()

    def post(self, path: str, json_data: Optional[dict] = None):
        r = self._client.post(path, json=json_data)
        r.raise_for_status()
        return r.json()

    def patch(self, path: str, json_data: dict):
        r = self._client.patch(path, json=json_data)
        r.raise_for_status()
        return r.json()

    def delete(self, path: str):
        r = self._client.delete(path)
        r.raise_for_status()

    def list_campaigns(self, limit: int = 50):
        return self.get("/campaigns", params={"limit": limit})

    def get_campaign_analytics(self, campaign_id: str):
        return self.get("/campaigns/analytics", params={"id": campaign_id})

Error Handling

PatternUse CaseBenefit
Error classificationAll API callsretryable flag prevents retrying 400/403 errors
Exponential backoff429 / 5xx errorsRespects rate limits automatically
Cursor paginationLarge datasetsMemory-efficient iteration
Multi-tenant factoryAgency/multi-workspaceIsolated clients per workspace

Resources


Content truncated.

When not to use it

  • When `instantly-install-auth` setup is not completed
  • When familiarity with async/await and TypeScript generics is lacking
  • When understanding of REST API pagination patterns is lacking

Prerequisites

Completed `instantly-install-auth` setupFamiliarity with async/await and TypeScript genericsUnderstanding of REST API pagination patterns

Limitations

  • Instantly has no official SDK
  • Requires understanding of REST API pagination patterns
  • Error classification prevents retrying 400/403 errors

How it compares

This skill offers structured, production-ready patterns for Instantly API integrations, providing advanced features like type safety and multi-tenancy, unlike basic API client setups.

Compared to similar skills

instantly-sdk-patterns side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
instantly-sdk-patterns (this skill)124dCautionIntermediate
exa-upgrade-migration124dReviewIntermediate
deepgram-sdk-patterns124dReviewIntermediate
perplexity-known-pitfalls024dReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

More by jeremylongshore

View all by jeremylongshore

analyzing-logs

jeremylongshore

Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.

14123

ollama-setup

jeremylongshore

Configure auto-configure Ollama when user needs local LLM deployment, free AI alternatives, or wants to eliminate hosted API costs. Trigger phrases: "install ollama", "local AI", "free LLM", "self-hosted AI", "replace OpenAI", "no API costs". Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

1167

backtesting-trading-strategies

jeremylongshore

Backtest crypto and traditional trading strategies against historical data. Calculates performance metrics (Sharpe, Sortino, max drawdown), generates equity curves, and optimizes strategy parameters. Use when user wants to test a trading strategy, validate signals, or compare approaches. Trigger with phrases like "backtest strategy", "test trading strategy", "historical performance", "simulate trades", "optimize parameters", or "validate signals".

1071

generating-database-seed-data

jeremylongshore

Process this skill enables AI assistant to generate realistic test data and database seed scripts for development and testing environments. it uses faker libraries to create realistic data, maintains relational integrity, and allows configurable data volumes. u... Use when working with databases or data models. Trigger with phrases like 'database', 'query', or 'schema'.

1033

cursor-codebase-indexing

jeremylongshore

Execute set up and optimize Cursor codebase indexing. Triggers on "cursor index setup", "codebase indexing", "index codebase", "cursor semantic search". Use when working with cursor codebase indexing functionality. Trigger with phrases like "cursor codebase indexing", "cursor indexing", "cursor".

885

testing-mobile-apps

jeremylongshore

Execute mobile app testing on iOS and Android devices/simulators. Use when performing specialized testing. Trigger with phrases like "test mobile app", "run iOS tests", or "validate Android functionality".

810

You might also like

exa-upgrade-migration

jeremylongshore

Analyze, plan, and execute Exa SDK upgrades with breaking change detection. Use when upgrading Exa SDK versions, detecting deprecations, or migrating to new API versions. Trigger with phrases like "upgrade exa", "exa migration", "exa breaking changes", "update exa SDK", "analyze exa version".

14

deepgram-sdk-patterns

jeremylongshore

Apply production-ready Deepgram SDK patterns for TypeScript and Python. Use when implementing Deepgram integrations, refactoring SDK usage, or establishing team coding standards for Deepgram. Trigger with phrases like "deepgram SDK patterns", "deepgram best practices", "deepgram code patterns", "idiomatic deepgram", "deepgram typescript".

10

perplexity-known-pitfalls

jeremylongshore

Identify and avoid Perplexity anti-patterns and common integration mistakes. Use when reviewing Perplexity code for issues, onboarding new developers, or auditing existing Perplexity integrations for best practices violations. Trigger with phrases like "perplexity mistakes", "perplexity anti-patterns", "perplexity pitfalls", "perplexity what not to do", "perplexity code review".

01

speak-sdk-patterns

jeremylongshore

Apply production-ready Speak SDK patterns for TypeScript and Python. Use when implementing Speak integrations, refactoring SDK usage, or establishing team coding standards for language learning features. Trigger with phrases like "speak SDK patterns", "speak best practices", "speak code patterns", "idiomatic speak".

01

mcp-builder

anthropics

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

136215

stripe-integration

wshobson

Implement Stripe payment processing for robust, PCI-compliant payment flows including checkout, subscriptions, and webhooks. Use when integrating Stripe payments, building subscription systems, or implementing secure checkout flows.

48165

Search skills

Search the agent skills registry