SolveHub

接口参考

SolveHub REST API 参考:任务、价格、余额与 Webhook

SolveHub 客户 API 完整参考:Bearer API Key 认证、任务创建与查询、实时价格、余额与账本、工单、Webhook 以及全部错误码。

适用于授权自动化测试、风控 QA 与浏览器集成。请仅在有权测试的站点和业务流程中使用。

本文按当前 HTTP 路由、应用服务及任务参数校验编写。生产地址(Base URL)为 https://www.tiam.codes,下文路径均相对于该地址;本地默认 http://127.0.0.1:8080,生产必须使用 HTTPS。所有示例中的密钥、邮箱和域名均为占位符。响应时间使用 RFC 3339,金额为 USD 微美元整数:1 USD = 1,000,000 micros。价格以 GET /v1/prices 的实时值为准,任务创建时冻结该次售价。

通用约定

常规 API 使用 Authorization: Bearer <API_KEY>;JSON 写请求使用 Content-Type: application/json。客户网页使用 HttpOnly、SameSite=Strict 的 solvehub_portal Cookie;Cookie 鉴权的非 GET/HEAD 请求必须加 X-SolveHub-Portal: 1。登录、注册及退出请求也要求该头。Bearer 优先于 Cookie:不要让浏览器无意附带另一个 Key 的 Authorization 头。

每次响应带 X-Request-ID,可用来向客服定位问题。失败响应通常为 {"error":"ERROR_CODE"},不是成功响应格式;204 没有响应体。请求体只接受一个 JSON 对象,未知顶层字段通常会返回 400 INVALID_JSON。除创建任务和兼容接口最多 8 MiB 外,JSON 请求体最多 1 MiB。

HTTP 状态 常见含义与处理
400 参数错误,如 INVALID_JSON、INVALID_TASK、INVALID_IDEMPOTENCY_KEY;修正请求。
401 UNAUTHORIZED、API_KEY_EXPIRED;账户登录还可能是 TOTP_REQUIRED 或 TOTP_INVALID。
402 INSUFFICIENT_BALANCE;先充值或调整消费。
403 INSUFFICIENT_SCOPE、IP_NOT_ALLOWED、ACCOUNT_FROZEN、ACCOUNT_CLOSED、ACCOUNT_UNBOUND(邮箱账户尚未绑定 Key)、PORTAL_CSRF_CHECK_FAILED、KEY_SPEND_FROZEN、KEY_QUOTA_EXHAUSTED(该 Key 的总额度已用完,退款不返还额度,需联系平台调整或改用其他 Key);过期 Key 扣费续费返回 RENEWAL_REAUTH_REQUIRED。
404 当前客户不可见或不存在的资源;不要用它判断其他客户资源是否存在。
409 状态/版本或幂等冲突,如 IDEMPOTENCY_CONFLICT、VERSION_CONFLICT。
410 已停用的旧充值订单创建与付款说明接口。
429 配额、工单频率或登录限制;KEY_SPEND_LIMIT 表示当前 Key 的 24 小时安全上限已用尽,响应带 Retry-After: 300,但具体恢复时间取决于历史预占退出窗口;KEY_CONCURRENCY_LIMIT 表示该 Key 同时排队或处理中的任务已达平台为它设置的并发上限,等已有任务结束后再提交,响应带 Retry-After: 60。
500/503 内部故障或依赖不可用;有幂等键时使用相同请求和相同键重试,先查询已创建的资源。数据库瞬时故障由服务端自动重试,约 10 秒仍未恢复时返回 503 DATABASE_BUSY 和 Retry-After: 1:读取请求可直接重试;写请求可能已生效(提交结果无法确认时),须带同一幂等键重试或先查询。

API Key 权限为 tasks(任务、用量)、billing(余额、账本、充值 Key、历史订单)、account(账户资料、Key 元数据、Webhook、会话列表)。创建、修改或吊销 Key、更改联系邮箱、结束其他设备会话还需要邮箱密码账户会话;持有 account 权限的 Key 也不能执行这些敏感变更。部分宽限接口接受过期 Key,例如余额、充值 Key 兑换、续费记录和工单;过期 Key 不能创建任务,也不能用自身凭证授权扣费续费。冻结账户不能执行新任务、充值 Key 兑换等操作。工单使用已认证客户身份,无单独权限范围。

无需登录的 GET /healthz 返回 {"status":"ok"},表示 API 进程存活;GET /readyz 返回 {"status":"ready"},表示数据库及迁移标记可用,异常时返回 503 DATABASE_UNAVAILABLE。这两个接口不保证任务处理能力可用。

身份与会话

