NoneCap API · v1
Get a key →
01 · getting started

The NoneCap hCaptcha API.

A RESTful, JSON-over-HTTPS API for solving hCaptcha programmatically. Send a sitekey and the page URL; we return a real P1_ token your client submits as h-captcha-response: the same shape hCaptcha hands back after a human solves the challenge.

Base URL
api.nonecap.com/v1
Auth scheme
Bearer token
Content type
application/json
Captcha
hCaptcha

Image-recognition solvers produce low-trust tokens that hCaptcha enterprise flags within seconds. NoneCap returns a finished token that passes hCaptcha's server-side checks, so it actually authorises the request it was issued for.

All endpoints live under https://api.nonecap.com. HTTPS only. JSON in, JSON out. Authentication on every request.

Quickstart

  1. Sign in to the dashboard and mint an API key (nc_live_…).
  2. POST a solve to /v1/solves. Add ?wait=N (1-90 s) to block up to N seconds and return as soon as the solve reaches a terminal state. Still in flight when the window closes? You get 202 with a null token — poll GET /v1/solves/{id} until it's terminal.
  3. Inject the returned P1_ token into the target form's h-captcha-response field and submit.

Authentication

API keys are minted from the dashboard. Format: nc_live_ + 32 base64url characters. Send on every request:

Authorization: Bearer nc_live_a8f2K9...

Errors

  • 401 unauthorized: missing, malformed, revoked, or unknown key.
  • 402 insufficient_credits: valid key but balance < 1; only raised on calls that consume credits.

Sign up in the dashboard to mint a key and claim 100 free credits. A future nc_test_ prefix is reserved for test-mode keys.

Errors

Every non-2xx response follows the same envelope:

{
  "error": {
    "code":    "insufficient_credits",
    "message": "Your account has 0 credits remaining. Top up at https://dashboard.nonecap.com/billing.",
    "param":   null
  }
}

param names the offending request field for validation errors; otherwise null.

HTTP status codes

400
BAD REQUEST
invalid_request: Malformed JSON or missing required structural field.
401
UNAUTHORIZED
unauthorized: Missing, malformed, revoked, or unknown API key.
402
PAYMENT REQUIRED
insufficient_credits: Not enough credits to start the solve.
403
FORBIDDEN
account_locked: The owning account has been locked by an administrator.
403
FORBIDDEN
forbidden: The API key lacks the scope required for this endpoint.
404
NOT FOUND
not_found: Solve id unknown or purged after retention.
409
CONFLICT
conflict: Cancel on already-terminal solve.
422
UNPROCESSABLE
validation_error: Bad field value (unknown type, bad url, etc.).
429
RATE LIMITED
rate_limited: Too many requests; slow down.
429
RATE LIMITED
concurrency_limit_exceeded: Too many solves in flight for this account (default 5; contact support to raise). Retry once one completes.
500
SERVER ERROR
internal_error: Unexpected server error.

Solve-failure codes

These ride in Solve.error.code on a terminal, non-solved solve. status is failed, cancelled, or expired. The request succeeded; the solve didn't produce a token.

challenge_not_loaded
The hCaptcha challenge never displayed. Usually proxy/IP reputation — retry with a different proxy. When hCaptcha is rate-limiting the sitekey itself the message says so instead: that is upstream of your proxy, so retry shortly rather than switching IP.
token_not_granted
The challenge was completed but hCaptcha did not issue a token. Retry; if it persists, use a higher-quality proxy IP.
challenge_expired
hCaptcha expired the challenge before the solve completed. Retry the solve.
challenge_errored
hCaptcha aborted the challenge widget. Retry the solve.
proxy_error
The supplied proxy failed to connect or auth, or its IP was refused by hCaptcha. Fix or swap the proxy.
target_unreachable
The target url did not load. Verify it is reachable.
vision_error
The challenge rendered but the solver could not read it this time. Retry; if it persists for one challenge type, contact support.
internal_error
An unclassified internal failure in the solving pipeline. Retry; contact support if it persists.
unsolvable_variant
The challenge used an animated variant NoneCap cannot currently solve. Not billed.
cancelled
The caller cancelled the job.
expired
Solve exceeded its time budget before producing a token (never billed).

Versioning

This is v1. Breaking changes will ship under v2 with at least 12 months of v1 support.

Resource shapes are additive within a major version: new optional fields can appear at any time. Clients should ignore unknown fields rather than treating them as an error.

Pagination

List endpoints use cursor-based pagination. The cursor is the id of the last item you received; pass it as starting_after on the next request.

  • limit: 1-100, default 20.
  • starting_after: a solve_… id (exclusive cursor).
  • Responses carry has_more: boolean. There is no separate cursor field: read the last item's id.
02 · solves

The solve object

A solve represents one captcha-solving job: its parameters, the worker that picked it up, the resulting token, and how much it cost you.

Attributes

