API Tutorials

Type-Safe CaptchaAI Client with TypeScript Generics

TypeScript generics let you build a CAPTCHA client where the compiler enforces correct parameter types for each CAPTCHA method. Pass wrong parameters for a Turnstile solve? The compiler catches it before runtime.


Type definitions

// types.ts

export interface RecaptchaV2Params {
  method: "userrecaptcha";
  googlekey: string;
  pageurl: string;
  invisible?: boolean;
  "data-s"?: string;
  proxy?: string;
  proxytype?: "HTTP" | "HTTPS" | "SOCKS4" | "SOCKS5";
}

export interface RecaptchaV3Params {
  method: "userrecaptcha";
  version: "v3";
  googlekey: string;
  pageurl: string;
  action?: string;
  min_score?: number;
}

export interface TurnstileParams {
  method: "turnstile";
  sitekey: string;
  pageurl: string;
  action?: string;
  data?: string;
}

export interface ImageParams {
  method: "base64";
  body: string;
  phrase?: boolean;
  regsense?: boolean;
  numeric?: 0 | 1 | 2;
  min_len?: number;
  max_len?: number;
}

export type CaptchaParams =
  | RecaptchaV2Params
  | RecaptchaV3Params
  | TurnstileParams
  | ImageParams;

export interface SolveResult {
  taskId: string;
  token: string;
  solveTime: number;
}

export interface APIResponse {
  status: number;
  request: string;
}

export class CaptchaAIError extends Error {
  constructor(public code: string) {
    super(`CaptchaAI error: ${code}`);
    this.name = "CaptchaAIError";
  }
}

export class TimeoutError extends CaptchaAIError {
  constructor(taskId: string) {
    super(`TIMEOUT: task ${taskId}`);
    this.name = "TimeoutError";
  }
}

Generic client

// client.ts

import {
  CaptchaParams,
  SolveResult,
  APIResponse,
  CaptchaAIError,
  TimeoutError,
} from "./types";

const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

interface ClientOptions {
  apiKey: string;
  timeout?: number;
  pollInterval?: number;
}

export class CaptchaAI {
  private apiKey: string;
  private timeout: number;
  private pollInterval: number;

  constructor(options: ClientOptions) {
    this.apiKey = options.apiKey;
    this.timeout = options.timeout ?? 120_000;
    this.pollInterval = options.pollInterval ?? 5_000;
  }

  async solve<T extends CaptchaParams>(params: T): Promise<SolveResult> {
    const start = Date.now();

    // Build form body
    const body = new URLSearchParams();
    body.set("key", this.apiKey);
    body.set("json", "1");

    for (const [key, value] of Object.entries(params)) {
      if (value !== undefined) {
        body.set(key, String(value));
      }
    }

    // Submit
    const submitResp = await fetch(SUBMIT_URL, {
      method: "POST",
      body,
    });
    const submitData: APIResponse = await submitResp.json();

    if (submitData.status !== 1) {
      throw new CaptchaAIError(submitData.request);
    }

    const taskId = submitData.request;

    // Poll
    const deadline = start + this.timeout;
    while (Date.now() < deadline) {
      await this.delay(this.pollInterval);

      const url = new URL(RESULT_URL);
      url.searchParams.set("key", this.apiKey);
      url.searchParams.set("action", "get");
      url.searchParams.set("id", taskId);
      url.searchParams.set("json", "1");

      const pollResp = await fetch(url.toString());
      const pollData: APIResponse = await pollResp.json();

      if (pollData.status === 1) {
        return {
          taskId,
          token: pollData.request,
          solveTime: (Date.now() - start) / 1000,
        };
      }

      if (pollData.request !== "CAPCHA_NOT_READY") {
        throw new CaptchaAIError(pollData.request);
      }
    }

    throw new TimeoutError(taskId);
  }

  async getBalance(): Promise<number> {
    const url = new URL(RESULT_URL);
    url.searchParams.set("key", this.apiKey);
    url.searchParams.set("action", "getbalance");
    url.searchParams.set("json", "1");

    const resp = await fetch(url.toString());
    const data: APIResponse = await resp.json();

    if (data.status !== 1) {
      throw new CaptchaAIError(data.request);
    }

    return parseFloat(data.request);
  }