方法与路径 请求 成功响应
POST /v1/portal/register/email 无需登录,X-SolveHub-Portal: 1;{"email":"ops@example.com"} 204,验证码已排入发件箱。注册必须先完成邮箱验证;验证码 20 分钟有效、只能使用一次,重复获取会让旧码立即失效,累计错误 5 次即作废。邮箱已注册返回 409 ACCOUNT_EXISTS;同一来源请求过多返回 429 REGISTER_THROTTLED。
POST /v1/portal/register 无需登录,X-SolveHub-Portal: 1;{"email":"ops@example.com","password":"...","code":"..."},code 为上一接口下发的验证码 201 {"customerId":"uuid","status":"unbound"},登录邮箱随即标记为已验证,因此不会产生邮箱未验证的账户。新账户处于未绑定状态:没有 Key、不能查看余额或创建任务,须用账户登录后调用 bind-key。邮箱已注册返回 409 ACCOUNT_EXISTS;验证码错误或过期返回 400 EMAIL_CODE_INVALID;密码不合规返回 400 INVALID_ACCOUNT;同一来源注册过于频繁返回 429 REGISTER_THROTTLED(带 Retry-After)。
POST /v1/portal/account/bind-key 账户会话,X-SolveHub-Portal: 1;{"apiKey":"sh_..."} 200 {"customerId":"uuid","keyId":"uuid","merged":true}。未绑定账户:账户(登录邮箱、密码、TOTP、当前会话)整体挂到该 Key 所属客户下,merged:true,无需重新登录;该客户已有邮箱账户时返回 409 KEY_ALREADY_BOUND。已绑定账户:只能粘贴本客户的 Key,作用是为旧 Key 保存加密明文以便日后查看,merged:false;其他客户的 Key 返回 409 KEY_OWNED_BY_OTHER_CUSTOMER。Key 不存在或已撤销返回 404 KEY_NOT_FOUND;失败按来源计数,过多时返回 429 BIND_THROTTLED。
POST /v1/portal/session {"apiKey":"sh_..."},加 X-SolveHub-Portal: 1 200 会话视图并设置 Cookie。Key 会话继承原 Key 权限、IP 白名单及到期限制。
POST /v1/portal/session/account {"email":"ops@example.com","password":"..."};已开启 TOTP 时再次提交同一邮箱密码和 code(6 位动态验证码或一次性恢复码) 200 会话视图并设置 Cookie。先校验密码;密码正确且启用 TOTP 才返回 401 TOTP_REQUIRED,未启用时直接登录。恢复码成功登录后立即失效。
GET /v1/portal/session / DELETE /v1/portal/session Cookie;退出需 X-SolveHub-Portal: 1 会话视图 / 204。
GET /v1/portal/sessions / DELETE /v1/portal/sessions/{id} 查询需 account 权限;结束会话还需邮箱密码账户会话 {"sessions":[...]} / 204。
GET /v1/portal/account/security account 权限 {"registered":true,"totpEnabled":false};账户会话另返回 email,emailVerified,Key 会话不返回登录邮箱。
POST /v1/portal/account/claim Key 会话且有 account 权限;{"email":"...","password":"..."} 204;Key 持有人自行绑定,无需管理员开通码。每个客户只能绑定一次,再次提交返回 409 ACCOUNT_EXISTS;邮箱已被占用同样返回 409;密码不合规返回 400 INVALID_ACCOUNT;已关闭客户返回 403 ACCOUNT_CLOSED。
POST /v1/portal/account/email-verification 账户会话,X-SolveHub-Portal: 1;空 JSON {} 204;向登录邮箱发送一次性验证码。SMTP 未配置时为 503 EMAIL_UNAVAILABLE;每客户至少间隔 15 分钟。
POST /v1/portal/account/email-verification/confirm 账户会话;{"code":"邮件中的验证码"} 204;验证码 20 分钟内有效,只能使用一次。通知邮箱与登录邮箱可不同,验证状态只属于登录邮箱。
POST /v1/portal/contact-email/verification 账户会话,X-SolveHub-Portal: 1;空 JSON {} 204;向当前通知邮箱发送一次性验证码。SMTP 未配置返回 503 EMAIL_UNAVAILABLE;已验证返回 409 EMAIL_ALREADY_VERIFIED;每客户至少间隔 15 分钟。
POST /v1/portal/contact-email/verification/confirm 账户会话;{"code":"邮件中的验证码"} 204;通知邮箱验证成功。验证码 20 分钟内有效且只能使用一次;更换通知邮箱后旧码失效。无效码返回 400 EMAIL_CODE_INVALID。
POST /v1/portal/account/password-recovery 无需登录,X-SolveHub-Portal: 1;{"email":"ops@example.com"} 一律 204,不透露账户是否存在或邮箱是否已验证;只有已验证的登录邮箱会收到邮件。SMTP 未配置时为 503。
POST /v1/portal/account/password-recovery/confirm 无需登录,X-SolveHub-Portal: 1;{"email":"...","token":"邮件中的验证码","password":"新密码","code":"动态验证码或恢复码"} 204;已开启 2FA 时 code 必填。邮件验证码和恢复码均只能使用一次;成功后所有账户会话失效,API Key 不变。无效码统一返回 400 RECOVERY_INVALID。
POST /v1/portal/account/totp {"password":"..."} 200 {"secret":"...","uri":"otpauth://..."};妥善保存,不能写入日志。
POST /v1/portal/account/totp/confirm 账户会话;{"code":"123456"} 200 {"recoveryCodes":["SHRC-...",...]};验证成功后立即启用两步验证并原子保存 8 个恢复码摘要。明文只返回本次,应离线保存。
POST /v1/portal/account/totp/recovery-codes 账户会话;{"password":"...","code":"123456"},必须是尚未使用的动态验证码 200 {"recoveryCodes":[...]};原子作废全部旧恢复码,新码明文只返回本次。
POST /v1/portal/account/totp/disable 账户会话;{"password":"...","code":"123456"},也可使用未用过的恢复码 204;全部剩余恢复码立即失效。
POST /v1/portal/account/password {"oldPassword":"...","newPassword":"...","code":"123456"};未启用 TOTP 时省略 code 204,已有账户会话被撤销,重新登录。

