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

The NoneCap hCaptcha API.

A RESTful, JSON-over-HTTPS hCaptcha solver API. 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 and out, and every request carries authentication.

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. If the solve is still in flight when that window closes you get a 202 with a null token, so 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 it with the solve's user_agent as your User-Agent header. Some sites refuse a token sent from a different browser version.
  4. Report the tokens your target refuses to /v1/feedback — send the solve_id with an outcome of rejected. A token can pass hCaptcha and still be refused by your target, and this is the only signal that shows us that. Reporting accepted tokens too is optional and sharpens the read. Feedback reference

Authentication

You mint API keys in the dashboard. Format: nc_live_ + 32 base64url characters. Send it 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.
  • 402 key_credit_limit_exceeded: the key reached its optional per-key credit limit; raise or reset it on the Keys page.

Sign up in the dashboard to mint a key and claim 1,300 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 no credits remaining. Top up at https://dashboard.nonecap.com/billing.",
    "param":   null,
    "request_id": "9f1c2d3e-4b5a-4c6d-8e7f-0a1b2c3d4e5f"
  }
}

param names the offending request field for validation errors; otherwise null. request_id (also the X-Request-Id response header) is the id to quote to support.

HTTP status codes

400
BAD REQUEST
invalid_request: The request body is not a JSON object, or is not valid JSON.
401
UNAUTHORIZED
unauthorized: The Authorization header is missing or malformed, or the API key is unknown or revoked.
402
PAYMENT REQUIRED
insufficient_credits: The account does not have the 1 credit a solve needs to start. Top up on the dashboard.
402
PAYMENT REQUIRED
key_credit_limit_exceeded: This API key has reached its own credit limit. Raise or reset it on the dashboard Keys page.
403
FORBIDDEN
account_locked: The owning account is locked. Contact support.
403
FORBIDDEN
forbidden: The API key lacks the scope this endpoint needs, the field is admin-only, or requests from your network address are refused (the message says which).
404
NOT FOUND
not_eligible: Feedback names a solve that is unknown, belongs to another account, or did not end in solved.
404
NOT FOUND
not_found: No solve with that id belongs to this account (ids are private per account), or no route matches the method and path.
409
CONFLICT
conflict: The solve is already in a terminal state, so it cannot be cancelled.
413
TOO LARGE
payload_too_large: The request body exceeds the route's size limit; the message names the limit.
415
UNSUPPORTED MEDIA
unsupported_media_type: A JSON route was called without Content-Type: application/json.
422
UNPROCESSABLE
expired_window: The first feedback for this solve arrived after the reporting window closed.
422
UNPROCESSABLE
recognition_failed: The recognition endpoint does not support this puzzle yet, or found no answer for these images, and nothing was charged. Load a fresh challenge and send it again.
422
UNPROCESSABLE
validation_error: A field has a bad value; param names it.
429
RATE LIMITED
concurrency_limit_exceeded: Too many solves in flight for this account, or too many recognitions in flight on this account. Wait for one to finish (Retry-After is set) or ask support to raise the limit.
429
RATE LIMITED
proxy_unavailable: Nearly every recent solve through the proxy you supplied failed because the proxy itself refused the connection, so new submits through that proxy are shed instead of run. Fix the proxy or switch exit; one submit per Retry-After interval is let through to re-check it.
429
RATE LIMITED
rate_capped: This account has a submit rate cap on this sitekey and reached it, or your own-proxy sessions for this sitekey are at their limit: new solves for the sitekey are refused until the trailing minute has room. Wait the Retry-After seconds; nothing is charged.
429
RATE LIMITED
rate_limited: Too many requests: this account passed its per-minute recognition rate (Retry-After is set), too many extension registrations or free-tier recognitions came from this network address today, or (on POST /v1/solves) an account with no credits kept submitting, so its submits are paused for the Retry-After seconds (top up, then retry).
429
RATE LIMITED
sitekey_rate_limited: hCaptcha is refusing to serve challenges for this sitekey, or demand on it jumped and new solves for it are admitted gradually, so new submits for it are shed instead of run. Wait the Retry-After seconds; the message says which, and whether a different proxy pool can help.
500
SERVER ERROR
internal_error: Something failed on our side. The message carries a request id; quote it to support if it persists.
503
UNAVAILABLE
maintenance: New solves are paused for maintenance. Retry shortly.

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, and nothing was charged. The message differs by whether you supplied a proxy: the first sentence below is the proxied wording, the second the proxyless one.