  async reportBad(taskId: string): Promise<void> {
    const url = new URL(RESULT_URL);
    url.searchParams.set("key", this.apiKey);
    url.searchParams.set("action", "reportbad");
    url.searchParams.set("id", taskId);
    url.searchParams.set("json", "1");
    await fetch(url.toString());
  }

  private delay(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }
}

Type-safe usage

The generic solve<T> method enforces parameter shapes at compile time:

import { CaptchaAI } from "./client";
import type {
  RecaptchaV2Params,
  RecaptchaV3Params,
  TurnstileParams,
  ImageParams,
} from "./types";

const solver = new CaptchaAI({ apiKey: "YOUR_API_KEY" });

// reCAPTCHA v2 — compiler requires googlekey and pageurl
const v2Result = await solver.solve<RecaptchaV2Params>({
  method: "userrecaptcha",
  googlekey: "6Le-SITEKEY",
  pageurl: "https://example.com",
});
console.log(`v2 token: ${v2Result.token.substring(0, 40)}...`);

// reCAPTCHA v3 — compiler requires version, action fields
const v3Result = await solver.solve<RecaptchaV3Params>({
  method: "userrecaptcha",
  version: "v3",
  googlekey: "6Le-V3KEY",
  pageurl: "https://example.com",
  action: "login",
  min_score: 0.7,
});
console.log(`v3 score token: ${v3Result.token.substring(0, 40)}...`);

// Turnstile — compiler requires sitekey (not googlekey)
const turnstileResult = await solver.solve<TurnstileParams>({
  method: "turnstile",
  sitekey: "0x4AAAAAAAB...",
  pageurl: "https://example.com",
});
console.log(`Turnstile token: ${turnstileResult.token.substring(0, 40)}...`);

// Image — compiler requires body (base64)
const imageResult = await solver.solve<ImageParams>({
  method: "base64",
  body: "iVBORw0KGgoAAAANSUhEUg...",
});
console.log(`Image text: ${imageResult.token}`);

Compile-time error examples

// ERROR: Property 'sitekey' does not exist on type 'RecaptchaV2Params'
await solver.solve<RecaptchaV2Params>({
  method: "userrecaptcha",
  sitekey: "wrong-field",  // should be 'googlekey'
  pageurl: "https://example.com",
});

// ERROR: Property 'version' is missing in type
await solver.solve<RecaptchaV3Params>({
  method: "userrecaptcha",
  googlekey: "6Le-KEY",
  pageurl: "https://example.com",
  // missing: version: "v3"
});

Error handling with type narrowing

import { CaptchaAIError, TimeoutError } from "./types";

try {
  const result = await solver.solve<RecaptchaV2Params>({
    method: "userrecaptcha",
    googlekey: "6Le-SITEKEY",
    pageurl: "https://example.com",
  });
  console.log(`Solved: ${result.token.substring(0, 50)}...`);
} catch (error) {
  if (error instanceof TimeoutError) {
    console.error("Solve timed out — increase timeout or check parameters");
  } else if (error instanceof CaptchaAIError) {
    switch (error.code) {
      case "ERROR_ZERO_BALANCE":
        console.error("Add funds to your account");
        break;
      case "ERROR_WRONG_USER_KEY":
        console.error("Check your API key");
        break;
      default:
        console.error(`API error: ${error.code}`);
    }
  }
}

Troubleshooting

Problem Cause Fix
Type errors on solve() call Wrong parameter interface Match the generic type to the method field
fetch is not defined Node.js < 18 Use Node.js 18+ or install node-fetch
CaptchaAIError: ERROR_WRONG_USER_KEY Invalid API key Verify key in CaptchaAI dashboard

FAQ

Why use generics instead of separate methods?

Generics give you one solve() method that handles all types while the compiler enforces correct parameters. You get the simplicity of a single method with the safety of per-type validation.

Can I extend this with new CAPTCHA types?

Yes. Define a new params interface, add it to the CaptchaParams union, and the solve() method works with it automatically.


Build type-safe CAPTCHA solving into your TypeScript projects

Get your API key at captchaai.com.


Discussions (0)

No comments yet.

Related Posts

API Tutorials CaptchaAI API Latency Optimization: Faster Solves
Reduce CAPTCHA solve latency with Captcha AI by optimizing poll intervals, connection pooling, prefetching, and proxy selection.

Reduce CAPTCHA solve latency with Captcha AI by optimizing poll intervals, connection pooling, prefetching, an...