注册与绑定流程:POST /v1/portal/register/email 获取邮箱验证码 → POST /v1/portal/register 凭验证码注册邮箱密码账户 → POST /v1/portal/session/account 登录 → POST /v1/portal/account/bind-key 粘贴运营发放的 API Key,账户即归属该 Key 的客户。一个账户对应一个客户,可管理该客户的多把 Key;同一客户只能绑定一个邮箱账户。未绑定期间除会话、安全设置与绑定接口外,其余接口返回 403 ACCOUNT_UNBOUND。已有 Key、尚无邮箱账户的客户也可以继续用 Key 登录后在「安全」页绑定邮箱(见 account/claim)。

密码须为 12–128 个 Unicode 字符,至少有 6 个不同字符,不能包含邮箱地址;不强制混用特殊字符。会话视图含 authMethod,sessionId,customerId,customerName,customerStatus,keyId,keyLabel,scopes,keyExpiresAt,keyExpired,expiresAt,idleTimeoutSeconds;账户会话的 authMethod 为 account,Key 会话为 api_key。会话登录后 24 小时到期。账户会话与某把 API Key 独立;Key 会话随该 Key 撤销失效。TOTP 验证码不能在同一个时间步重复使用。登录失败有 IP 和账户级限制;收到 429 LOGIN_THROTTLED 时遵循 Retry-After。既有账户的登录邮箱默认未验证,需要在控制台“安全”页验证后才能自助恢复密码。遗失验证器时可用一次性恢复码登录、关闭 2FA 或配合已验证登录邮箱的邮件验证码重设密码;恢复码也遗失时需联系管理员核验身份。恢复码只能在启用或重新生成时看到,不应粘贴到工单、聊天或日志中。

**Key 泄露处理:**若仍持有密码账户会话,用 POST /v1/portal/keys/{id}/compromise(account 权限)应急撤销泄露 Key;该接口可撤销最后一把 Key,普通 DELETE /v1/keys/{id} 不行。随后查看 GET /v1/portal/sessions、GET /v1/ledger 和任务列表,撤销可疑会话,创建替代 Key;必要时联系运营冻结客户。已过期的泄露 Key 不能再以自身凭证扣费续费。尚未撤销的泄露 Key 仍能在它的安全额度内创建任务,因此发现泄露后应立即撤销。只有泄露 Key 而没有账户会话的攻击者不能调用应急接口,但撤销传播受多实例缓存影响,仍应尽快联系运营。

新用户试用余额(Telegram 绑定)

注册邮箱密码账户后,可在控制台「安全 → 绑定 Telegram」绑定并验证一个 Telegram 账号,验证成功后平台一次性发放 0.10 USD 试用余额到钱包。余额可直接调用接口,无需充值。

方法与路径 请求/参数 成功响应
GET /v1/portal/account/telegram 邮箱密码账户会话 enabled,status,tgUsername,verifiedAt,trialCredited,trialAmountMicros,trialMaxActive。status 为空表示尚未发起,pending 表示等待在 Telegram 内确认,verified 表示已发放;enabled:false 表示服务端未启用该 Bot。
POST /v1/portal/account/telegram/bind 邮箱密码账户会话,X-SolveHub-Portal: 1 200 {botUsername,deepLink,expiresAt}。用浏览器打开 deepLink 或在 Telegram 内点击链接后,Bot 收到 /start 即完成验证并入账;链接 15 分钟内有效,每次重新生成都会让上一条失效。

规则:

  • 去重以 Telegram 数字 user_id 为准,一个 Telegram 账号只能绑定一个 SolveHub 账户,同一账户也只能绑定一个 Telegram 账号。
  • 绑定不可解绑:验证成功后换绑、注销后重新注册都无法再次领取试用余额。
  • Bot 回复语言跟随控制台界面语言:bind 请求可带 {"locale":"zh|en|ja"},未提供时退回 Telegram 客户端语言,仍无法识别则用英文。
  • 试用余额永不过期,但只够支撑 1 个并发任务:验证时会把该客户的 max_active 收紧为 1,前一个任务结束后才能提交下一个。任意金额充值到账(含充值码、Cregis 入账、订单确认与正向调账)都会自动删除这条系统设置的限制,恢复到全局默认并发;运营手工调整过的配额不受影响。
  • 入账记为一条 credit 分录(备注「新用户 Telegram 验证奖励」),reference 唯一,重复触发不会重复加钱。
  • 未绑定账户(status: unbound)验证成功后自动转为 active,随后即可在「API Key」页自助创建 Key(若 customerKeyCreation 为 false 则需运营发放)。

账户与 API Key

