JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 17
  • Score
    100M100P100Q88031F
  • License MIT

Official Node.js SDK for the OneCaptcha unified captcha-solving gateway.

Package Exports

  • @onecaptcha/sdk

Readme

@onecaptcha/sdk

Official Node.js SDK for the OneCaptcha unified captcha-solving gateway.

  • Zero dependencies. Built-in fetch (Node 18+).
  • ESM only.
  • Mirrors project_spec/openapi.yaml exactly — same field names, same error codes.

Install

npm install @onecaptcha/sdk

Quick start

import { OneCaptchaClient } from '@onecaptcha/sdk';

const client = new OneCaptchaClient({
  apiKey:  process.env.ONECAPTCHA_API_KEY,
  baseUrl: 'https://api.one-captcha.com', // optional — this is the default
});

// Sync solve — gateway holds the connection until done.
const result = await client.solveRecaptchaV2({
  url:     'https://example.com/login',
  sitekey: '6Lc...',
});

console.log(result.token);            // the gRecaptchaResponse token
console.log(result.cost);              // 0.003887
console.log(result.balanceRemaining);  // 0.997113

Constructor options

Option Default Description
apiKey required Your gateway API key (sent as X-API-Key)
baseUrl https://api.one-captcha.com Gateway origin, no trailing slash
timeout 30000 ms timeout for non-solve calls
solveTimeout 120 (seconds) Default X-Timeout for sync solve(). Min 10, max 180.
pollInterval 5000 ms between polls in waitForTask
pollTimeout 180000 Total ms waitForTask waits before giving up
fetch globalThis.fetch Custom fetch implementation (test injection)
userAgent onecaptcha-sdk-node/0.1.0 Sent as User-Agent

API

Sync solve

const result = await client.solve({
  type: 'recaptcha_v2',
  params: { url, sitekey },
  idempotencyKey: '...optional UUID...', // safe retries within 5 minutes
  timeout: 60,                            // optional per-call seconds
});

Result fields (depend on captcha type):

  • type, status: 'ready'
  • token — token-based widgets (reCAPTCHA, Turnstile, FunCaptcha, …)
  • text — image OCR
  • coordinates — image-to-coordinates
  • cookies — Amazon WAF / DataDome
  • userAgent — when the provider returns one
  • cost — USD charged to your balance for this call
  • balanceRemaining — your account balance after the operation
  • rateLimit{ limit, remaining, reset }

Per-type helpers

One per captcha type — sugar around solve():

client.solveImageToText({ body })
client.solveImageToCoordinates({ body, mode: 'points' })
client.solveRecaptchaV2({ url, sitekey, invisible: false, dataSValue: '...' })
client.solveRecaptchaV2Enterprise({ url, sitekey, enterprisePayload: { s: '...' } })
client.solveRecaptchaV3({ url, sitekey, action: 'login', minScore: 0.7 })
client.solveRecaptchaV3Enterprise({ url, sitekey, action: 'login', minScore: 0.7 })
client.solveFunCaptcha({ url, publicKey, subdomain, data })
client.solveGeeTestV3({ url, gt, challenge, apiServer })
client.solveGeeTestV4({ url, captchaId, apiServer })
client.solveTurnstile({ url, sitekey, action, cData })
client.solveAmazonWaf({ url, key, iv, context, challengeScript, captchaScript })
client.solveMtCaptcha({ url, sitekey })
client.solveProsopo({ url, sitekey })
client.solveFriendlyCaptcha({ url, sitekey })

All accept an optional second argument with { idempotencyKey, timeout }.

Async submit + poll

// One call: submit + poll until ready.
const result = await client.solveAsync({
  type: 'turnstile',
  params: { url, sitekey },
});

// Or do it manually:
const submitted = await client.createTask({ type, params });
const result    = await client.waitForTask(submitted.taskRef, {
  pollInterval: 5_000,
  pollTimeout:  180_000,
});

// Single non-blocking poll:
const r = await client.getTask(submitted.taskRef);
if (r.status === 'ready') console.log(r.token);

taskRef is a self-contained signed token — no server-side session. Refs expire 5 minutes after creation, and the signature binds them to your API key, so they cannot be polled by another user.

Balance & feedback

const { balance, currency } = await client.getBalance();

await client.reportTask(taskRef, true);  // target accepted the token
await client.reportTask(taskRef, false); // target rejected the token

Report endpoints are best-effort: the gateway forwards them to providers that support feedback (reCAPTCHA family fully; image_to_text and FunCaptcha negative-only) and silently no-ops the rest.

Errors

Every public method throws OneCaptchaError on failure.

import { OneCaptchaError, ERROR_CODES } from '@onecaptcha/sdk';

try {
  await client.solve({ type: 'recaptcha_v2', params: { url, sitekey } });
} catch (err) {
  if (err instanceof OneCaptchaError) {
    err.code              // 'BALANCE_EMPTY' | 'PROVIDER_SITEKEY' | 'UNSOLVABLE' | …
    err.message           // human-readable explanation
    err.status            // HTTP status the gateway returned
    err.field             // for INPUT_* errors
    err.retryable         // boolean
    err.retryAfter        // seconds to wait
    err.balanceRemaining  // null or number
    err.rateLimit         // null or { limit, remaining, reset }
    err.raw               // raw error body from the gateway
  }
}

ERROR_CODES enumerates the codes, plus two SDK-only codes (SDK_TIMEOUT, SDK_NETWORK) for local request failures.

Billing model

The gateway uses pre-charge with selective refund: the per-captcha-type base price is debited from your balance before the provider call. On a successful solve the charge stays. On a refund-safe failure (auth, balance, input, sitekey/domain rejection, network errors, etc.) it is automatically credited back. Errors that may have consumed sub-provider worker time (UNSOLVABLE, real PROVIDER_TIMEOUT, …) are held to cover the upstream cost.

The post-operation balance is on every billing-relevant response as result.balanceRemaining (and on errors as err.balanceRemaining).

License

MIT