id string optional
Prefixed ULID, e.g. solve_01HQF7K3JKWZX.
object "solve" optional
Constant.
type string · enum optional
Captcha type. See Captcha types below.
hcaptchahcaptcha_enterprise
status string · enum optional
Current state. Terminal states are solved, failed, cancelled and expired.
pendingsolvingsolvedfailedcancelledexpired
sitekey string optional
Echoed from the original request.
url string optional
Echoed from the original request.
token string · nullable optional
Present iff status = solved.
error object · nullable optional
Present on failed, cancelled, and expired; null otherwise. See Errors.
credits_charged integer · nullable optional
Final billed amount. null until terminal.
proxy_bytes integer · nullable optional
Bytes that egressed through your metered proxy for this solve. null when the solve ran without a proxy.
created_at string · RFC 3339 optional
When the job was accepted.
started_at string · nullable optional
When a worker picked it up.
finished_at string · nullable optional
When the solve reached a terminal state.
queue_ms integer · nullable optional
Milliseconds spent waiting in the queue before a worker picked the solve up (started_at − created_at). For a solve that went terminal without ever being picked up — e.g. expired or cancelled while still queued — this is the full wait (finished_at − created_at). null while still pending.
resolve_ms integer · nullable optional
Milliseconds of actual solving (finished_at − started_at). null if the solve never left the queue, or hasn't finished yet. Pair with queue_ms to tell capacity (queue) from solver performance (resolve).

Lifecycle

pending → solving → solved
                  → failed
                  → expired     (exceeded time budget / reclaimed)

pending | solving → cancelled   (via DELETE)

Records are purged after a 30-day retention window; after that GET /v1/solves/{id} returns 404. That retention is separate from the expired status above.

Captcha types

hcaptcha captcha type optional
Required: sitekey, url. Optional: user_agent, proxy. Returns a P1_ token.
hcaptcha_enterprise captcha type optional
Required: sitekey, url, rqdata. Optional: user_agent, proxy. Returns a P1_ token.
recaptcha_v2 reserved optional
Reserved for future expansion.
recaptcha_v3 reserved optional
Reserved for future expansion.
cloudflare_turnstile reserved optional
Reserved for future expansion.
funcaptcha reserved optional
Reserved for future expansion.

Create a solve

POST https://api.nonecap.com /v1/solves

Submit a new captcha solve. You're charged only when a solve succeeds (the amount is metered per round and reported as credits_charged); failed, cancelled, and expired solves are never charged. Submitting requires a balance of at least 1 credit.

Body parameters