方法与路径 请求/参数 成功响应
GET /v1/me 认证 客户资料 customerId,name,status,statusReason,contactEmail,contactEmailVerified,createdAt 与本次凭据的 key 视图。账户会话的 keyId 可能为空。
PUT /v1/me 邮箱密码账户会话;{"contactEmail":"new@example.com"} 更新后的账户资料;新邮箱的 contactEmailVerified 为 false,须完成验证才会收到业务通知。留空表示不接收邮件。
GET /v1/me/prices 认证(任意权限,过期 Key 亦可读取) 本客户的生效单价,结构同 GET /v1/prices,另含 negotiated 与 listPriceMicros,见下文“价格”。
GET /v1/keys/policy 认证 customerKeyCreation,maxActiveKeys,maxValidityDays,customerRenewal,reminderDays。
GET /v1/keys account {"keys":[APIKeyMeta...]};列表不含明文,viewable:true 的 Key 可通过下方 reveal 接口查看。
POST /v1/keys 邮箱密码账户会话;{"label":"prod","scopes":["tasks"],"ipAllowlist":["203.0.113.0/24"],"expiresInDays":30,"spendLimit24hMicros":100000000,"spendFreezeHourMicros":20000000} 201 {"keyId":"uuid","apiKey":"sh_...","key":APIKeyMeta};明文加密保存,之后可用 reveal 再次查看。省略额度时默认分别为 100 与 20 USD;空 scopes 表示全部权限,空白名单表示不限来源。
GET /v1/keys/{id} 自身 Key 或 account 权限 APIKeyMeta。
POST /v1/keys/{id}/reveal 账户会话,X-SolveHub-Portal: 1;未开启 TOTP 时 {"password":"..."},已开启时 {"code":"123456"}(动态验证码或恢复码) 200 {"apiKey":"sh_..."},带 Cache-Control: no-store,每次查看写入审计日志。Key 会话返回 403 ACCOUNT_SESSION_REQUIRED;密码错误 400 INVALID_PASSWORD;缺少或错误的二次验证码 400 TOTP_REQUIRED / 400 TOTP_INVALID;Key 没有保存明文(旧 Key,或服务端未配置数据加密密钥)返回 409 KEY_NOT_VIEWABLE,旧 Key 用 bind-key 粘贴一次即可启用;已撤销 409 KEY_REVOKED。
PUT /v1/keys/{id} 邮箱密码账户会话;整体提交 label,scopes,ipAllowlist,version;可附加 spendLimit24hMicros,spendFreezeHourMicros,clearSpendFreeze 更新后的 APIKeyMeta;客户不可直接编辑过期时间。version 用于避免覆盖并发修改。scopes、ipAllowlist(可为空数组,分别表示全部权限、不限来源)与读取时的 version 缺一不可,漏传或为 null 返回 400 INVALID_KEY_REQUEST 且不修改。设置 clearSpendFreeze:true 仅解除冻结,不清除历史额度窗口。
DELETE /v1/keys/{id} 邮箱密码账户会话 204;普通撤销不能撤销最后一把有效 Key。
GET /v1/keys/renewal-plans 认证 {"enabled":true,"plans":[{"code":"month","name":"30 天","days":30,"priceMicros":0}],"currency":"USD"};价格为示例,必须读取实时值。
POST /v1/keys/{id}/renew 有效的自身 Key、有效且有 account 权限的其他 Key,或账户会话;Idempotency-Key 8–128 字符;{"plan":"month"} 首次 201、重放 200 且 Idempotent-Replayed: true,响应为续费记录。过期 Key 自身发起时返回 403 RENEWAL_REAUTH_REQUIRED;账户会话或其他有效且有 account 权限的 Key 可为它续费。
GET /v1/keys/{id}/renewals?limit=50 自身 Key 或 account {"renewals":[...]}。

通知邮箱与登录邮箱分别验证,即使地址相同也不共用验证状态。未验证的通知邮箱不会收到公告、工单回复、Key 提醒或财务邮件;已排队但尚未投递的旧地址业务邮件在更改地址后作废。已经发出的邮件无法撤回。仅使用 Key 的客户须先在「安全」页用带 account 权限的 Key 自行绑定邮箱密码,才能设置及验证通知邮箱。

APIKeyMeta 包含 keyId,label,hint,status,scopes,ipAllowlist,expiresAt,lastUsedAt,lastUsedIp,createdBy,createdAt,revokedAt,version,spendLimit24hMicros,spendFreezeHourMicros,spendFrozenAt,viewable;viewable 表示服务端保存了该 Key 的加密明文,可在账户会话二次验证后查看,撤销后明文随即删除。expiresAt:null 表示长期有效,状态为 active、expired 或 revoked。spendFrozenAt 非空表示因一小时累计预占超阈值而冻结任务创建。两项额度均为正整数微美元,最多 10,000 USD,且一小时阈值不能超过 24 小时上限。额度按五分钟窗口保守统计,最多额外限制约五分钟;失败或取消后的退款不会释放安全额度,防止反复创建和退款试探。触发冻结的请求不创建任务、不动钱包;已配置联系邮箱且邮件服务可用时会发送通知,不能把邮件当作冻结生效的前提。解除冻结前先核对任务和账本。标签为 1–100 字符;IP 白名单接受单个地址或 CIDR,最多 32 项。不要把 API Key 放入 URL、浏览器本地存储或工单正文。Key 的 account 权限可以读取其他 Key 元数据并管理 Webhook,但不能签发或修改 Key;建议任务进程只授予 tasks。