challenge_not_loaded
retryable
hCaptcha did not serve a challenge through your proxy. This usually means the proxy's IP has poor reputation with hCaptcha. Retry with a different proxy or exit IP. This solve was not charged.
Proxyless: hCaptcha did not serve a challenge this time. Retry; if it keeps happening for this sitekey, contact support with the solve id. This solve was not charged.
token_not_granted
retryable
The challenge was answered but hCaptcha did not issue a token. If it persists, use a proxy whose IP has better reputation with hCaptcha. This solve was not charged.
Proxyless: The challenge was answered but hCaptcha did not issue a token. Retry; if it keeps happening for this sitekey, contact support with the solve id. This solve was not charged.
challenge_expired
retryable
hCaptcha expired the challenge before the solve completed. Retry the solve. This solve was not charged.
challenge_errored
retryable
hCaptcha aborted the challenge before the solve completed. Retry the solve. This solve was not charged.
proxy_error
retryable proxyless only
Your proxy could not be used: it failed to connect, or hCaptcha refused its IP. Check the proxy host and credentials, or switch to a different exit IP. This solve was not charged.
Proxyless: NoneCap's network could not reach hCaptcha this time. Retry the solve. This solve was not charged.
target_unreachable
not retryable
The target url could not be loaded. Verify it is reachable. This solve was not charged.
vision_error
retryable
The challenge was served but could not be solved this time. Retry; if it persists for one challenge type, contact support with the solve id. This solve was not charged.
internal_error
retryable
Something failed on NoneCap's side before the solve completed. Retry; if it persists, contact support with the solve id. This solve was not charged.
unsolvable_variant
not retryable
This challenge is in a format NoneCap cannot currently solve. This solve was not charged.
capacity_exhausted
retryable
NoneCap is momentarily at capacity for this challenge type. Retry in a few seconds. This solve was not charged.
cancelled
not retryable
Cancelled by the caller. This solve was not charged.
expired
retryable
Your proxy did not respond in time, so the solve reached its deadline. Check the proxy, or switch to a different exit IP. This solve was not charged.
Proxyless: The solve did not complete before its deadline. Retry; if it keeps happening for this sitekey, contact support with the solve id. This solve was not charged.
cancelled
not retryable
Cancelled by the caller. This solve was not charged.
challenge_not_loaded
When hCaptcha answered 429 before a challenge was served: hCaptcha refused to serve a challenge for this sitekey (HTTP 429, before the solve began). Three causes look identical from here: the sitekey as a whole is being limited (retry later; a different IP will not help), your IP pool is (try a different proxy pool), or the site only serves visitors from its own country (use a proxy located there, or for proxyless solves ask support to pin the exit country for this sitekey). This solve was not charged.
challenge_not_loaded
When hCaptcha rejected every challenge request for the sitekey (an unrecognised sitekey): hCaptcha rejected every challenge request for this sitekey and never served a challenge, which is what it does for a sitekey it does not recognise. Check that the sitekey is copied exactly from the site (the data-sitekey attribute, or the sitekey parameter of the hCaptcha frame on the page the url points at). This solve was not charged.
token_not_granted
When after a refused round, hCaptcha escalated the challenge to a level that has never issued a token on the sitekey: hCaptcha escalated this challenge to a level that does not issue tokens on this sitekey, so the solve was stopped early. Retry the solve. This solve was not charged.
token_not_granted
When hCaptcha kept serving a challenge whose tokens the site does not accept, through every replacement NoneCap asked for: hCaptcha kept serving a challenge whose tokens this site does not accept, so the solve was stopped before issuing a token. Retry the solve. This solve was not charged.
token_not_granted
When hCaptcha kept serving a challenge that was not issuing tokens on any sitekey, through every fresh session NoneCap opened: hCaptcha kept serving a challenge that is not issuing tokens right now, so the solve was stopped early. Retry the solve. This solve was not charged.

Solve-failure reasons

error.reason is a typed sub-reason within error.code, set when the solver knows more than the code says; null otherwise. error.retryable says whether re-submitting the same request unchanged can succeed.

