{
  "openapi": "3.1.0",
  "info": {
    "title": "Captcha OCR API",
    "summary": "Solve numeric and arithmetic captchas (also alphanumeric and Hindi-number). ₹25 per 1,000; pay only for reliable answers.",
    "description": "Send a captcha image, get back the text to type, a confidence score, and a `reliable` flag\nthat says whether it is worth submitting.\n\n**Two ways to call it.**\n\n- *Call and wait:* `POST /v1/solve` returns the answer in the same request, in about 25 ms\n  for text and 6 ms for math captchas. `POST /v1/solve_batch` does up to 256 at once.\n- *Submit, then fetch:* `POST /v1/submit` returns a task `id` immediately and solves the captcha\n  in the background. `GET /v1/result/{id}` returns `processing`, then `ready` with the answer.\n  Add `?wait=10` to hold the request until the answer is ready (up to 30 s) instead of polling.\n  Results are kept 48 hours.\n\n| Options | Engine | Reads |\n|---|---|---|\n| (default), or `numeric: true` | `ocr` | numeric codes (`482915`) and alphanumeric text |\n| `math: true` | `math` | arithmetic captchas (`14 + 9 = ?` → `23`) |\n| `math: true, hindi: true` | `hindi_math` | Hindi number words (`इकतीस + 6 = ?`); returns the answer |\n\n**Pricing.** ₹25 per 1,000 solves (packs from ₹100), and only answers with `reliable: true`\nare charged. Unreadable images and low-confidence reads are free.\n\n**Balance and alerts.** `GET /v1/balance` returns your credits. Set one low-balance alert with\n`PUT /v1/alert`: when your credits drop below its threshold, we POST your JSON payload to your URL.\n\n**Authentication.** `Authorization: Bearer <API key>` (or `X-API-Key: <API key>`). Create keys on\nthe dashboard.\n\n# Quickstart\n\n1. Sign up on the website. New accounts get **500 free credits**.\n2. Create an API key on the dashboard (**API keys → New key**). The key is shown once.\n3. Send a captcha:\n\n```bash\ncurl -s https://captchaocr.allvoraz.com/v1/solve \\\n  -H \"Authorization: Bearer $CAPTCHA_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d \"{\\\"image\\\": \\\"$(base64 < captcha.png | tr -d '\\n')\\\", \\\"numeric\\\": true, \\\"length\\\": 6}\"\n# {\"text\":\"482915\",\"confidence\":0.99,\"reliable\":true,\"engine\":\"ocr\",\"raw\":\"482915\",\n#  \"expression\":null,\"error\":null,\"id\":184467,\"charged\":true}\n```\n\nOfficial SDKs: Python, TypeScript/JavaScript, Go, Java, Kotlin, C#, PHP, Ruby, Rust, Swift and Dart.\nEvery operation below shows each language's call.\n\n# Two ways to call\n\n| | Call and wait | Submit, then fetch |\n|---|---|---|\n| Endpoints | `POST /v1/solve` (or `/v1/solve_batch`) | `POST /v1/submit`, then `GET /v1/result/{id}` |\n| First response | the answer | `{\"id\": 184467, \"status\": \"processing\"}`, at once |\n| Use it when | you need the answer to continue (most form fills) | you queue captchas, or your HTTP client must not block |\n\nBoth take the same body and options, cost the same, and return the same answer object.\n\n**Submit, then fetch.** `POST /v1/submit` reserves a credit, stores the task, and returns its\n`id` with HTTP 202 before solving. The captcha is solved in the background, usually within\n0.1 s. `GET /v1/result/{id}` returns:\n\n| `status` | Meaning |\n|---|---|\n| `processing` | Not done yet. Ask again in ~0.5 s, or pass `?wait=10`. |\n| `ready` | `result` holds the answer (same fields as `/v1/solve`). Check `result.reliable`. |\n| `failed` | The solver couldn't run. `error` says why; the credit was returned. Submit again. |\n\n`?wait=N` (0-30) holds the request until the task finishes or N seconds pass, so one request\nusually returns the answer without a polling loop. Results are kept 48 hours; another key's\ntask ids return 404. A key may have up to 256 unfinished tasks (429 beyond that).\n\n```bash\ncurl -s https://captchaocr.allvoraz.com/v1/submit -H \"Authorization: Bearer $CAPTCHA_API_KEY\" \\\n  -H 'Content-Type: application/json' -d '{\"image\": \"<base64>\", \"numeric\": true, \"length\": 6}'\n# {\"id\": 184467, \"status\": \"processing\"}\ncurl -s \"https://captchaocr.allvoraz.com/v1/result/184467?wait=10\" -H \"Authorization: Bearer $CAPTCHA_API_KEY\"\n# {\"id\": 184467, \"status\": \"ready\", \"result\": {\"text\": \"482915\", \"reliable\": true, ...}, \"error\": null}\n```\n# Authentication\n\nSend your API key with every request, either as `Authorization: Bearer <key>` or as `X-API-Key: <key>`.\nKeys are created and revoked on the dashboard. A revoked key stops working within 30 seconds.\nKeep keys on your server: anyone holding a key can spend its credits.\n\n# Pricing and billing\n\n- **1 credit = 1 reliable answer.** A captcha costs a credit only when the response has\n  `reliable: true`. Undecodable images (`error`) and low-confidence reads are returned free.\n- Credits are prepaid in packs (₹100, ₹1,000, ₹5,000) by card, UPI (Google Pay, PhonePe, Paytm)\n  or netbanking. They work out to ₹25, ₹22 and ₹20 per 1,000 solves.\n- Every response carries an `X-Credits-Remaining` header. `GET /v1/balance` returns the balance.\n- A request needs enough credits for all of its images up front (`402 insufficient_credits`\n  otherwise). The uncharged ones are returned before the response is sent; for `/v1/submit`,\n  when the task finishes.\n\n# Choosing options\n\nDescribe the captcha, not the answer you want. Each option you set removes wrong readings\nthe model could otherwise make.\n\n| Captcha looks like | Send |\n|---|---|\n| `482915`, always 6 digits | `numeric: true, length: 6` |\n| `14 + 9 = ?` (answer: 23) | `math: true` |\n| `PUKLX8`, capitals and digits | `uppercase: true, numeric: true` |\n| `hyi5ag`, site ignores case | `lowercase: true, numeric: true` |\n| `7rX2Yx`, mixed case, case matters | nothing (case is kept as read) |\n| `बयालीस - 6 = ?` (answer: 36) | `math: true, hindi: true` |\n\n- `numeric` alone also turns look-alike letters into digits (`O` → `0`, `l` → `1`, `S` → `5`).\n- `uppercase` or `lowercase` alone folds the other case into it, and turns look-alike digits\n  into letters (`0` → `O`).\n- `length` is enforced by the decoder: it returns the most likely reading of exactly that many\n  characters. Set it whenever the site's captchas have a fixed length.\n- `math` returns the computed answer in `text` and the expression it computed in `expression`.\n\n# Acting on the result\n\n```\nif result.error:          the image couldn't be decoded (not charged): re-download it\nelif result.reliable:     submit result.text (charged)\nelse:                     refresh the captcha and solve the new one (not charged)\n```\n\n`confidence` is the probability of the least certain character. `reliable` combines it with\nengine-specific checks: the length matched, a math answer is non-negative, a Hindi number\nword was read exactly.\n\n# Balance and low-balance alert\n\n`GET /v1/balance` returns `{\"credits\": N, \"alert_threshold\": T}` (`alert_threshold` is null without\nan alert). Every solve response also carries the balance in the `X-Credits-Remaining` header.\n\nEach account can have **one low-balance alert**. When a solve leaves your credits below its\n`threshold`, we POST your JSON `payload` to your `url`, so your team hears about it before\ncaptchas start failing with 402.\n\n```bash\ncurl -s -X PUT https://captchaocr.allvoraz.com/v1/alert -H \"Authorization: Bearer $CAPTCHA_API_KEY\" \\\n  -H 'Content-Type: application/json' -d '{\n    \"threshold\": 500,\n    \"url\": \"https://hooks.example.org/captcha-credits\",\n    \"payload\": {\"text\": \"Captcha credits low: {{credits}} left (alert at {{threshold}})\"},\n    \"headers\": {\"Authorization\": \"Bearer my-hook-secret\"}\n  }'\n```\n\n| Field | Meaning |\n|---|---|\n| `threshold` | Fire when credits drop below this (1 or more). |\n| `url` | Your HTTPS endpoint. It must resolve to a public address. |\n| `payload` | Optional JSON object, up to 8 KB. In strings, `{{credits}}`, `{{threshold}}` and `{{time}}` are filled in; a value that is exactly `\"{{credits}}\"` becomes a number. Default: `{\"event\": \"low_balance\", \"credits\": N, \"threshold\": T}`. |\n| `headers` | Optional, up to 10, e.g. `Authorization` so your endpoint can check the call is ours. |\n\nHow it behaves:\n\n- It fires **once** per drop below the threshold, then `armed` becomes false. Buying credits\n  that bring the balance back to the threshold or above re-arms it.\n- We POST with `Content-Type: application/json` and `X-CaptchaOCR-Event: low_balance`, and treat\n  any 2xx as delivered. Otherwise we retry after 10 s and 60 s. Redirects are not followed.\n- `PUT /v1/alert` replaces your alert and arms it. `GET /v1/alert` shows it with the last\n  delivery (`last_fired_at`, `last_status`, `last_error`). `DELETE /v1/alert` removes it.\n- `POST /v1/alert/test` sends it right now with your current balance and returns\n  `{\"delivered\": true, \"status\": 200, \"error\": null}`, without changing `armed`.\n\n# Wrong answers and refunds\n\nIf a site rejects an answer that was `reliable`, call `POST /v1/report` with the answer's `id` (from\n`/v1/solve`, or the task id from `/v1/submit`)\nwithin 48 hours, and the credit is returned. Refunds per day are capped at 10% of that day's\ncharged solves (plus 5).\n\n# Batches\n\n`POST /v1/solve_batch` takes up to 256 images, solves them in parallel, and returns results in\nrequest order. The top-level options apply to every image. An item can override any of them:\n\n```json\n{\n  \"numeric\": true,\n  \"images\": [\n    {\"image\": \"<base64>\"},\n    {\"image\": \"<base64>\", \"length\": 5},\n    {\"image\": \"<base64>\", \"math\": true}\n  ]\n}\n```\n\nA plain base64 string works as shorthand for `{\"image\": \"<base64>\"}`. A bad image fails only its\nown slot.\n\n# Errors\n\n| Status | Body | What to do |\n|---|---|---|\n| 200 with `error: \"invalid_image\"` | `Solved` | The image can't be decoded. Not charged. Re-download it. |\n| 401 | `{\"detail\": \"invalid_api_key\"}` | Check the key; it may have been revoked. |\n| 402 | `{\"detail\": \"insufficient_credits\", \"credits\": N}` | Buy credits on the dashboard. |\n| 422 | `HTTPValidationError` | Invalid options (unknown field, `hindi` without `math`, `length` outside 1-32, >256 images). Fix the request; don't retry. |\n| 404 | `{\"detail\": \"unknown_task\"}` / `\"no_alert\"` | `/v1/result`: no such task for this key, or older than 48 hours. `/v1/alert`: none set. |\n| 429 | `{\"detail\": \"too_many_concurrent_requests\"}` | More than 32 requests in flight (or 256 unfinished submitted tasks) on one key. Retry after `Retry-After`. |\n| 503 | `{\"detail\": \"solver_unavailable\"}` | Temporary. Retry with backoff. Credits were returned. |\n\n# Task API\n\nBesides `/v1`, the API offers task-style endpoints for normal (image) captchas, the\n`createTask` / `getTaskResult` shape many captcha integrations already use. Point such a client\nat this API's host and send your key as `clientKey`.\n\n| Endpoint / field | Behaviour |\n|---|---|\n| `POST /createTask` with `ImageToTextTask` | returns a `taskId` at once; solved in the background |\n| `POST /getTaskResult` | `status: \"processing\"`, then `\"ready\"` (usually within 0.1 s) |\n| `POST /getBalance` | `balance` is in credits |\n| `POST /reportIncorrect` / `reportCorrect` | refunds as above |\n| `numeric` 1 / 2 | digits only / letters only |\n| `minLength` = `maxLength` | exact `length` |\n| `math: true` | arithmetic; add `\"languagePool\": \"hi\"` (or `task.hindi: true`) for Hindi number words |\n\nLow-confidence reads come back as `ERROR_CAPTCHA_UNSOLVABLE` and are not charged.\n\n# Limits\n\n- About 25 ms per text captcha and 6 ms per math captcha, plus network time.\n- Up to 32 concurrent requests per key, 256 unfinished submitted tasks per key, 256 images per\n  batch, 5 MB per image.\n- Reuse one SDK client (HTTP keep-alive) rather than creating one per call.\n\n# Versioning\n\nThe API and every SDK share one semantic version. Adding fields is a minor release, and clients\nmust ignore unknown response fields. Removing or renaming a field is a major release.\n",
    "version": "1.0.0",
    "contact": {
      "name": "Allvoraz",
      "url": "https://captchaocr.allvoraz.com"
    }
  },
  "servers": [
    {
      "url": "https://captchaocr.allvoraz.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/v1/solve": {
      "post": {
        "tags": [
          "solve"
        ],
        "summary": "Solve one captcha",
        "description": "Read one captcha. Check `reliable` before submitting the answer: only reliable answers are\ncharged, and the others are returned free so you can decide.",
        "operationId": "solve",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SolveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Solved"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits; `credits` is the current balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "429": {
            "description": "Too many concurrent requests for this key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -s https://captchaocr.allvoraz.com/v1/solve \\\n  -H \"Authorization: Bearer $CAPTCHA_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d \"{\\\"image\\\": \\\"$(base64 < captcha.png | tr -d '\\n')\\\", \\\"numeric\\\": true, \\\"length\\\": 6}\""
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "import base64, os\nimport captcha_ocr\nfrom captcha_ocr import SolveRequest\n\nconfig = captcha_ocr.Configuration(\n    host=\"https://captchaocr.allvoraz.com\",\n    access_token=os.environ[\"CAPTCHA_API_KEY\"],\n)\nclient = captcha_ocr.ApiClient(config)          # reuse it: keeps connections open\nsolver = captcha_ocr.SolveApi(client)\n\nimage = base64.b64encode(open(\"captcha.png\", \"rb\").read()).decode()\nres = solver.solve(SolveRequest(image=image, numeric=True, length=6))\nif res.reliable:\n    print(res.text)          # submit it (1 credit)\nelse:\n    print(\"refresh the captcha\")  # not charged"
          },
          {
            "lang": "TypeScript",
            "label": "TypeScript",
            "source": "import { readFileSync } from \"node:fs\";\nimport { Configuration, SolveApi } from \"@allvoraz/captcha-ocr\";\n\nconst config = new Configuration({\n  basePath: \"https://captchaocr.allvoraz.com\",\n  accessToken: process.env.CAPTCHA_API_KEY,\n});\nconst solver = new SolveApi(config);\n\nconst image = readFileSync(\"captcha.png\").toString(\"base64\");\nconst res = await solver.solve({ solveRequest: { image, numeric: true, length: 6 } });\nconsole.log(res.reliable ? res.text : \"refresh the captcha\"); // only reliable answers are charged"
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "import (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"os\"\n\n\tcaptchaocr \"github.com/allvoraz/captcha-ocr-sdks/go\"\n)\n\ncfg := captchaocr.NewConfiguration()\ncfg.Servers = captchaocr.ServerConfigurations{{URL: \"https://captchaocr.allvoraz.com\"}}\nclient := captchaocr.NewAPIClient(cfg)\n// The API key travels in the context.\nctx := context.WithValue(context.Background(), captchaocr.ContextAccessToken, os.Getenv(\"CAPTCHA_API_KEY\"))\n\ndata, _ := os.ReadFile(\"captcha.png\")\nreq := captchaocr.NewSolveRequest(base64.StdEncoding.EncodeToString(data))\nreq.SetNumeric(true)\nreq.SetLength(6)\n\nres, _, err := client.SolveAPI.Solve(ctx).SolveRequest(*req).Execute()\nif err != nil {\n\tpanic(err)\n}\nif res.GetReliable() {\n\tfmt.Println(res.GetText()) // only reliable answers are charged\n}"
          },
          {
            "lang": "Java",
            "label": "Java",
            "source": "import com.allvoraz.captchaocr.ApiClient;\nimport com.allvoraz.captchaocr.api.SolveApi;\nimport com.allvoraz.captchaocr.model.SolveRequest;\nimport com.allvoraz.captchaocr.model.Solved;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Base64;\n\nString key = System.getenv(\"CAPTCHA_API_KEY\");\nApiClient client = new ApiClient()\n    .setScheme(\"https\").setHost(\"captchaocr.allvoraz.com\").setPort(443)\n    .setRequestInterceptor(request -> request.header(\"Authorization\", \"Bearer \" + key));\nSolveApi solver = new SolveApi(client);\n\nString image = Base64.getEncoder().encodeToString(Files.readAllBytes(Path.of(\"captcha.png\")));\nSolved res = solver.solve(new SolveRequest().image(image).numeric(true).length(6));\nif (res.getReliable()) {\n    System.out.println(res.getText()); // only reliable answers are charged\n}"
          },
          {
            "lang": "Kotlin",
            "label": "Kotlin",
            "source": "import com.allvoraz.captchaocr.apis.SolveApi\nimport com.allvoraz.captchaocr.infrastructure.ApiClient\nimport com.allvoraz.captchaocr.models.SolveRequest\nimport java.io.File\nimport java.util.Base64\n\nApiClient.accessToken = System.getenv(\"CAPTCHA_API_KEY\") // sent as \"Authorization: Bearer <key>\"\nval solver = SolveApi(\"https://captchaocr.allvoraz.com\")\n\nval image = Base64.getEncoder().encodeToString(File(\"captcha.png\").readBytes())\nval res = solver.solve(SolveRequest(image = image, numeric = true, length = 6))\nif (res.reliable == true) println(res.text) // only reliable answers are charged"
          },
          {
            "lang": "C#",
            "label": "C#",
            "source": "using Allvoraz.CaptchaOcr.Api;\nusing Allvoraz.CaptchaOcr.Client;\nusing Allvoraz.CaptchaOcr.Model;\n\nvar config = new Configuration\n{\n    BasePath = \"https://captchaocr.allvoraz.com\",\n    AccessToken = Environment.GetEnvironmentVariable(\"CAPTCHA_API_KEY\"),\n};\nvar solver = new SolveApi(config);\n\nvar image = Convert.ToBase64String(File.ReadAllBytes(\"captcha.png\"));\nvar res = await solver.SolveAsync(new SolveRequest(image: image, numeric: true, length: 6));\nif (res.Reliable) Console.WriteLine(res.Text); // only reliable answers are charged"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php\nrequire 'vendor/autoload.php';\n\nuse Allvoraz\\CaptchaOcr\\Api\\SolveApi;\nuse Allvoraz\\CaptchaOcr\\Configuration;\nuse Allvoraz\\CaptchaOcr\\Model\\SolveRequest;\n\n$config = Configuration::getDefaultConfiguration()\n    ->setHost('https://captchaocr.allvoraz.com')\n    ->setAccessToken(getenv('CAPTCHA_API_KEY'));\n$solver = new SolveApi(new GuzzleHttp\\Client(), $config);\n\n$image = base64_encode(file_get_contents('captcha.png'));\n$res = $solver->solve(new SolveRequest(['image' => $image, 'numeric' => true, 'length' => 6]));\nif ($res->getReliable()) {\n    echo $res->getText(), PHP_EOL; // only reliable answers are charged\n}"
          },
          {
            "lang": "Ruby",
            "label": "Ruby",
            "source": "require 'captcha_ocr'\n\nCaptchaOcr.configure do |c|\n  c.scheme = 'https'\n  c.host = 'captchaocr.allvoraz.com'\n  c.access_token = ENV.fetch('CAPTCHA_API_KEY')\nend\nsolver = CaptchaOcr::SolveApi.new\n\nimage = [File.binread('captcha.png')].pack('m0') # base64\nres = solver.solve(CaptchaOcr::SolveRequest.new(image: image, numeric: true, length: 6))\nputs res.text if res.reliable # only reliable answers are charged"
          },
          {
            "lang": "Rust",
            "label": "Rust",
            "source": "use base64::{engine::general_purpose::STANDARD, Engine as _};\nuse captcha_ocr::apis::{configuration::Configuration, solve_api};\nuse captcha_ocr::models::SolveRequest;\n\nlet mut config = Configuration::new();\nconfig.base_path = \"https://captchaocr.allvoraz.com\".into();\nconfig.bearer_access_token = Some(std::env::var(\"CAPTCHA_API_KEY\")?);\n\nlet mut req = SolveRequest::new(STANDARD.encode(std::fs::read(\"captcha.png\")?));\nreq.numeric = Some(true);\nreq.length = Some(Some(6)); // nullable fields are Option<Option<T>>\n\nlet res = solve_api::solve(&config, req).await?;\nif res.reliable == Some(true) {\n    println!(\"{}\", res.text.unwrap_or_default()); // only reliable answers are charged\n}"
          },
          {
            "lang": "Swift",
            "label": "Swift",
            "source": "import CaptchaOcr\nimport Foundation\n\nlet config = CaptchaOcrAPIConfiguration.shared\nconfig.basePath = \"https://captchaocr.allvoraz.com\"\nconfig.customHeaders[\"Authorization\"] = \"Bearer \\(ProcessInfo.processInfo.environment[\"CAPTCHA_API_KEY\"] ?? \"\")\"\n\nlet image = try Data(contentsOf: URL(fileURLWithPath: \"captcha.png\")).base64EncodedString()\n// Swift labels follow declaration order: options first, image last.\nlet res = try await SolveAPI.solve(solveRequest: SolveRequest(numeric: true, length: 6, image: image))\nif res.reliable == true { print(res.text ?? \"\") } // only reliable answers are charged"
          },
          {
            "lang": "Dart",
            "label": "Dart",
            "source": "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:captcha_ocr/api.dart';\n\nfinal client = ApiClient(\n  basePath: 'https://captchaocr.allvoraz.com',\n  authentication: HttpBearerAuth()..accessToken = Platform.environment['CAPTCHA_API_KEY'],\n);\nfinal solver = SolveApi(client);\n\nfinal image = base64Encode(File('captcha.png').readAsBytesSync());\nfinal res = (await solver.solve(SolveRequest(image: image, numeric: true, length: 6)))!;\nif (res.reliable) print(res.text); // only reliable answers are charged"
          }
        ]
      }
    },
    "/v1/solve_batch": {
      "post": {
        "tags": [
          "solve"
        ],
        "summary": "Solve many captchas",
        "description": "Up to 256 images in parallel; top-level options apply to every image and each item may override\nthem. Credits for every image are reserved first (402 if the balance can't cover the batch), then\nthe unreliable ones are returned.",
        "operationId": "solveBatch",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SolvedBatch"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits; `credits` is the current balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "429": {
            "description": "Too many concurrent requests for this key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "b64() { base64 < \"$1\" | tr -d '\\n'; }\ncurl -s https://captchaocr.allvoraz.com/v1/solve_batch \\\n  -H \"Authorization: Bearer $CAPTCHA_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d \"{\\\"numeric\\\": true, \\\"images\\\": [\n        {\\\"image\\\": \\\"$(b64 a.png)\\\"},\n        {\\\"image\\\": \\\"$(b64 b.png)\\\", \\\"length\\\": 5},\n        {\\\"image\\\": \\\"$(b64 sum.png)\\\", \\\"math\\\": true}\n      ]}\""
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "import base64\nimport captcha_ocr\nfrom captcha_ocr import BatchItem, BatchRequest\n\ndef b64(path):\n    return base64.b64encode(open(path, \"rb\").read()).decode()\n\nconfig = captcha_ocr.Configuration(host=\"http://localhost:8080\")\nwith captcha_ocr.ApiClient(config) as client:\n    batch = captcha_ocr.SolveApi(client).solve_batch(BatchRequest(\n        numeric=True,                                      # shared by every image\n        images=[\n            BatchItem(image=b64(\"a.png\")),\n            BatchItem(image=b64(\"b.png\"), length=5),       # per-image override\n            BatchItem(image=b64(\"sum.png\"), math=True),\n        ],\n    ))\n    for r in batch.results:                                # same order as the request\n        print(r.text if r.reliable else f\"refresh ({r.error or 'unsure'})\")"
          },
          {
            "lang": "TypeScript",
            "label": "TypeScript",
            "source": "import { readFileSync } from \"node:fs\";\nimport { Configuration, SolveApi } from \"@allvoraz/captcha-ocr\";\n\nconst solver = new SolveApi(new Configuration({ basePath: \"http://localhost:8080\" }));\nconst b64 = (path: string) => readFileSync(path).toString(\"base64\");\n\nconst batch = await solver.solveBatch({\n  batchRequest: {\n    numeric: true, // shared by every image\n    images: [\n      { image: b64(\"a.png\") },\n      { image: b64(\"b.png\"), length: 5 }, // per-image override\n      { image: b64(\"sum.png\"), math: true },\n    ],\n  },\n});\nfor (const r of batch.results) console.log(r.reliable ? r.text : `refresh (${r.error ?? \"unsure\"})`);"
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "b64 := func(path string) string {\n\tdata, _ := os.ReadFile(path)\n\treturn base64.StdEncoding.EncodeToString(data)\n}\n\na := captchaocr.NewBatchItem(b64(\"a.png\"))\nb := captchaocr.NewBatchItem(b64(\"b.png\"))\nb.SetLength(5) // per-image override\nsum := captchaocr.NewBatchItem(b64(\"sum.png\"))\nsum.SetMath(true)\n\nreq := captchaocr.NewBatchRequest([]captchaocr.BatchItem{*a, *b, *sum})\nreq.SetNumeric(true) // shared by every image\n\nbatch, _, err := client.SolveAPI.SolveBatch(ctx).BatchRequest(*req).Execute() // ctx carries the API key\nif err != nil {\n\tpanic(err)\n}\nfor _, r := range batch.Results { // same order as the request\n\tfmt.Println(r.GetText(), r.GetReliable())\n}"
          },
          {
            "lang": "Java",
            "label": "Java",
            "source": "SolvedBatch batch = solver.solveBatch(new BatchRequest()\n    .numeric(true)                                                // shared by every image\n    .addImagesItem(new BatchItem().image(b64(\"a.png\")))\n    .addImagesItem(new BatchItem().image(b64(\"b.png\")).length(5)) // per-image override\n    .addImagesItem(new BatchItem().image(b64(\"sum.png\")).math(true)));\n\nfor (Solved r : batch.getResults()) {                             // same order as the request\n    System.out.println(r.getReliable() ? r.getText() : \"refresh\");\n}"
          },
          {
            "lang": "Kotlin",
            "label": "Kotlin",
            "source": "val batch = solver.solveBatch(\n    BatchRequest(\n        numeric = true, // shared by every image\n        images = listOf(\n            BatchItem(image = b64(\"a.png\")),\n            BatchItem(image = b64(\"b.png\"), length = 5), // per-image override\n            BatchItem(image = b64(\"sum.png\"), math = true),\n        ),\n    ),\n)\nbatch.results.forEach { println(if (it.reliable == true) it.text else \"refresh\") }"
          },
          {
            "lang": "C#",
            "label": "C#",
            "source": "var batch = await solver.SolveBatchAsync(new BatchRequest(\n    numeric: true, // shared by every image\n    images: new List<BatchItem>\n    {\n        new(image: B64(\"a.png\")),\n        new(image: B64(\"b.png\"), length: 5), // per-image override\n        new(image: B64(\"sum.png\"), math: true),\n    }));\n\nforeach (var r in batch.Results) // same order as the request\n    Console.WriteLine(r.Reliable ? r.Text : \"refresh\");"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php\nuse Allvoraz\\CaptchaOcr\\Model\\BatchItem;\nuse Allvoraz\\CaptchaOcr\\Model\\BatchRequest;\n\n$batch = $solver->solveBatch(new BatchRequest([\n    'numeric' => true, // shared by every image\n    'images' => [\n        new BatchItem(['image' => b64('a.png')]),\n        new BatchItem(['image' => b64('b.png'), 'length' => 5]), // per-image override\n        new BatchItem(['image' => b64('sum.png'), 'math' => true]),\n    ],\n]));\nforeach ($batch->getResults() as $r) { // same order as the request\n    echo $r->getReliable() ? $r->getText() : 'refresh', PHP_EOL;\n}"
          },
          {
            "lang": "Ruby",
            "label": "Ruby",
            "source": "batch = solver.solve_batch(CaptchaOcr::BatchRequest.new(\n  numeric: true, # shared by every image\n  images: [\n    CaptchaOcr::BatchItem.new(image: b64('a.png')),\n    CaptchaOcr::BatchItem.new(image: b64('b.png'), length: 5), # per-image override\n    CaptchaOcr::BatchItem.new(image: b64('sum.png'), math: true)\n  ]\n))\nbatch.results.each { |r| puts(r.reliable ? r.text : 'refresh') } # same order as the request"
          },
          {
            "lang": "Rust",
            "label": "Rust",
            "source": "use captcha_ocr::models::{BatchItem, BatchRequest};\n\nlet a = BatchItem::new(b64(\"a.png\"));\nlet mut b = BatchItem::new(b64(\"b.png\"));\nb.length = Some(Some(5)); // per-image override\nlet mut sum = BatchItem::new(b64(\"sum.png\"));\nsum.math = Some(Some(true));\n\nlet mut req = BatchRequest::new(vec![a, b, sum]);\nreq.numeric = Some(true); // shared by every image\n\nlet batch = solve_api::solve_batch(&config, req).await?;\nfor r in batch.results { // same order as the request\n    println!(\"{:?} reliable={:?}\", r.text, r.reliable);\n}"
          },
          {
            "lang": "Swift",
            "label": "Swift",
            "source": "let batch = try await SolveAPI.solveBatch(batchRequest: BatchRequest(\n    numeric: true, // shared by every image\n    images: [\n        BatchItem(image: try b64(\"a.png\")),\n        BatchItem(image: try b64(\"b.png\"), length: 5), // per-image override\n        BatchItem(image: try b64(\"sum.png\"), math: true),\n    ]\n))\nfor r in batch.results { // same order as the request\n    print(r.reliable == true ? r.text ?? \"\" : \"refresh\")\n}"
          },
          {
            "lang": "Dart",
            "label": "Dart",
            "source": "final batch = (await solver.solveBatch(BatchRequest(\n  numeric: true, // shared by every image\n  images: [\n    BatchItem(image: b64('a.png')),\n    BatchItem(image: b64('b.png'), length: 5), // per-image override\n    BatchItem(image: b64('sum.png'), math: true),\n  ],\n)))!;\nfor (final r in batch.results) {\n  print(r.reliable ? r.text : 'refresh'); // same order as the request\n}"
          }
        ]
      }
    },
    "/v1/submit": {
      "post": {
        "tags": [
          "solve"
        ],
        "summary": "Submit a captcha (background)",
        "description": "Same body as /v1/solve, but returns a task `id` at once and solves in the background. Get the\nanswer with `GET /v1/result/{id}`. A credit is reserved now (402 if there is none) and returned\nif the answer turns out unreliable or the task fails. Up to 256 unfinished tasks per key (429).",
        "operationId": "submit",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SolveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Submitted"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits; `credits` is the current balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "429": {
            "description": "Too many concurrent requests for this key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "# Returns at once with a task id; the captcha is solved in the background.\ncurl -s https://captchaocr.allvoraz.com/v1/submit -H \"Authorization: Bearer $CAPTCHA_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d \"{\\\"image\\\": \\\"$(base64 < captcha.png | tr -d '\\n')\\\", \\\"numeric\\\": true, \\\"length\\\": 6}\"\n# {\"id\": 184467, \"status\": \"processing\"}\n\n# Fetch the answer; wait=10 holds the request until it's ready (up to 10 s).\ncurl -s \"https://captchaocr.allvoraz.com/v1/result/184467?wait=10\" -H \"Authorization: Bearer $CAPTCHA_API_KEY\"\n# {\"id\": 184467, \"status\": \"ready\", \"result\": {\"text\": \"482915\", \"reliable\": true, ...}, \"error\": null}"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "# Submit: returns a task id at once, the captcha is solved in the background.\ntask = solver.submit(SolveRequest(image=image, numeric=True, length=6))\n\n# ... do other work ...\n\nr = solver.get_result(task.id, wait=10)  # waits up to 10 s for the answer\nif r.status == \"ready\" and r.result.reliable:\n    print(r.result.text)"
          },
          {
            "lang": "TypeScript",
            "label": "TypeScript",
            "source": "// Submit: returns a task id at once, the captcha is solved in the background.\nconst task = await solver.submit({ solveRequest: { image, numeric: true, length: 6 } });\n\n// ... do other work ...\n\nconst r = await solver.getResult({ taskId: task.id, wait: 10 }); // waits up to 10 s\nif (r.status === \"ready\" && r.result?.reliable) console.log(r.result.text);"
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "// Submit: returns a task id at once, the captcha is solved in the background.\ntask, _, err := client.SolveAPI.Submit(ctx).SolveRequest(*req).Execute()\nif err != nil {\n\tpanic(err)\n}\n\n// ... do other work ...\n\nr, _, err := client.SolveAPI.GetResult(ctx, task.GetId()).Wait(10).Execute() // waits up to 10 s\nif err != nil {\n\tpanic(err)\n}\nif answer := r.GetResult(); r.GetStatus() == \"ready\" && answer.GetReliable() {\n\tfmt.Println(answer.GetText())\n}"
          },
          {
            "lang": "Java",
            "label": "Java",
            "source": "// Submit: returns a task id at once, the captcha is solved in the background.\nSubmitted task = solver.submit(new SolveRequest().image(image).numeric(true).length(6));\n\n// ... do other work ...\n\nTaskResult r = solver.getResult(task.getId(), 10); // waits up to 10 s\nif (r.getStatus() == TaskResult.StatusEnum.READY && r.getResult().getReliable()) {\n    System.out.println(r.getResult().getText());\n}"
          },
          {
            "lang": "Kotlin",
            "label": "Kotlin",
            "source": "// Submit: returns a task id at once, the captcha is solved in the background.\nval task = solver.submit(SolveRequest(image = image, numeric = true, length = 6))\n\n// ... do other work ...\n\nval r = solver.getResult(task.id, wait = 10) // waits up to 10 s\nif (r.status == TaskResult.Status.ready && r.result?.reliable == true) println(r.result?.text)"
          },
          {
            "lang": "C#",
            "label": "C#",
            "source": "// Submit: returns a task id at once, the captcha is solved in the background.\nvar task = await solver.SubmitAsync(new SolveRequest(image: image, numeric: true, length: 6));\n\n// ... do other work ...\n\nvar r = await solver.GetResultAsync(task.Id, wait: 10); // waits up to 10 s\nif (r.Status == TaskResult.StatusEnum.Ready && r.Result.Reliable) Console.WriteLine(r.Result.Text);"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php\n// Submit: returns a task id at once, the captcha is solved in the background.\n$task = $solver->submit(new SolveRequest(['image' => $image, 'numeric' => true, 'length' => 6]));\n\n// ... do other work ...\n\n$r = $solver->getResult($task->getId(), 10); // waits up to 10 s\nif ($r->getStatus() === 'ready' && $r->getResult()->getReliable()) {\n    echo $r->getResult()->getText(), PHP_EOL;\n}"
          },
          {
            "lang": "Ruby",
            "label": "Ruby",
            "source": "# Submit: returns a task id at once, the captcha is solved in the background.\ntask = solver.submit(CaptchaOcr::SolveRequest.new(image: image, numeric: true, length: 6))\n\n# ... do other work ...\n\nr = solver.get_result(task.id, wait: 10) # waits up to 10 s\nputs r.result.text if r.status == 'ready' && r.result.reliable"
          },
          {
            "lang": "Rust",
            "label": "Rust",
            "source": "use captcha_ocr::models::task_result::Status;\n\n// Submit: returns a task id at once, the captcha is solved in the background.\nlet task = solve_api::submit(&config, req).await?;\n\n// ... do other work ...\n\nlet r = solve_api::get_result(&config, task.id, Some(10)).await?; // waits up to 10 s\nif let (Status::Ready, Some(Some(res))) = (r.status, &r.result) {\n    println!(\"{}\", res.text.clone().unwrap_or_default());\n}"
          },
          {
            "lang": "Swift",
            "label": "Swift",
            "source": "// Submit: returns a task id at once, the captcha is solved in the background.\nlet task = try await SolveAPI.submit(solveRequest: SolveRequest(numeric: true, length: 6, image: image))\n\n// ... do other work ...\n\nlet r = try await SolveAPI.getResult(taskId: task.id, wait: 10) // waits up to 10 s\nif r.status == .ready, r.result?.reliable == true { print(r.result?.text ?? \"\") }"
          },
          {
            "lang": "Dart",
            "label": "Dart",
            "source": "// Submit: returns a task id at once, the captcha is solved in the background.\nfinal task = (await solver.submit(SolveRequest(image: image, numeric: true, length: 6)))!;\n\n// ... do other work ...\n\nfinal r = (await solver.getResult(task.id, wait: 10))!; // waits up to 10 s\nif (r.status == TaskResultStatusEnum.ready && r.result!.reliable) print(r.result!.text);"
          }
        ]
      }
    },
    "/v1/result/{task_id}": {
      "get": {
        "tags": [
          "solve"
        ],
        "summary": "Get a submitted captcha's answer",
        "description": "`processing` until the captcha is solved, then `ready` with the same answer object /v1/solve\nreturns. With `wait`, the request returns as soon as the task finishes (or after `wait` seconds).",
        "operationId": "getResult",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "task_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "maximum": 9223372036854775807,
              "minimum": 0,
              "description": "The `id` from /v1/submit.",
              "format": "int64",
              "title": "Task Id"
            },
            "description": "The `id` from /v1/submit."
          },
          {
            "name": "wait",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 30,
              "minimum": 0,
              "description": "Seconds to hold the request while the task is processing (0 = answer now).",
              "default": 0,
              "title": "Wait"
            },
            "description": "Seconds to hold the request while the task is processing (0 = answer now)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskResult"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "404": {
            "description": "No such task for this key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "# Without wait: \"processing\" until the answer is ready, then \"ready\" (or \"failed\").\ncurl -s https://captchaocr.allvoraz.com/v1/result/184467 -H \"Authorization: Bearer $CAPTCHA_API_KEY\"\n# {\"id\": 184467, \"status\": \"processing\", \"result\": null, \"error\": null}"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "import time\n\n# Poll without holding the connection.\nwhile (r := solver.get_result(task.id)).status == \"processing\":\n    time.sleep(0.5)\nprint(r.status, r.result.text if r.result else r.error)"
          },
          {
            "lang": "TypeScript",
            "label": "TypeScript",
            "source": "// Poll without holding the connection.\nlet r = await solver.getResult({ taskId: task.id });\nwhile (r.status === \"processing\") {\n  await new Promise((done) => setTimeout(done, 500));\n  r = await solver.getResult({ taskId: task.id });\n}\nconsole.log(r.status, r.result?.text ?? r.error);"
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "// Poll without holding the connection.\nfor r.GetStatus() == \"processing\" {\n\ttime.Sleep(500 * time.Millisecond)\n\tr, _, err = client.SolveAPI.GetResult(ctx, task.GetId()).Execute()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\nanswer := r.GetResult()\nfmt.Println(r.GetStatus(), answer.GetText())"
          },
          {
            "lang": "Java",
            "label": "Java",
            "source": "// Poll without holding the connection (wait = null).\nTaskResult r = solver.getResult(task.getId(), null);\nwhile (r.getStatus() == TaskResult.StatusEnum.PROCESSING) {\n    Thread.sleep(500);\n    r = solver.getResult(task.getId(), null);\n}"
          },
          {
            "lang": "Kotlin",
            "label": "Kotlin",
            "source": "// Poll without holding the connection.\nvar r = solver.getResult(task.id)\nwhile (r.status == TaskResult.Status.processing) {\n    Thread.sleep(500)\n    r = solver.getResult(task.id)\n}"
          },
          {
            "lang": "C#",
            "label": "C#",
            "source": "// Poll without holding the connection.\nvar r = await solver.GetResultAsync(task.Id);\nwhile (r.Status == TaskResult.StatusEnum.Processing)\n{\n    await Task.Delay(500);\n    r = await solver.GetResultAsync(task.Id);\n}"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php\n// Poll without holding the connection.\nwhile (($r = $solver->getResult($task->getId()))->getStatus() === 'processing') {\n    usleep(500000);\n}"
          },
          {
            "lang": "Ruby",
            "label": "Ruby",
            "source": "# Poll without holding the connection.\nr = solver.get_result(task.id)\nwhile r.status == 'processing'\n  sleep 0.5\n  r = solver.get_result(task.id)\nend"
          },
          {
            "lang": "Rust",
            "label": "Rust",
            "source": "// Poll without holding the connection.\nlet mut r = solve_api::get_result(&config, task.id, None).await?;\nwhile r.status == Status::Processing {\n    tokio::time::sleep(std::time::Duration::from_millis(500)).await;\n    r = solve_api::get_result(&config, task.id, None).await?;\n}"
          },
          {
            "lang": "Swift",
            "label": "Swift",
            "source": "// Poll without holding the connection.\nvar r = try await SolveAPI.getResult(taskId: task.id)\nwhile r.status == .processing {\n    try await Task.sleep(for: .milliseconds(500))\n    r = try await SolveAPI.getResult(taskId: task.id)\n}"
          },
          {
            "lang": "Dart",
            "label": "Dart",
            "source": "// Poll without holding the connection.\nvar r = (await solver.getResult(task.id))!;\nwhile (r.status == TaskResultStatusEnum.processing) {\n  await Future.delayed(const Duration(milliseconds: 500));\n  r = (await solver.getResult(task.id))!;\n}"
          }
        ]
      }
    },
    "/v1/balance": {
      "get": {
        "tags": [
          "account"
        ],
        "summary": "Credits left",
        "description": "Your credit balance. Every solve response also carries it in the `X-Credits-Remaining` header.",
        "operationId": "balance",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Balance"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -s https://captchaocr.allvoraz.com/v1/balance -H \"Authorization: Bearer $CAPTCHA_API_KEY\"\n# {\"credits\": 4321}"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "account = captcha_ocr.AccountApi(client)\nprint(account.balance().credits)"
          },
          {
            "lang": "TypeScript",
            "label": "TypeScript",
            "source": "import { AccountApi } from \"@allvoraz/captcha-ocr\";\n\nconst { credits } = await new AccountApi(config).balance();"
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "bal, _, err := client.AccountAPI.Balance(ctx).Execute()\nif err != nil {\n\tpanic(err)\n}\nfmt.Println(bal.Credits)"
          },
          {
            "lang": "Java",
            "label": "Java",
            "source": "long credits = new AccountApi(client).balance().getCredits();"
          },
          {
            "lang": "Kotlin",
            "label": "Kotlin",
            "source": "val credits = AccountApi(\"https://captchaocr.allvoraz.com\").balance().credits"
          },
          {
            "lang": "C#",
            "label": "C#",
            "source": "var credits = (await new AccountApi(config).BalanceAsync()).Credits;"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php\n$credits = (new Allvoraz\\CaptchaOcr\\Api\\AccountApi(new GuzzleHttp\\Client(), $config))->balance()->getCredits();"
          },
          {
            "lang": "Ruby",
            "label": "Ruby",
            "source": "credits = CaptchaOcr::AccountApi.new.balance.credits"
          },
          {
            "lang": "Rust",
            "label": "Rust",
            "source": "let credits = captcha_ocr::apis::account_api::balance(&config).await?.credits;"
          },
          {
            "lang": "Swift",
            "label": "Swift",
            "source": "let credits = try await AccountAPI.balance().credits"
          },
          {
            "lang": "Dart",
            "label": "Dart",
            "source": "final credits = (await AccountApi(client).balance())!.credits;"
          }
        ]
      }
    },
    "/v1/alert": {
      "get": {
        "tags": [
          "account"
        ],
        "summary": "Get your low-balance alert",
        "operationId": "getAlert",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "404": {
            "description": "No alert set",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      },
      "put": {
        "tags": [
          "account"
        ],
        "summary": "Set your low-balance alert",
        "description": "One alert per account; this replaces any existing one and arms it. When a solve leaves your\ncredits below `threshold`, we POST `payload` (JSON) to `url` with your `headers`, once, retrying\nfor about a minute if your endpoint fails. It re-arms when you add credits above the threshold.\nUse `POST /v1/alert/test` to check delivery now.",
        "operationId": "setAlert",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "# One alert per account. When your credits drop below 500, we POST the payload to your URL.\ncurl -s -X PUT https://captchaocr.allvoraz.com/v1/alert -H \"Authorization: Bearer $CAPTCHA_API_KEY\" \\\n  -H 'Content-Type: application/json' -d '{\n    \"threshold\": 500,\n    \"url\": \"https://hooks.example.org/captcha-credits\",\n    \"payload\": {\"text\": \"Captcha credits low: {{credits}} left (alert at {{threshold}})\"},\n    \"headers\": {\"Authorization\": \"Bearer my-hook-secret\"}\n  }'\n# {\"threshold\": 500, \"url\": \"...\", \"armed\": true, \"last_status\": null, ...}\n\ncurl -s -X POST https://captchaocr.allvoraz.com/v1/alert/test -H \"Authorization: Bearer $CAPTCHA_API_KEY\"\n# {\"delivered\": true, \"status\": 200, \"error\": null}\n\ncurl -s https://captchaocr.allvoraz.com/v1/alert -H \"Authorization: Bearer $CAPTCHA_API_KEY\"          # read it\ncurl -s -X DELETE https://captchaocr.allvoraz.com/v1/alert -H \"Authorization: Bearer $CAPTCHA_API_KEY\" # remove it"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "from captcha_ocr import AlertRequest\n\naccount = captcha_ocr.AccountApi(client)\nprint(account.balance().credits)\n\n# When credits drop below 500, POST this payload to your URL (one alert per account).\naccount.set_alert(AlertRequest(\n    threshold=500,\n    url=\"https://hooks.example.org/captcha-credits\",\n    payload={\"text\": \"Captcha credits low: {{credits}} left\"},\n    headers={\"Authorization\": \"Bearer my-hook-secret\"},\n))\nprint(account.test_alert())   # sends it now: delivered=True status=200\n# account.delete_alert()      # remove it"
          },
          {
            "lang": "TypeScript",
            "label": "TypeScript",
            "source": "const account = new AccountApi(config);\nconsole.log((await account.balance()).credits);\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\nawait account.setAlert({ alertRequest: {\n  threshold: 500,\n  url: \"https://hooks.example.org/captcha-credits\",\n  payload: { text: \"Captcha credits low: {{credits}} left\" },\n  headers: { Authorization: \"Bearer my-hook-secret\" },\n} });\nconsole.log(await account.testAlert()); // sends it now: { delivered: true, status: 200 }\n// await account.deleteAlert();         // remove it"
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "bal, _, _ := client.AccountAPI.Balance(ctx).Execute()\nfmt.Println(bal.Credits)\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\nalert := captchaocr.NewAlertRequest(500, \"https://hooks.example.org/captcha-credits\")\nalert.SetPayload(map[string]interface{}{\"text\": \"Captcha credits low: {{credits}} left\"})\nalert.SetHeaders(map[string]string{\"Authorization\": \"Bearer my-hook-secret\"})\nif _, _, err := client.AccountAPI.SetAlert(ctx).AlertRequest(*alert).Execute(); err != nil {\n\tpanic(err)\n}\ntest, _, _ := client.AccountAPI.TestAlert(ctx).Execute() // sends it now\nfmt.Println(test.Delivered, test.GetStatus())\n// client.AccountAPI.DeleteAlert(ctx).Execute()          // remove it"
          },
          {
            "lang": "Java",
            "label": "Java",
            "source": "AccountApi account = new AccountApi(client);\nSystem.out.println(account.balance().getCredits());\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\naccount.setAlert(new AlertRequest()\n    .threshold(500)\n    .url(\"https://hooks.example.org/captcha-credits\")\n    .payload(Map.of(\"text\", \"Captcha credits low: {{credits}} left\"))\n    .headers(Map.of(\"Authorization\", \"Bearer my-hook-secret\")));\nAlertTestResult test = account.testAlert(); // sends it now\nSystem.out.println(test.getDelivered() + \" \" + test.getStatus());\n// account.deleteAlert();                   // remove it"
          },
          {
            "lang": "Kotlin",
            "label": "Kotlin",
            "source": "val account = AccountApi(\"https://captchaocr.allvoraz.com\")\nprintln(account.balance().credits)\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\naccount.setAlert(AlertRequest(\n    threshold = 500,\n    url = \"https://hooks.example.org/captcha-credits\",\n    payload = mapOf(\"text\" to \"Captcha credits low: {{credits}} left\"),\n    headers = mapOf(\"Authorization\" to \"Bearer my-hook-secret\"),\n))\nprintln(account.testAlert()) // sends it now: delivered=true, status=200\n// account.deleteAlert()     // remove it"
          },
          {
            "lang": "C#",
            "label": "C#",
            "source": "var account = new AccountApi(config);\nConsole.WriteLine((await account.BalanceAsync()).Credits);\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\nawait account.SetAlertAsync(new AlertRequest(\n    threshold: 500,\n    url: \"https://hooks.example.org/captcha-credits\",\n    payload: new Dictionary<string, object> { [\"text\"] = \"Captcha credits low: {{credits}} left\" },\n    headers: new Dictionary<string, string> { [\"Authorization\"] = \"Bearer my-hook-secret\" }));\nvar test = await account.TestAlertAsync(); // sends it now\nConsole.WriteLine($\"{test.Delivered} {test.Status}\");\n// await account.DeleteAlertAsync();       // remove it"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php\n$account = new Allvoraz\\CaptchaOcr\\Api\\AccountApi(new GuzzleHttp\\Client(), $config);\necho $account->balance()->getCredits(), PHP_EOL;\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\n$account->setAlert(new Allvoraz\\CaptchaOcr\\Model\\AlertRequest([\n    'threshold' => 500,\n    'url' => 'https://hooks.example.org/captcha-credits',\n    'payload' => ['text' => 'Captcha credits low: {{credits}} left'],\n    'headers' => ['Authorization' => 'Bearer my-hook-secret'],\n]));\n$test = $account->testAlert(); // sends it now\necho json_encode($test->getDelivered()), ' ', $test->getStatus(), PHP_EOL;\n// $account->deleteAlert();    // remove it"
          },
          {
            "lang": "Ruby",
            "label": "Ruby",
            "source": "account = CaptchaOcr::AccountApi.new\nputs account.balance.credits\n\n# When credits drop below 500, POST this payload to your URL (one alert per account).\naccount.set_alert(CaptchaOcr::AlertRequest.new(\n  threshold: 500,\n  url: 'https://hooks.example.org/captcha-credits',\n  payload: { text: 'Captcha credits low: {{credits}} left' },\n  headers: { 'Authorization' => 'Bearer my-hook-secret' }\n))\ntest = account.test_alert # sends it now\nputs \"#{test.delivered} #{test.status}\"\n# account.delete_alert    # remove it"
          },
          {
            "lang": "Rust",
            "label": "Rust",
            "source": "use captcha_ocr::apis::account_api;\nuse captcha_ocr::models::AlertRequest;\nuse std::collections::HashMap;\n\nprintln!(\"{}\", account_api::balance(&config).await?.credits);\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\nlet mut alert = AlertRequest::new(500, \"https://hooks.example.org/captcha-credits\".into());\nalert.payload = Some(Some(HashMap::from([(\"text\".into(), serde_json::json!(\"Captcha credits low: {{credits}} left\"))])));\nalert.headers = Some(Some(HashMap::from([(\"Authorization\".into(), \"Bearer my-hook-secret\".into())])));\naccount_api::set_alert(&config, alert).await?;\nlet test = account_api::test_alert(&config).await?; // sends it now\nprintln!(\"{} {:?}\", test.delivered, test.status.flatten());\n// account_api::delete_alert(&config).await?;       // remove it"
          },
          {
            "lang": "Swift",
            "label": "Swift",
            "source": "print(try await AccountAPI.balance().credits)\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\n_ = try await AccountAPI.setAlert(alertRequest: AlertRequest(\n    threshold: 500,\n    url: \"https://hooks.example.org/captcha-credits\",\n    payload: [\"text\": .string(\"Captcha credits low: {{credits}} left\")],\n    headers: [\"Authorization\": \"Bearer my-hook-secret\"]))\nlet test = try await AccountAPI.testAlert() // sends it now\nprint(test.delivered, test.status ?? 0)\n// try await AccountAPI.deleteAlert()       // remove it"
          },
          {
            "lang": "Dart",
            "label": "Dart",
            "source": "final account = AccountApi(client);\nprint((await account.balance())!.credits);\n\n// When credits drop below 500, POST this payload to your URL (one alert per account).\nawait account.setAlert(AlertRequest(\n  threshold: 500,\n  url: 'https://hooks.example.org/captcha-credits',\n  payload: {'text': 'Captcha credits low: {{credits}} left'},\n  headers: {'Authorization': 'Bearer my-hook-secret'},\n));\nfinal test = (await account.testAlert())!; // sends it now\nprint('${test.delivered} ${test.status}');\n// await account.deleteAlert();            // remove it"
          }
        ]
      },
      "delete": {
        "tags": [
          "account"
        ],
        "summary": "Remove your low-balance alert",
        "operationId": "deleteAlert",
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/alert/test": {
      "post": {
        "tags": [
          "account"
        ],
        "summary": "Send your alert now (test)",
        "description": "Sends the alert once, right now, with your current balance, and reports what your endpoint\nanswered. Doesn't change whether the alert is armed. One test per 10 seconds.",
        "operationId": "testAlert",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTestResult"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "404": {
            "description": "No alert set",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "429": {
            "description": "One test per 10 seconds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ]
      }
    },
    "/v1/report": {
      "post": {
        "tags": [
          "account"
        ],
        "summary": "Report a wrong answer",
        "description": "The site rejected a reliable answer? Report its `id` within 48 hours and the credit comes back.\nRefunds per day are capped at 10% of that day's charged solves (plus 5).",
        "operationId": "report",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReportRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportResult"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -s https://captchaocr.allvoraz.com/v1/report -H \"Authorization: Bearer $CAPTCHA_API_KEY\" \\\n  -H 'Content-Type: application/json' -d '{\"id\": 184467}'\n# {\"refunded\": true, \"reason\": null, \"credits\": 4322}"
          },
          {
            "lang": "Python",
            "label": "Python",
            "source": "from captcha_ocr import ReportRequest\n\n# The site rejected res.text: get the credit back (within 48 hours).\nr = captcha_ocr.AccountApi(client).report(ReportRequest(id=res.id))\nprint(r.refunded, r.reason)"
          },
          {
            "lang": "TypeScript",
            "label": "TypeScript",
            "source": "// The site rejected res.text: get the credit back (within 48 hours).\nconst r = await new AccountApi(config).report({ reportRequest: { id: res.id! } });\nconsole.log(r.refunded, r.reason);"
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "// The site rejected res.GetText(): get the credit back (within 48 hours).\nr, _, err := client.AccountAPI.Report(ctx).ReportRequest(*captchaocr.NewReportRequest(res.GetId())).Execute()\nif err != nil {\n\tpanic(err)\n}\nfmt.Println(r.Refunded, r.GetReason())"
          },
          {
            "lang": "Java",
            "label": "Java",
            "source": "// The site rejected res.getText(): get the credit back (within 48 hours).\nReportResult r = new AccountApi(client).report(new ReportRequest().id(res.getId()));"
          },
          {
            "lang": "Kotlin",
            "label": "Kotlin",
            "source": "// The site rejected res.text: get the credit back (within 48 hours).\nval r = AccountApi(\"https://captchaocr.allvoraz.com\").report(ReportRequest(id = res.id!!))"
          },
          {
            "lang": "C#",
            "label": "C#",
            "source": "// The site rejected res.Text: get the credit back (within 48 hours).\nvar r = await new AccountApi(config).ReportAsync(new ReportRequest(id: res.Id!.Value));"
          },
          {
            "lang": "PHP",
            "label": "PHP",
            "source": "<?php\n// The site rejected the answer: get the credit back (within 48 hours).\n$r = (new Allvoraz\\CaptchaOcr\\Api\\AccountApi(new GuzzleHttp\\Client(), $config))\n    ->report(new Allvoraz\\CaptchaOcr\\Model\\ReportRequest(['id' => $res->getId()]));"
          },
          {
            "lang": "Ruby",
            "label": "Ruby",
            "source": "# The site rejected res.text: get the credit back (within 48 hours).\nr = CaptchaOcr::AccountApi.new.report(CaptchaOcr::ReportRequest.new(id: res.id))"
          },
          {
            "lang": "Rust",
            "label": "Rust",
            "source": "// The site rejected the answer: get the credit back (within 48 hours).\nlet r = captcha_ocr::apis::account_api::report(&config,\n    captcha_ocr::models::ReportRequest::new(res.id.flatten().unwrap())).await?;"
          },
          {
            "lang": "Swift",
            "label": "Swift",
            "source": "// The site rejected res.text: get the credit back (within 48 hours).\nlet r = try await AccountAPI.report(reportRequest: ReportRequest(id: res.id!))"
          },
          {
            "lang": "Dart",
            "label": "Dart",
            "source": "// The site rejected res.text: get the credit back (within 48 hours).\nfinal r = await AccountApi(client).report(ReportRequest(id: res.id!));"
          }
        ]
      }
    },
    "/health": {
      "get": {
        "tags": [
          "service"
        ],
        "summary": "Service health",
        "operationId": "health",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayHealth"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -s https://captchaocr.allvoraz.com/health\n# {\"status\":\"ok\",\"solver\":{\"status\":\"ok\",\"engines\":{\"ocr\":true,\"math\":true,\"hindi_math\":true}}}"
          }
        ]
      }
    },
    "/createTask": {
      "post": {
        "tags": [
          "tasks"
        ],
        "summary": "createTask (ImageToTextTask)",
        "description": "`{\"clientKey\": KEY, \"task\": {\"type\": \"ImageToTextTask\", \"body\": BASE64, \"numeric\": 1, ...}}`.\nReturns a `taskId` at once; the captcha is solved in the background (usually within 0.1 s).\nPoll getTaskResult. Low-confidence reads come back as `ERROR_CAPTCHA_UNSOLVABLE` and are\nfree: get a new captcha and try again.",
        "operationId": "task_create_createTask_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": true,
                "type": "object",
                "title": "Body"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Task Create Createtask Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/getTaskResult": {
      "post": {
        "tags": [
          "tasks"
        ],
        "summary": "getTaskResult",
        "operationId": "task_get_result_getTaskResult_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": true,
                "type": "object",
                "title": "Body"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Task Get Result Gettaskresult Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/getBalance": {
      "post": {
        "tags": [
          "tasks"
        ],
        "summary": "getBalance (credits)",
        "operationId": "task_get_balance_getBalance_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": true,
                "type": "object",
                "title": "Body"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Task Get Balance Getbalance Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/reportIncorrect": {
      "post": {
        "tags": [
          "tasks"
        ],
        "summary": "reportIncorrect (refund)",
        "operationId": "task_report_incorrect_reportIncorrect_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": true,
                "type": "object",
                "title": "Body"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Task Report Incorrect Reportincorrect Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/reportCorrect": {
      "post": {
        "tags": [
          "tasks"
        ],
        "summary": "reportCorrect",
        "operationId": "task_report_correct_reportCorrect_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": true,
                "type": "object",
                "title": "Body"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Task Report Correct Reportcorrect Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Alert": {
        "properties": {
          "threshold": {
            "type": "integer",
            "title": "Threshold"
          },
          "url": {
            "type": "string",
            "title": "Url"
          },
          "payload": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Payload"
          },
          "headers": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Headers"
          },
          "armed": {
            "type": "boolean",
            "title": "Armed",
            "description": "True: fires the next time a solve leaves your credits below the threshold. False: it fired; it re-arms when you add credits above the threshold."
          },
          "last_fired_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Fired At",
            "description": "When it was last sent (UTC)."
          },
          "last_status": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Status",
            "description": "HTTP status your endpoint returned last time."
          },
          "last_error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Error",
            "description": "Why the last delivery failed, if it did."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "title": "Updated At"
          }
        },
        "type": "object",
        "required": [
          "threshold",
          "url",
          "armed",
          "updated_at"
        ],
        "title": "Alert",
        "description": "Your low-balance alert and its last delivery."
      },
      "AlertRequest": {
        "properties": {
          "threshold": {
            "type": "integer",
            "maximum": 1000000000.0,
            "minimum": 1.0,
            "title": "Threshold",
            "description": "Call `url` when your credits drop below this number."
          },
          "url": {
            "type": "string",
            "maxLength": 2048,
            "title": "Url",
            "description": "Your HTTPS endpoint. We POST `payload` to it as JSON."
          },
          "payload": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Payload",
            "description": "The JSON object to send (up to 8 KB). In string values, `{{credits}}`, `{{threshold}}` and `{{time}}` are replaced; a value that is exactly `{{credits}}` or `{{threshold}}` becomes a number. Default: `{\"event\": \"low_balance\", \"credits\": N, \"threshold\": T}`."
          },
          "headers": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Headers",
            "description": "Extra request headers, e.g. `Authorization` for your endpoint. Up to 10."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "threshold",
          "url"
        ],
        "title": "AlertRequest",
        "description": "Your low-balance alert. One per account: setting it again replaces it."
      },
      "AlertTestResult": {
        "properties": {
          "delivered": {
            "type": "boolean",
            "title": "Delivered",
            "description": "True if your endpoint answered with a 2xx status."
          },
          "status": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status",
            "description": "HTTP status your endpoint returned."
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "Why delivery failed, if it did."
          }
        },
        "type": "object",
        "required": [
          "delivered"
        ],
        "title": "AlertTestResult"
      },
      "Balance": {
        "properties": {
          "credits": {
            "type": "integer",
            "title": "Credits",
            "description": "Credits left. 1 credit = 1 reliable answer."
          },
          "alert_threshold": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Alert Threshold",
            "description": "Your low-balance alert's threshold, if one is set."
          }
        },
        "type": "object",
        "required": [
          "credits"
        ],
        "title": "Balance"
      },
      "BatchItem": {
        "properties": {
          "image": {
            "type": "string",
            "maxLength": 7000000,
            "minLength": 1,
            "title": "Image",
            "description": "Base64-encoded captcha image: PNG, JPEG, GIF, WebP, TIFF, BMP or SVG, detected by content. A `data:image/...;base64,` prefix is accepted.",
            "examples": [
              "iVBORw0KGgoAAAANSUhEUgAA..."
            ]
          },
          "math": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Math",
            "description": "Arithmetic captcha (\"14 - 10 = ?\"); `text` is the computed answer."
          },
          "hindi": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hindi",
            "description": "Operands are Hindi number words (\"इकतीस + 6 = ?\"). Requires `math`."
          },
          "numeric": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Numeric",
            "description": "The captcha may contain digits 0-9."
          },
          "uppercase": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Uppercase",
            "description": "The captcha may contain letters A-Z. Alone, lowercase readings are folded to uppercase."
          },
          "lowercase": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lowercase",
            "description": "The captcha may contain letters a-z. Alone, uppercase readings are folded to lowercase."
          },
          "length": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 32.0,
                "minimum": 1.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Length",
            "description": "Exact number of characters. The decoder returns the most likely reading of exactly this length. Ignored when `math` is set."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "image"
        ],
        "title": "BatchItem",
        "description": "One /solve_batch image. Options set here override the request's shared options\nfor this image only; unset (null) options inherit them."
      },
      "BatchRequest": {
        "properties": {
          "math": {
            "type": "boolean",
            "title": "Math",
            "description": "Arithmetic captcha (\"14 - 10 = ?\"); `text` is the computed answer.",
            "default": false
          },
          "hindi": {
            "type": "boolean",
            "title": "Hindi",
            "description": "Operands are Hindi number words (\"इकतीस + 6 = ?\"). Requires `math`.",
            "default": false
          },
          "numeric": {
            "type": "boolean",
            "title": "Numeric",
            "description": "The captcha may contain digits 0-9.",
            "default": false
          },
          "uppercase": {
            "type": "boolean",
            "title": "Uppercase",
            "description": "The captcha may contain letters A-Z. Alone, lowercase readings are folded to uppercase.",
            "default": false
          },
          "lowercase": {
            "type": "boolean",
            "title": "Lowercase",
            "description": "The captcha may contain letters a-z. Alone, uppercase readings are folded to lowercase.",
            "default": false
          },
          "length": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 32.0,
                "minimum": 1.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Length",
            "description": "Exact number of characters. The decoder returns the most likely reading of exactly this length. Ignored when `math` is set."
          },
          "images": {
            "items": {
              "$ref": "#/components/schemas/BatchItem"
            },
            "type": "array",
            "maxItems": 256,
            "minItems": 1,
            "title": "Images",
            "description": "1-256 images, solved in parallel; results come back in the same order. A plain base64 string is accepted as shorthand for `{\"image\": ...}`."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "images"
        ],
        "title": "BatchRequest",
        "description": "Many captchas in one call. The top-level options apply to every image.",
        "examples": [
          {
            "images": [
              {
                "image": "iVBORw0KGgo..."
              },
              {
                "image": "R0lGODlh...",
                "length": 5
              }
            ],
            "numeric": true
          }
        ]
      },
      "ErrorMessage": {
        "properties": {
          "detail": {
            "type": "string",
            "title": "Detail"
          },
          "credits": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Credits"
          }
        },
        "type": "object",
        "required": [
          "detail"
        ],
        "title": "ErrorMessage"
      },
      "GatewayHealth": {
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded"
            ],
            "title": "Status"
          },
          "solver": {
            "additionalProperties": true,
            "type": "object",
            "title": "Solver"
          }
        },
        "type": "object",
        "required": [
          "status",
          "solver"
        ],
        "title": "GatewayHealth"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "ReportRequest": {
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "title": "Id",
            "description": "The `id` of a solve from the last 48 hours."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "id"
        ],
        "title": "ReportRequest"
      },
      "ReportResult": {
        "properties": {
          "refunded": {
            "type": "boolean",
            "title": "Refunded",
            "description": "True if the credit was returned."
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason",
            "description": "Why not, when refunded is false."
          },
          "credits": {
            "type": "integer",
            "title": "Credits"
          }
        },
        "type": "object",
        "required": [
          "refunded",
          "credits"
        ],
        "title": "ReportResult"
      },
      "SolveRequest": {
        "properties": {
          "math": {
            "type": "boolean",
            "title": "Math",
            "description": "Arithmetic captcha (\"14 - 10 = ?\"); `text` is the computed answer.",
            "default": false
          },
          "hindi": {
            "type": "boolean",
            "title": "Hindi",
            "description": "Operands are Hindi number words (\"इकतीस + 6 = ?\"). Requires `math`.",
            "default": false
          },
          "numeric": {
            "type": "boolean",
            "title": "Numeric",
            "description": "The captcha may contain digits 0-9.",
            "default": false
          },
          "uppercase": {
            "type": "boolean",
            "title": "Uppercase",
            "description": "The captcha may contain letters A-Z. Alone, lowercase readings are folded to uppercase.",
            "default": false
          },
          "lowercase": {
            "type": "boolean",
            "title": "Lowercase",
            "description": "The captcha may contain letters a-z. Alone, uppercase readings are folded to lowercase.",
            "default": false
          },
          "length": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 32.0,
                "minimum": 1.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Length",
            "description": "Exact number of characters. The decoder returns the most likely reading of exactly this length. Ignored when `math` is set."
          },
          "image": {
            "type": "string",
            "maxLength": 7000000,
            "minLength": 1,
            "title": "Image",
            "description": "Base64-encoded captcha image: PNG, JPEG, GIF, WebP, TIFF, BMP or SVG, detected by content. A `data:image/...;base64,` prefix is accepted.",
            "examples": [
              "iVBORw0KGgoAAAANSUhEUgAA..."
            ]
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "image"
        ],
        "title": "SolveRequest",
        "description": "One captcha image plus solving options.",
        "examples": [
          {
            "image": "iVBORw0KGgoAAAANSUhEUgAA...",
            "length": 6,
            "numeric": true
          },
          {
            "hindi": true,
            "image": "iVBORw0KGgoAAAANSUhEUgAA...",
            "math": true
          }
        ]
      },
      "Solved": {
        "properties": {
          "text": {
            "type": "string",
            "title": "Text",
            "description": "What to type into the form. For math captchas, the computed answer.",
            "default": ""
          },
          "confidence": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Confidence",
            "description": "Probability of the least certain character (0-1).",
            "default": 0.0
          },
          "reliable": {
            "type": "boolean",
            "title": "Reliable",
            "description": "Worth submitting. When false, fetch a fresh captcha instead.",
            "default": false
          },
          "engine": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "ocr",
                  "math",
                  "hindi_math"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Engine",
            "description": "Engine that read the image."
          },
          "raw": {
            "type": "string",
            "title": "Raw",
            "description": "The model's reading before post-processing.",
            "default": ""
          },
          "expression": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expression",
            "description": "Math only: the expression computed, e.g. `31+6`."
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "`invalid_image` (cannot be decoded, or larger than 4 megapixels), `timeout`, `model_unavailable` or `internal_error`; null on success."
          },
          "id": {
            "anyOf": [
              {
                "type": "integer",
                "format": "int64"
              },
              {
                "type": "null"
              }
            ],
            "title": "Id",
            "description": "Task id. Use it with /v1/report if the answer was wrong."
          },
          "charged": {
            "type": "boolean",
            "title": "Charged",
            "description": "Whether this answer cost a credit (only reliable answers do).",
            "default": false
          }
        },
        "type": "object",
        "title": "Solved",
        "description": "A solved captcha plus billing details.",
        "examples": [
          {
            "confidence": 0.97,
            "engine": "ocr",
            "raw": "A9D411",
            "reliable": true,
            "text": "A9D411"
          },
          {
            "confidence": 0.99,
            "engine": "hindi_math",
            "expression": "31+6",
            "raw": "इकतीस+6",
            "reliable": true,
            "text": "37"
          }
        ]
      },
      "SolvedBatch": {
        "properties": {
          "results": {
            "items": {
              "$ref": "#/components/schemas/Solved"
            },
            "type": "array",
            "title": "Results"
          }
        },
        "type": "object",
        "required": [
          "results"
        ],
        "title": "SolvedBatch",
        "description": "Results of /v1/solve_batch, in request order."
      },
      "Submitted": {
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "title": "Id",
            "description": "Task id. Get the answer with GET /v1/result/{id}."
          },
          "status": {
            "type": "string",
            "const": "processing",
            "title": "Status",
            "description": "Always `processing` here; see /v1/result."
          }
        },
        "type": "object",
        "required": [
          "id",
          "status"
        ],
        "title": "Submitted",
        "description": "A captcha accepted for background solving."
      },
      "TaskResult": {
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "title": "Id"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "ready",
              "failed"
            ],
            "title": "Status",
            "description": "`processing`: ask again (or pass `wait`). `ready`: the answer is in `result`. `failed`: the solver couldn't run; the credit was returned, submit again."
          },
          "result": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Solved"
              },
              {
                "type": "null"
              }
            ],
            "description": "The answer, when status is `ready`. Check `reliable` as with /v1/solve."
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "Why the task failed, when status is `failed`."
          }
        },
        "type": "object",
        "required": [
          "id",
          "status"
        ],
        "title": "TaskResult",
        "description": "A submitted captcha: still processing, ready with its answer, or failed."
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "description": "`Authorization: Bearer <API key>` (keys are on the dashboard)",
        "scheme": "bearer"
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "description": "Alternative: `X-API-Key: <API key>`",
        "in": "header",
        "name": "X-API-Key"
      }
    }
  },
  "tags": [
    {
      "name": "solve",
      "description": "Read captchas. Each reliable answer costs 1 credit."
    },
    {
      "name": "account",
      "description": "Balance and refunds."
    },
    {
      "name": "tasks",
      "description": "Task API: createTask / getTaskResult / getBalance / reportIncorrect (ImageToTextTask)."
    },
    {
      "name": "service",
      "description": "Operational endpoints."
    }
  ],
  "externalDocs": {
    "description": "Guide and SDKs",
    "url": "https://captchaocr.allvoraz.com/docs"
  }
}