价格、任务与用量

GET /v1/prices 无需登录,返回按类型命名的对象;每项含 available,启用时含全局 priceMicros,currency,停用时含 reason,还可能有 version,updatedAt。available 表示该类型在价目配置中启用,不代表实时处理能力保证。

需要知道自己的实际单价时调用认证接口 GET /v1/me/prices:结构与 GET /v1/prices 相同,启用类型另含 listPriceMicros(公开标价)和 negotiated。negotiated:true 时 priceMicros 为你的协议价;运营上调采购价导致协议价不再适用时,自动回退公开标价且 negotiated:false。停用或未配置的类型不报价,即使签有协议价。报价与建单使用同一规则,但两次请求之间仍可能调价,最终预占金额以创建响应的 priceMicros 为准。version 是公开价目版本,协议价变化不会改变它。POST /v1/tasks 需要 tasks 权限和 8–128 字符的 Idempotency-Key。请求示例:

POST /v1/tasks HTTP/1.1
Authorization: Bearer sh_EXAMPLE
Content-Type: application/json
Idempotency-Key: order-12345-turnstile

{"type":"turnstile","task":{"websiteURL":"https://example.com","websiteKey":"SITE_KEY"}}

成功返回 202 任务对象,如 {"taskId":"uuid","type":"turnstile","status":"queued","priceMicros":200,"traceId":"uuid","createdAt":"2026-10-02T00:00:00Z"}。任务对象还可能有 solution、errorCode、finishedAt。失败时 errorCode 为 TASK_FAILED 或 TASK_TIMEOUT;待核对时为 TASK_UNCERTAIN。结果只包含客户完成业务所需的字段,诊断信息请凭 taskId 与 X-Request-ID 联系客服。任务状态:queued(可取消)、dispatching、processing、uncertain、completed、failed、cancelled。uncertain 不是终态:平台暂时无法确认任务处理结果或费用,金额继续预占;继续查询原任务并向客服提供 taskId,不要换幂等键创建替代任务。完成时扣除冻结售价,明确失败/取消则退回预占。

失败任务还可能返回 failureReason:上游明确失败时的具体说明(例如 IP Blocked (fake page)),经过脱敏与长度限制;上游没有说明时可能退回稳定失败码。请根据 errorCode 和 status 判断流程,failureReason 仅用于诊断展示,不应作为固定枚举解析。

方法与路径 参数 响应
GET /v1/tasks/{id} tasks 200 任务对象。
GET /v1/tasks status,type,from,to,limit,cursor,offset;时间 RFC 3339,limit 1–100,默认 50;offset 0–100000,不能与 cursor 同时使用 {"tasks":[...],"nextCursor":"..."};把非空游标原样传入下一页。带 offset 时按页码分页,并额外返回符合筛选条件的总数 total。
GET /v1/tasks/{id}/events tasks {"events":[{"traceId":"...","from":"queued","to":"processing","message":"...","at":"..."}]}。
POST /v1/tasks/{id}/cancel tasks 200 任务对象;只有 queued 可取消,否则 409 TASK_NOT_CANCELLABLE。
GET /v1/usage tasks;可选 from,to(最多 90 天)、granularity=day&tz=Asia/Shanghai {"from":"...","to":"...","items":[{"type":"turnstile","created":1,"completed":1,"failed":0,"cancelled":0,"uncertain":0,"chargedMicros":200,"reservedMicros":0}],"currency":"USD"}。按日统计时每项有 date。

同一客户在任务幂等记录保留期内重用完全相同的请求体与同一键,会返回原任务而不会再次预占;同键不同请求返回 409 IDEMPOTENCY_CONFLICT。客户端网络超时或 5xx 时先用同一键重试,记录返回的 taskId 并持续查询。服务端定期清理超过约 25 小时的任务幂等记录,因此客户端应长期保存 taskId,不要在清理后依赖旧幂等键去重。任务 task 不得超过 7 MiB。

任务类型与参数

外层 type 必填;内层 task.type 可省略,若提供必须与外层一致。所有类型都拒绝未列出的字段,不能传入 clientKey 或任何外部服务密钥。下表的 URL 必须为完整 HTTP(S) URL;代理端口为字符串,代理协议只能为 http。