sitekey_rate_limited
challenge_not_loaded
hCaptcha answered 429 before serving a challenge; the message says which of the three shapes it can be.
passive_required
token_not_granted
The sitekey is configured to pass without a challenge and did not issue a token this time.
rounds_exhausted
token_not_granted
hCaptcha kept serving new challenges without accepting an answer, so the solve was stopped.
proxy_rejected
proxy_error
Your proxy refused the connection (credentials or source IP); the message quotes its reply. Not retryable.
proxy_tls
proxy_error
Your proxy intercepts or rewrites TLS, so hCaptcha cannot be reached through it. Not retryable.
proxy_stalled
expired
Your proxy accepted the connection but did not answer within the solve deadline. Not retryable.
proxy_egress_blocked
proxy_error
Your proxy points at a private or internal network address, so no connection was attempted. Not retryable.
target_egress_blocked
target_unreachable
The target url points at a private or internal network address, so the page was never opened. Not retryable.
profile_engine_unavailable
capacity_exhausted
NoneCap could not prepare this solve on this attempt, so it was not started and nothing was charged. Retry in a few seconds.
type_not_served
internal_error
The solve could not be run and nothing was charged. Contact support with the solve id. Not retryable.
recaptcha_not_loaded
challenge_not_loaded
reCAPTCHA did not initialise on the given url for this sitekey: the key is not a v3 key or the hostname is not on its allowed domains. Not retryable.
browser_lane_capped
capacity_exhausted
Tokens for this sitekey are being reported as rejected at a high rate, so NoneCap is temporarily running fewer solves for it. This one was not started and nothing was charged. Retry after a short wait.
refused_wording_unescaped
token_not_granted
hCaptcha kept serving a challenge whose tokens this site does not accept, so the solve was stopped before a token was issued and nothing was charged.
session_capped
capacity_exhausted
NoneCap is pacing solves for this sitekey and no slot opened before the solve deadline, so it was not started and nothing was charged. Retry after a short wait.

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.

Switching from NopeCHA

Code written against NopeCHA's hCaptcha Token API runs here: use the base URL https://api.nonecap.com/compat/nopecha with your NoneCap API key (header, key body field or key query parameter). It accepts /token with type: "hcaptcha" and /v1/token/hcaptcha; other types are refused. Solves bill, rate-limit and appear in your dashboard exactly like POST /v1/solves. cookie and useragent are accepted but ignored, so a site that binds the token to a cookie session may refuse it. Balance and status are not aliased: use the dashboard or GET /v1/me.

curl https://api.nonecap.com/compat/nopecha/token \
  -H "Authorization: Bearer nc_live_••••" \
  -H "Content-Type: application/json" \
  -d '{"type": "hcaptcha", "sitekey": "…", "url": "https://example.com/login"}'
# → {"data": "solve_…"}; then GET /compat/nopecha/token?id=solve_… until it returns {"data": "P1_…"}

NopeCHA's hCaptcha recognition calls run on the same base URL: POST / with type hcaptcha or hcaptcha_area_select (their SDKs' recognize_hcaptcha and recognize_hcaptcha_area_select), and POST /v1/recognition/hcaptcha with a data challenge object. The answer is ready when the submit returns, so the first poll returns it. New code can call POST /v1/recognize directly and skip the poll.

curl https://api.nonecap.com/compat/nopecha/ \
  -H "Authorization: Bearer nc_live_••••" \
  -H "Content-Type: application/json" \
  -d '{"type": "hcaptcha", "task": "Please click each image containing a bicycle", "image_data": ["…"]}'
# → {"data": "rec_…"}; GET /compat/nopecha/?id=rec_… returns {"data": [true, false, …]} at once
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 when status = solved. Tokens expire within minutes of issue, and a solve may return null here once it is more than 7 days old.
resp_key string · nullable optional
hCaptcha's response key for the challenge behind token — the value the widget's hcaptcha.getRespKey() returns (E0_…). Sites that verify the token and key together need both. Set with token when the solve finishes and null otherwise. It is kept when an older solve's token is cleared.
user_agent string · nullable optional
The browser user agent this solve presented while it earned token. Some sites reject a token submitted by a different browser version than the one that solved it, so send the token with this string as your User-Agent header, and from the same IP as your proxy if you gave one. Set with token when the solve finishes and null otherwise, including on the rare solve where it could not be read. It is kept when an older solve's token is cleared.
error object · nullable optional
Present on failed, cancelled, and expired; null otherwise. Carries code, a customer-readable message (what happened, what to do, whether it was charged), a typed reason or null, retryable, and docs_url. 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 (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).
warnings array optional
Advisories about this solve, each { code, message }; empty when there is none. proxy_session_refused: the last token(s) you reported from this solve's proxy session were rejected (see feedback). A new proxy session (a new exit) is more likely to pass, so switch to one for your next solves. The solve still runs and bills as usual.

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: proxy, user_agent. Returns a P1_ token.
hcaptcha_enterprise captcha type optional
Required: sitekey, url. Optional: rqdata (send it whenever the site provides one), proxy, user_agent. 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: a UUID, the data-sitekey value on the page's hCaptcha widget. Anything else is refused with 422 validation_error (param: "sitekey") before a solve is created. A reCAPTCHA key (6L…) gets a message that says so.
url string required
Page URL where the challenge appears.
rqdata string optional
The rqdata value the page's own widget configuration supplies, when present. Optional for hcaptcha_enterprise too: many enterprise sitekeys issue none. When the site does provide one, send it, fresh for each challenge.
user_agent string optional
Optional. Send the user agent of the browser that loaded the page, as is. On most sites it changes nothing; on some it is required for the token to be accepted. If you do not have it, leave the field out.
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. The solve runs on our servers, so the host must be a public hostname or public IP reachable from the internet. localhost, a private address such as 127.0.0.1 or 10.0.0.5, or a bare service name from your own network (proxy-pool) cannot be reached from here: the request is answered with a 422 validation_error pointing at proxy, or the solve fails.