type string required
Captcha type to solve.
hcaptchahcaptcha_enterprise
sitekey string required
The sitekey hCaptcha gave you.
url string required
Page URL where the challenge appears.
rqdata string optional
Required for hcaptcha_enterprise; carries the IP-bound challenge data.
user_agent string optional
Match the user agent your real client uses.
proxy string | object optional
URL string (http://user:pass@host:port) or object form with host, port, scheme, username, password. Supported schemes: http, https, socks5, socks5h, socks4 (default http). For example socks5://user:pass@host:port.

Query parameters

wait integer optional
Block up to N seconds (1-90); return as soon as the solve reaches a terminal state.

Responses

202
ACCEPTED
pending: Async: solve is still in flight.
200
OK
terminal: Set ?wait and the solve reached a terminal state in time.
422
UNPROCESSABLE
validation_error: Malformed body or invalid field value.
402
PAYMENT REQUIRED
insufficient_credits: Balance < 1 credit.
429
TOO MANY
concurrency_limit_exceeded: Account already at its concurrency cap (default 5). Retry once one completes.

Retrieve a solve

GET https://api.nonecap.com /v1/solves/{id}

Fetch the current state of a solve by id. With ?wait=N (1-90 s), the call blocks until the solve reaches a terminal state or the wait expires.

Path parameters

id string required
Prefixed ULID of the solve, e.g. solve_01HQF7K3JKWZX.

Query parameters

wait integer optional
Block up to N seconds (1-90); return as soon as the solve reaches a terminal state.

Responses

200
OK
Terminal (solved/failed/cancelled/expired). Returns the full solve object.
202
ACCEPTED
Still pending/solving. Poll again (or use ?wait).
404
NOT FOUND
Solve id unknown or purged after the 30-day retention window.

List solves

GET https://api.nonecap.com /v1/solves

Cursor-paginated history of solves for the authenticated account. Newest first.

Query parameters

limit integer optional
Number of solves to return. Default 20, range 1-100.
starting_after string optional
Pagination cursor: id of the last solve from the previous page.
status string optional
Filter by solve status.
pendingsolvingsolvedfailedcancelledexpired
type string optional
Filter by captcha type.
hcaptchahcaptcha_enterprise

Response carries has_more: boolean. There is no separate cursor field. The cursor is the id of the last item in data.

Cancel a solve

DELETE https://api.nonecap.com /v1/solves/{id}

Cancel a pending or solving solve. Cancelled solves are never charged, so no credit is spent.

Path parameters

id string required
Prefixed ULID of the solve to cancel, e.g. solve_01HQF7K3JKWZX.

Responses

200
OK
Cancelled. Returns the solve with status: "cancelled".
409
CONFLICT
conflict: Solve already reached a terminal state and cannot be cancelled.
404
NOT FOUND
not_found: Unknown solve id.
03 · account

Account & balance

GET https://api.nonecap.com /v1/me

Returns the authenticated account plus the current credit balance. Useful for showing balance in your own dashboard or as a pre-flight before a batch.

Response

object "account" optional
Constant.
id string optional
Prefixed ULID, e.g. user_01HQ….
email string optional
Verified email on the account.
credits_balance integer optional
Available solves remaining.
created_at string · RFC 3339 optional
Account creation timestamp.
04 · feedback

Report feedback

POST https://api.nonecap.com /v1/feedback

Report the downstream accept / reject verdict for solves you've already run, so we can watch real token quality in real time and catch regressions fast. This is the primary, batch endpoint — buffer verdicts and flush up to 500 at once. There's no extra charge and no new key or scope: it's gated on the same solve scope that created the solves (your existing API key works unchanged). You can only report your own solves.

Body parameters

feedback array required
1–500 feedback items. An empty, missing, non-array, or over-cap value is a 422 validation_error on feedback. The batch is not all-or-nothing — each item is validated and upserted independently, and one bad solve_id never discards the good rows.

Feedback item

solve_id string required
The solve_... id returned by Create a solve. Must belong to you and be a solved solve. Keep this id next to the token you submit downstream — it's the only thing you retain to report the outcome later.
outcome string · enum required
The downstream verdict. Only accepted and rejected count toward the acceptance rate; unknown (verdict undetermined), unused (token never submitted / expired), and error (non-token failure — network, 5xx, maintenance) are recorded but excluded from the quality denominator.
acceptedrejectedunknownunusederror
estado boolean optional
Raw OSIPTEL signal, stored verbatim: false = accepted, true = rejected. If present it must agree with outcome (else the item is a validation_error).
reason string optional
Freeform downstream reason or code (e.g. an OSIPTEL rejection message). Truncated to 512 characters.
reported_at string · ISO 8601 optional
Client's instant of the downstream verdict. Advisory only — the server always stamps its own created_at / updated_at.

Rules

  • Own solves only. A foreign or unknown id resolves to a per-item not_eligible.
  • Solved solves only. A solve that never reached solved is not reportable (not_eligible).
  • 30-day first-report window. The first report must land within 30 days of the solve; a late first report is expired_window. Corrections to an already-reported solve are not age-gated.
  • Idempotent, last-write-wins. Reporting the same solve_id again overwrites the mutable fields (status: updated); re-sending an identical value is a no-op (status: unchanged). The first reported outcome stays immutable server-side and report_count bumps only on a real change, so verdict flips stay auditable.

Two response shapes

This batch endpoint returns the batch envelope: { object: "feedback_batch", recorded, updated, unchanged, failed, results }, where each results entry has a status of recorded | updated | unchanged | error, and a failed item nests a bare { code, message, param } (no error wrapper). The single-item alias below returns the feedback resource directly, or the standard { error: { code, message, param } } envelope on failure. Handle both.

Responses

200
OK
feedback_batch: Always returned once the request is structurally valid — even if some items failed. Inspect per-item status.
400
BAD REQUEST
invalid_request: Body is not a JSON object.
422
UNPROCESSABLE
validation_error: feedback is missing, empty, not an array, or over 500 items (param feedback).

Per-item error.code values inside a 200 batch are validation_error (bad field), not_eligible (unknown / foreign / not-solved id), or expired_window (first report past the 30-day window).

Report one solve

POST https://api.nonecap.com /v1/solves/:id/feedback

Convenience alias for reporting a single solve — the same validation and upsert path as one Report feedback batch item, for low-volume callers and interactive testing. The solve_id comes from the path, so the body is just the item fields (no feedback wrapper). High-volume integrations should use the batch endpoint above.

Body parameters

outcome string · enum required
The downstream verdict. Only accepted / rejected count toward the acceptance rate.
acceptedrejectedunknownunusederror
estado boolean optional
Raw OSIPTEL signal (false = accepted, true = rejected). Must agree with outcome.
reason string optional
Freeform downstream reason, truncated to 512 characters.
reported_at string · ISO 8601 optional
Advisory verdict timestamp; the server stamps its own timestamps.

Same rules as the batch endpoint: own solves only, solved solves only, first report within 30 days, idempotent last-write-wins.

Responses

200
OK
feedback: The feedback resource (same shape whether recorded or updated).
400
BAD REQUEST
invalid_request: Body is not JSON.
404
NOT FOUND
not_found: Unknown id, not your solve, or not a solved solve.
422
UNPROCESSABLE
validation_error: Bad field value (invalid outcome, or estado disagrees with outcome).
422
UNPROCESSABLE
expired_window: First report is past the 30-day window (param solve_id).