type task 必填字段 可选字段与限制
ocr base64:图片 Base64,可含 data:image/...;base64, 前缀,字符串最长 5,242,880 字节 无;图片需能解码。
turnstile websiteURL,websiteKey useragent; cdata,action;代理四元组 proxyType,proxyAddress,proxyPort 及可选登录信息。
interstitial websiteURL,proxyType,proxyAddress,proxyPort siteKey(页面 Turnstile sitekey,可使用快捷路径)、useragent,source(布尔)、method(GET/POST)、代理登录信息。
perimeterx websiteURL,websiteKey 与代理四元组 useragent、代理登录信息。
datadome websiteURL,captchaUrl 与代理四元组 useragent; 代理登录信息。
akamai websiteURL 与代理四元组 useragent; ApiURL、代理登录信息。
aliyun websiteURL,websiteKey,prefix 与代理四元组 region(sgp/cn)、useragent、代理登录信息。
imperva websiteURL;isUtmvc=true 时还需 scriptURL,否则需 reeseScriptUrl cookies(最多 100 个 {name,value})、language,useragent、可选代理。
awswaf websiteURL,WafScriptUrl 可选代理。
alix5sec websiteURL useragent、可选代理;目录中默认禁用,以实时价格/启用状态为准。
funcaptcha proxy(完整 http/https/socks5 地址,必须带端口)、challengeInfo、browserInfo challengeInfo 至少包含 publicKey,site,surl,capiMode,styleTheme,locationHref,documentReferrer,treeStructure 字符串,ancestorOrigins,treeIndex 数组,languageEnabled,jsfEnabled 布尔值;browserInfo 至少包含 User-Agent 字符串及 Linux,Mac,Mobile,Safari 布尔值。可选字段传入时须符合 FunCaptcha 接入说明 中的类型。
funcaptcha_classification base64Image(可解码 Base64)、gameType(非负整数)、variant 是否启用以实时价格为准;当前默认禁用。
perimeterx_cookies appId(PerimeterX 应用 ID,≤ 64 字节)、site(目标页面 URL)、proxy(完整 http/https/socks5 地址,必须带端口) 无其他字段;结果为 solution.cookies。是否启用以实时价格为准;当前默认禁用。

websiteURL 上限 2048 字节;websiteKey 256,proxyAddress 256,proxyPort 5,代理用户名/密码各 256。captchaUrl 和 WafScriptUrl 上限 4096;具体可选字段长度以服务端验证为准。funcaptcha 的复杂结构必须按该类型验证规则提交,避免将其他验证码类型字段混用。

funcaptcha.challengeInfo 允许字段:publicKey,site,surl,apiUrl,capiMode,styleTheme,locationHref,documentReferrer,documentTitle,iframeUrl,ancestorOrigins,treeIndex,treeStructure,languageEnabled,jsfEnabled,appMode,uniqueFingerprint,oldFingerprint,overrideFingerprint,syntheticFingerprint,randomProtoChain,randomVideoExtended,staticSpeechData,customTimezoneOffset,historyLength,noIframe,lowBandwidthMode,storageAccess,solvePOW,cookieTimestamp,disableArid,disableAridCookie,disableCookies,disableCookiesAnalytics,disableGT2Cookies,disableNavigatorCookies,powPause,exploitMode,skipHighWaves,submitAnswerPause,extraData。browserInfo 允许字段:Accept-Language,Cache,Cookie,DNT,HTTP3,Linux,Mac,Mobile,Safari,Sec-Ch-Ua,Sec-Ch-Ua-Platform,User-Agent,dataBrands,languages,randomTLS,userbrowser。未列出的字段会被拒绝。

余额与充值

方法与路径 请求 响应
GET /v1/balance billing {"availableMicros":1000000,"reservedMicros":0,"currency":"USD"}。
GET /v1/ledger?before=123 billing;before 为上一页 nextCursor 的正整数 {"entries":[{"id":123,"kind":"credit","availableDeltaMicros":1000000,"reservedDeltaMicros":0,"at":"..."}],"nextCursor":...}。
POST /v1/recharge-codes/redeem billing;{"code":"..."} 200 {"amountMicros":1000000};充值 Key 一次性使用,已用/过期/撤销统一返回 409 RECHARGE_CODE_UNAVAILABLE。
GET /v1/topup-orders / GET /v1/topup-orders/{id} billing;历史记录 {"orders":[...]} / 订单对象。
PUT /v1/topup-orders/{id} / POST /v1/topup-orders/{id}/cancel billing;仅处理已有、仍允许修改/取消的历史订单。PUT 请求可含 paymentChannel,payerReference,customerNote,至少一个字段 更新后的订单对象。

充值只支持管理员人工入账或管理员发行充值 Key 后由客户兑换。客户 POST /v1/topup-orders 固定返回 410 TOPUP_ORDERS_DISABLED,GET /v1/topup-orders/instructions 返回 410 PAYMENT_METHODS_DISABLED。平台没有公开的银行卡、支付宝、微信、USDT、PayPal 或自动付款 API。余额以账本与 GET /v1/balance 为准,不根据客户端付款提示自行增加。

工单与公告

方法与路径 请求/参数 响应
GET /v1/tickets?status=&limit=50&offset=0 已认证;状态 awaiting_support、awaiting_customer、closed {"tickets":[Ticket...],"total":1}。
POST /v1/tickets 可选 Idempotency-Key;{"category":"technical","subject":"任务结果异常","body":"请协助核查任务 ..."} 201 {"ticket":Ticket};幂等重放为 200 且带 Idempotent-Replayed: true。分类为 technical,billing,account,other;主题 5–120 字符,正文 10–5000 字符。
GET /v1/tickets/{id}?before=123 已认证;每页最多 50 条消息 {"ticket":Ticket,"messages":[TicketMessage...],"nextBefore":123};非零游标继续翻页。内部备注不会显示给客户。
POST /v1/tickets/{id}/messages 可选 Idempotency-Key;{"body":"补充信息"},正文 1–5000 字符 200 {"ticket":Ticket},幂等重放时带 Idempotent-Replayed: true 且不追加消息;关闭工单回复可能返回 409 TICKET_CLOSED。
POST /v1/tickets/{id}/close / POST /v1/tickets/{id}/reopen 已认证 200 {"ticket":Ticket}。
GET /v1/announcements?limit=50&offset=0 无需登录 {"announcements":[{"id":"uuid","title":"...","body":"...","publishedAt":"..."}],"total":1};仅展示已发布的网站公告。邮件专属公告不在这里显示。