Automation Python reCAPTCHA v2
Feb 27, 2026
API Tutorials Building a Python Wrapper Library for CaptchaAI API
Build a reusable Python wrapper library for the Captcha AI API with type hints, retry logic, context managers, and support for CAPTCHA types.

Build a reusable Python wrapper library for the Captcha AI API with type hints, retry logic, context managers,...

Automation Python reCAPTCHA v2
Jan 31, 2026
Reference CAPTCHA Token Injection Methods Reference
Complete reference for injecting solved CAPTCHA tokens into web pages.

Complete reference for injecting solved CAPTCHA tokens into web pages. Covers re CAPTCHA, Turnstile, and Cloud...

Automation Python reCAPTCHA v2
Apr 08, 2026
Reference Browser Session Persistence for CAPTCHA Workflows
Manage browser sessions, cookies, and storage across CAPTCHA-solving runs to reduce repeat challenges and maintain authenticated state.

Manage browser sessions, cookies, and storage across CAPTCHA-solving runs to reduce repeat challenges and main...

Automation Python reCAPTCHA v2
Feb 24, 2026
Use Cases CAPTCHA Solving in Ticket Purchase Automation
How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automated purchasing workflows.

How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automate...

Automation Python reCAPTCHA v2
Feb 25, 2026
Tutorials Caching CAPTCHA Tokens for Reuse
Cache and reuse CAPTCHA tokens with Captcha AI to reduce API calls and costs.

Cache and reuse CAPTCHA tokens with Captcha AI to reduce API calls and costs. Covers token lifetimes, cache st...

Automation Python reCAPTCHA v2
Feb 15, 2026
Explainers Reducing CAPTCHA Solve Costs: 10 Strategies
Cut CAPTCHA solving costs with Captcha AI using 10 practical strategies — from skipping unnecessary solves to batching and caching tokens.

Cut CAPTCHA solving costs with Captcha AI using 10 practical strategies — from skipping unnecessary solves to...

Python reCAPTCHA v2 Cloudflare Turnstile
Mar 11, 2026
Tutorials Browser Console CAPTCHA Detection: Finding Sitekeys and Parameters
Use browser Dev Tools to detect CAPTCHA types, extract sitekeys, and find parameters needed for Captcha AI API requests.

Use browser Dev Tools to detect CAPTCHA types, extract sitekeys, and find all parameters needed for Captcha AI...

Automation reCAPTCHA v2 Cloudflare Turnstile
Mar 25, 2026
Use Cases Multi-Step Checkout Automation with CAPTCHA Solving
Automate multi-step e-commerce checkout flows that include CAPTCHA challenges at cart, payment, or confirmation stages using Captcha AI.

Automate multi-step e-commerce checkout flows that include CAPTCHA challenges at cart, payment, or confirmatio...

Automation Python reCAPTCHA v2
Mar 21, 2026
Comparisons Headless vs Headed Chrome for CAPTCHA Solving
Compare headless and headed Chrome for CAPTCHA automation — detection differences, performance trade-offs, and when to use each mode with Captcha AI.

Compare headless and headed Chrome for CAPTCHA automation — detection differences, performance trade-offs, and...

Automation Python reCAPTCHA v2
Mar 09, 2026
API Tutorials How to Solve reCAPTCHA v2 Callback Using API
how to solve re CAPTCHA v 2 callback implementations using Captcha AI API.

Learn how to solve re CAPTCHA v 2 callback implementations using Captcha AI API. Detect the callback function,...

Automation reCAPTCHA v2 Webhooks
Mar 01, 2026
API Tutorials Solve GeeTest v3 CAPTCHA with Python and CaptchaAI
Step-by-step Python tutorial for solving Gee Test v 3 slide puzzle CAPTCHAs using the Captcha AI API.

Step-by-step Python tutorial for solving Gee Test v 3 slide puzzle CAPTCHAs using the Captcha AI API. Includes...

Automation Python Testing
Mar 23, 2026
API Tutorials Case-Sensitive CAPTCHA API Parameter Guide
How to use the regsense parameter for case-sensitive CAPTCHA solving with Captcha AI.

How to use the regsense parameter for case-sensitive CAPTCHA solving with Captcha AI. Covers when to use, comm...

Python Web Scraping Image OCR
Apr 09, 2026