On enterprise sitekeys, submit the token from the same network address the solve used. Many deployments reject a token submitted from a different address as invalid-response, so pass a proxy that stays on one exit for the whole exchange: page load, solve, and submit. If you omit proxy the solve egresses from our pool rather than your address.

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.
402
PAYMENT REQUIRED
key_credit_limit_exceeded: Key hit its per-key credit limit. Raise or reset it on the Keys page.
429
TOO MANY
concurrency_limit_exceeded: Account already at its concurrency cap (5 on the free trial, 25 after $5 in purchases, 50 at $20, 100 at $100, 200 at $500). Retry once one completes.
429
TOO MANY
sitekey_rate_limited: hCaptcha is rate-limiting requests for this sitekey, or demand on it jumped and new solves are admitted gradually. Wait the Retry-After seconds; the response body says which, and whether the limit is sitekey-wide or scoped to your egress.
429
TOO MANY
proxy_unavailable: Nearly every recent solve through the proxy you supplied failed because the proxy refused the connection. Fix the proxy or switch exit; wait the Retry-After seconds.
429
TOO MANY
rate_capped: Your account has a submit rate cap on this sitekey and reached it for the trailing minute, or your own-proxy sessions for this sitekey are at their limit. Wait the Retry-After seconds; nothing is charged.
429
TOO MANY
rate_limited: The account has no credits and this client kept submitting (600 or more refused in a minute), so its submits are paused. Top up, then wait the Retry-After seconds.

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. A cancelled solve is never charged.

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 tokens your target rejected, so we can see how they actually performed and catch regressions early. Reporting accepted ones as well is optional. This is the batch endpoint: buffer your verdicts and flush up to 500 at once. There's no extra charge and no new key or scope, since it's gated on the same solve scope that created the solves, so 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, so 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, since it's the only thing you need to 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 or expired), and error (a failure that wasn't the token's fault, such as a network problem, a 5xx or maintenance) are recorded but excluded from the quality denominator.
acceptedrejectedunknownunusederror
reason string optional
Freeform downstream reason or code: whatever your target returned when it refused the token, for example invalid-response. Truncated to 512 characters. This is the field worth populating, because it's the only part of the rejection we cannot see from our side.
context string optional
Optional free text: anything about the attempt you think would help us diagnose it. There is no schema, so a status code, the response body your target returned, which proxy pool you were on or what your retry did are all fine. A human reads it when you raise a ticket; nothing parses it. Truncated to 2000 characters.
reported_at string · ISO 8601 optional
Client's instant of the downstream verdict. Advisory only: the server always stamps its own created_at and updated_at.

Rules

  • You can report your own solves only. A foreign or unknown id resolves to a per-item not_eligible.
  • Only a solve that reached solved is reportable; anything else is not_eligible.
  • The first report must land within 30 days of the solve. A late first report is expired_window, but corrections to an already-reported solve are not age-gated.
  • Reports are idempotent and last-write-wins. Reporting the same solve_id again overwrites the mutable fields (status: updated); re-sending an identical value does nothing (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 or error, and a failed item nests a bare { code, message, param } without the 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: Returned once the request is structurally valid, even if some items failed. Inspect the 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. It runs the same validation and upsert path as one Report feedback batch item, and is meant 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 and rejected count toward the acceptance rate. A rejected whose reason is a rate limit (an HTTP 429, "rate limit", "too many requests") is stored as error: your target refused the request, not the token. So is a rejected whose reason is a connection failure (a connect timeout, a reset or refused connection, a failed proxy tunnel): the request never reached a verdict.
acceptedrejectedunknownunusederror
reason string optional
Freeform downstream reason or code, e.g. the rejection message your target returned. Truncated to 512 characters.
context string optional
Optional free text: anything about the attempt you think would help us diagnose it. There is no schema, so a status code, the response body your target returned, which proxy pool you were on or what your retry did are all fine. A human reads it when you raise a ticket; nothing parses it. Truncated to 2000 characters.
reported_at string · ISO 8601 optional
Advisory verdict timestamp; the server stamps its own timestamps.

The rules match the batch endpoint: your own solves only, only solves that reached solved, a first report within 30 days, and 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 (an outcome outside the enum).
422
UNPROCESSABLE
expired_window: First report is past the 30-day window (param solve_id).
05 · recognition

Recognize a challenge

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

For callers who run their own browser or extension and only need the answer: send one hCaptcha challenge's images and instruction, get back which tiles to click, where to click, or where to drop each piece, in the same response. There is no token and no polling; your own client clicks and submits. The request and answer fields are the ones NopeCHA's recognition API uses, so an integration written for it needs only the new URL and key.

Use an API key with the solve scope. Each answered call costs a flat 5 credits, whatever the challenge type, and credits_charged in the response says what it cost. The charge is final once the answer is returned, however the challenge ends. A puzzle we do not support yet is refused with recognition_failed and not charged: load a fresh challenge and send that. Your calls and the credits they used appear on the dashboard's Analytics page.

Body: the simple form

type string · enum required
hcaptcha is the image grid (select every matching tile); hcaptcha_area_select is one image to click on.
hcaptchahcaptcha_area_select
task string required
The challenge instruction in English, as shown above the images. Up to 500 characters.
image_data array of string optional
The images, base64-encoded (a bare string or a data:image/…;base64, URI; PNG, JPEG, WebP or GIF, up to 1.5 MiB and 1 megapixel each, 12 megapixels for all of a call's images together). For hcaptcha, 1 to 27 tiles in tile order (left to right, top to bottom, page after page); for hcaptcha_area_select, exactly one image. Send this or image_urls.
image_urls array of string optional
The same images as URLs, instead of image_data. Only hCaptcha's own image URLs are fetched; send anything else as base64.
image_examples array of string optional
1 to 3 example images shown with the instruction, base64 or hCaptcha URLs. Send them when the challenge shows one: some instructions only make sense next to their example.

Body: the full form

data object optional
Instead of the fields above, the challenge object exactly as the widget received it: request_type (image_label_binary, image_label_area_select or image_drag_drop), requester_question.en, optional requester_question_example and request_config, and tasklist (1 to 27 tasks for a grid, 1 to 5 for area select and drag, each task_key and datapoint_uri, plus entities with entity_id, entity_uri, coords and size for drag challenges). Each datapoint_uri / entity_uri is base64 or an hCaptcha image URL. This form is the only one that covers drag challenges.

The answer

  • id: this recognition, for the outcome report.
  • Grid, simple form: data is one boolean per tile, true = click it. Full form: one array of up to 9 booleans per page.
  • Area select: data is { x, y, w, h } in percent of the image, with w and h 0: click at x, y. When the instruction asks for more than one click, points lists them all. Full form: one box per task, and points per task.
  • Drag: data holds, per task, where each piece goes: entity_id and its box (x, y = the piece's top-left, w, h = its size), in percent of the image. Drag its centre to x + w/2, y + h/2. Pieces to leave in place are not listed.
  • credits_charged: what this call cost.

Limits

Per account, across all its API keys: as many calls in flight as its concurrency limit, and 60 calls a minute per unit of that limit. Over either you get 429 with Retry-After; nothing is charged.

Responses

200
OK
recognition: The answer. credits_charged is what this call cost.
401
UNAUTHORIZED
unauthorized: Missing or unknown API key. Extension install keys are not accepted here.
402
PAYMENT REQUIRED
insufficient_credits: The balance does not cover one call. Nothing was charged.
413
TOO LARGE
payload_too_large: An image over 1.5 MiB decoded, or a body over 12 MiB.
422
UNPROCESSABLE
validation_error: A field is missing or malformed, an image is over 1 megapixel, or the images together are over 12; param names it.
422
UNPROCESSABLE
recognition_failed: This puzzle is not supported yet, or no answer was found for these images. Nothing was charged; load a fresh challenge.
429
RATE LIMITED
concurrency_limit_exceeded: Too many calls in flight on this account. Retry-After is set.
429
RATE LIMITED
rate_limited: Too many calls started on this account in the last minute. Retry-After is set.
05 · recognition

Report a recognition outcome

POST https://api.nonecap.com /v1/recognize/outcome

Optional. Tell us how the challenge ended after you applied the answer; we use it to track accuracy. It does not change billing: no credits are refunded for any result, so refunded_credits is always 0. The first report for an id is the one kept. An id that is not one of your recognitions is 404 not_found.

id string required
The id from the /v1/recognize response.
result string · enum required
How the challenge ended.
solvedfailed