Ticket 含 id,customerId,customerName,category,subject,status,priority,assignedTo,version,createdAt,updatedAt,lastMessageAt,closedAt,messageCount;TicketMessage 含 id,ticketId,authorKind,authorRef,body,internal,createdAt。工单有未关闭数量(20 个)和频率限制(24 小时内创建 10 个)。

创建工单和客户回复可带 Idempotency-Key(8–128 个可见 ASCII 字符,不含空格;格式不符返回 400 INVALID_IDEMPOTENCY_KEY)。键按客户隔离、24 小时内有效:同一键重试相同请求(首尾空白不影响)时返回原工单当前状态,不会重复创建或追加消息,即使工单已关闭或已达到频率上限;同一键用于不同内容、不同工单或在创建与回复之间混用时返回 409 IDEMPOTENCY_CONFLICT。网络错误或 5xx 时应以同一键原样重试;每次新的工单或回复须使用新键。不带该头时保持原有行为,每次请求都会写入。公告正文按纯文本展示;邮箱公告为异步发送,网站接口不代表邮件已送达。

Webhook

推荐多端点接口,最多 10 个端点;地址必须是公开可访问的 HTTPS 443 URL,不允许凭据、查询串或片段。创建与密钥轮换的 signingSecret 只返回一次。

方法与路径 请求/参数 响应
GET /v1/webhooks account {"endpoints":[...],"availableEvents":[...],"maxEndpoints":10}。
POST /v1/webhooks {"url":"https://hooks.example.com/solvehub","description":"prod","events":["task.completed","task.failed"],"enabled":true} 201 {"endpoint":WebhookEndpoint,"signingSecret":"whsec_..."};空 events 默认订阅全部任务事件。
GET /v1/webhooks/{id} / PUT /v1/webhooks/{id} / DELETE /v1/webhooks/{id} account;PUT 为整体更新 url,description,events,enabled 端点对象 / 更新后端点 / 204。
POST /v1/webhooks/{id}/rotate-secret account;可选 {"graceHours":24} 200 {"endpoint":...,"signingSecret":"..."};宽限期内可能发出新旧两个签名。
POST /v1/webhooks/{id}/test account 202 {"eventId":123,"status":"pending"}。每位客户跨端点每 60 秒最多创建一条测试投递;过快返回 429 WEBHOOK_TEST_RATE_LIMITED 和 Retry-After: 60。
GET /v1/webhook/deliveries account;可选 endpointId,status,before,limit,状态 pending,delivered,dead {"deliveries":[...],"nextCursor":"..."}。
POST /v1/webhook/deliveries/{id}/retry account;用于失败投递 202 {"status":"pending"}。
GET /v1/webhook / PUT /v1/webhook / DELETE /v1/webhook account;旧版主端点接口,PUT {"url":"https://..."} 旧版单端点视图 / 带 signingSecret 的配置 / 204。

可订阅事件:task.completed、task.failed、task.cancelled、task.uncertain、api_key.expiring、api_key.expired、api_key.renewed、balance.low、topup_order.paid、topup_order.rejected、topup_order.expired。手动测试事件为 webhook.test,无需订阅。部分历史订单事件只针对已存在的订单。

balance.low 在可用余额因任务预占、Key 续费、人工扣减或冲正,从至少 5 USD 降到低于 5 USD 时产生;预占余额不计入可用余额。事件载荷包含 availableMicros 与 thresholdMicros。已验证的通知邮箱也会收到邮件;未验证邮箱不会收件。余额随后补至至少 5 USD,再次跌破时会产生新提醒。已低于阈值的历史余额不会因部署本功能而补发提醒。

平台 POST JSON 到端点,头为 X-SolveHub-Event-ID(十进制事件 ID)、X-SolveHub-Event-Type、X-SolveHub-Timestamp(Unix 秒)及 X-SolveHub-Signature。任务事件正文示例:{"event":"task.completed","occurredAt":"2026-10-02T00:00:00Z","taskId":"uuid","type":"turnstile","status":"completed","traceId":"uuid","priceMicros":200};测试事件含 event,testId,endpointId,occurredAt。签名为 sha256= 加上 HMAC-SHA256(signingSecret, timestamp + "." + 原始请求体字节) 的十六进制值;轮换宽限期内签名头可能是逗号分隔的两个 sha256= 值,验证任意一个即可。接收端应在读取原始字节后校验时间窗口、恒时比较签名、按事件 ID 去重,再快速返回 2xx;非 2xx 会重试,投递可重复、也可能晚到。事件载荷不是最终结算依据,任务事件收到后查询 GET /v1/tasks/{id}。

兼容接口

POST /createTask、POST /getTaskResult、POST /getBalance 接受 clientKey JSON 字段;业务成功或失败均可能返回 HTTP 200,必须检查 errorId(0 成功、1 失败)和 errorCode。createTask 支持原生类型及 ImageToTextTask、TurnstileTask、TurnstileTaskProxyless、TurnstileTaskProxyLess、AntiTurnstileTaskProxyLess 别名。

接口 请求示例 成功响应与注意事项
POST /createTask {"clientKey":"sh_...","task":{"type":"TurnstileTaskProxyless","websiteURL":"https://example.com","websiteKey":"SITE_KEY"}} {"errorId":0,"taskId":"uuid"};图片 OCR 兼容请求用 ImageToTextTask 和 body 图片字段。
POST /getTaskResult {"clientKey":"sh_...","taskId":"uuid"} 进行中含 {"errorId":0,"status":"processing"},包括原生 uncertain;完成含 status:"ready",solution,cost,createTime,endTime,solveCount。cost 是美元字符串,时间是 Unix 秒。失败/取消返回 errorId:1,errorCode:"ERROR_CAPTCHA_UNSOLVABLE"。
POST /getBalance {"clientKey":"sh_..."} {"errorId":0,"balance":1.25},单位 USD 浮点数;财务核对请用微美元整数的 /v1/balance。

兼容错误可能为 ERROR_KEY_DOES_NOT_EXIST、ERROR_KEY_DENIED_ACCESS、ERROR_IP_NOT_ALLOWED、ERROR_ACCOUNT_SUSPENDED、ERROR_BAD_PARAMETERS、ERROR_TASK_NOT_SUPPORTED、ERROR_NO_SLOT_AVAILABLE、ERROR_ZERO_BALANCE、ERROR_NO_SUCH_CAPCHA_ID 或 ERROR_SERVICE_UNAVAILABLE。兼容创建接口没有幂等键,超时后盲目重试可能再次创建任务和预占余额;新集成应使用 /v1/tasks。

最小接入示例

export SOLVEHUB_URL='https://www.tiam.codes'
export SOLVEHUB_API_KEY='sh_REPLACE_ME'
curl -sS -H "Authorization: Bearer $SOLVEHUB_API_KEY" "$SOLVEHUB_URL/v1/balance"
curl -sS -X POST "$SOLVEHUB_URL/v1/tasks" \
  -H "Authorization: Bearer $SOLVEHUB_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: your-order-12345' \
  -d '{"type":"turnstile","task":{"websiteURL":"https://example.com","websiteKey":"SITE_KEY"}}'

接入时保存 taskId、幂等键和 X-Request-ID。不要在日志、截图或工单中提交完整 API Key、充值 Key、密码、TOTP 秘钥或原始代理凭据。

DataDome 挑战 URL 工具

POST /v1/datadome/build-url:要求有效 Key 的 tasks 权限和可用账户,同步返回结果,免费且不创建解题任务。传入 websiteURL(≤ 2048 字节)及 body、location、captchaUrl 至少一个。body 为捕获的 HTML/JSON(≤ 1 MiB);location 和 captchaUrl 各 ≤ 4096 字节。优先采用已提供的 captchaUrl。不要传入内部服务的凭据。

curl -sS -X POST 'https://www.tiam.codes/v1/datadome/build-url' \
  -H 'Authorization: Bearer sh_REPLACE_ME' \
  -H 'Content-Type: application/json' \
  --data '{"websiteURL":"https://example.com/login","body":"{\"url\":\"https://geo.captcha-delivery.com/captcha/?cid=EXAMPLE\"}"}'
{"captchaUrl":"https://geo.captcha-delivery.com/captcha/?cid=EXAMPLE","challengeType":"captcha"}

成功返回 captchaUrl,challengeType;URL 原样用于 DataDome 解题任务。错误:400 INVALID_DATADOME_PAYLOAD、422 DATADOME_CHALLENGE_NOT_FOUND、503 DATADOME_BUILDER_UNAVAILABLE(稍后退避重试)、502 DATADOME_BUILDER_FAILED。兼容 POST /buildDataDomeUrl 在 JSON 中传 SolveHub 的 clientKey,使用 HTTP 200 和 errorId/errorCode/errorDescription。此工具不需要 Idempotency-Key;解题任务仍使用原有幂等和计费规则。

浏览器支持范围和可复制的 UA 示例见支持的 User-Agent。处理软时限从任务确认受理后起算;DataDome 为 240 秒,PerimeterX 为 210 秒。

可选查询参数 keyId 可用于 GET /v1/tasks 和 GET /v1/usage,仅筛选当前客户对应 Key 的任务;省略时仍按原方式汇总全部 Key。任务响应的 keyId 为 Key ID,非密钥明文;历史任务可能省略该字段。GET /v1/ledger 支持 kind(credit,reserve,capture,refund,fee,reversal,adjustment)在全部历史流水中筛选,翻页时请保留相同的 kind。

相关文档

从 cURL 开始接入注册账户

最近更新: