SolveHub

API リファレンス

SolveHub REST API リファレンス:タスク、料金、残高、Webhook

SolveHub カスタマー API の完全リファレンス:Bearer API Key 認証、タスク作成とポーリング、リアルタイム料金、残高と台帳、サポートチケット、Webhook、全エラーコード。

許可された QA 自動化とブラウザー連携向けです。テスト権限のあるサイトと業務フローでのみ使用してください。

本書は現行の HTTP ルーティング、アプリケーションサービスおよびタスクパラメータの検証に基づいて作成されています。本番環境のベース URL は https://www.tiam.codes で、以下のパスはすべてこのアドレスからの相対パスです。ローカルのデフォルトは http://127.0.0.1:8080 で、本番環境では必ず HTTPS を使用してください。すべての例に含まれるキー、メールアドレス、ドメインはプレースホルダーです。レスポンスの時刻は RFC 3339 形式、金額は マイクロ USD(micros)の整数 です:1 USD = 1,000,000 micros。価格は GET /v1/prices のリアルタイム値が優先され、タスク作成時にその回の販売価格が確定します。

共通仕様

通常の API では Authorization: Bearer <API_KEY> を使用し、JSON の書き込みリクエストには Content-Type: application/json を付けます。顧客向け Web 画面では HttpOnly、SameSite=Strict の solvehub_portal Cookie を使用します。Cookie 認証による GET/HEAD 以外のリクエストには必ず X-SolveHub-Portal: 1 を付けてください。ログイン、登録、ログアウトのリクエストにもこのヘッダーが必要です。Bearer は Cookie より優先されます。ブラウザが意図せず別のキーの Authorization ヘッダーを付加しないようにしてください。

すべてのレスポンスには X-Request-ID が付与され、サポートに問題を特定してもらう際に利用できます。失敗レスポンスは通常 {"error":"ERROR_CODE"} で、成功レスポンスとは形式が異なります。204 にはレスポンスボディがありません。リクエストボディは 1 つの 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(メールアカウントにまだキーが紐付けられていない)、PORTAL_CSRF_CHECK_FAILED、KEY_SPEND_FROZEN、KEY_QUOTA_EXHAUSTED(このキーの総額度を使い切りました。返金されても額度は戻らないため、プラットフォームに調整を依頼するか、別のキーを使用してください)。期限切れキーによる課金での更新(延長)は RENEWAL_REAUTH_REQUIRED を返します。
404 現在の顧客から参照できない、または存在しないリソース。他の顧客のリソースが存在するかどうかの判断には使用しないでください。
409 状態/バージョンまたは冪等性の競合。IDEMPOTENCY_CONFLICT、VERSION_CONFLICT など。
410 廃止された旧チャージ注文の作成および支払い案内エンドポイント。
429 クォータ、サポートチケットの頻度、またはログインの制限。KEY_SPEND_LIMIT は現在のキーの 24 時間安全上限に達したことを示し、レスポンスに Retry-After: 300 が付きますが、実際の回復時刻は過去の仮押さえが集計ウィンドウから外れるタイミングによって決まります。KEY_CONCURRENCY_LIMIT は、このキーで待機中または処理中のタスク数が、プラットフォームが設定した同時実行上限に達したことを示します。既存のタスクが終わってから再送信してください。レスポンスに Retry-After: 60 が付きます。
500/503 内部障害または依存サービスの利用不可。冪等キー(Idempotency-Key)がある場合は同じリクエストと同じキーで再試行し、先に作成済みのリソースを確認してください。データベースの一時的な障害はサーバー側で自動再試行され、約 10 秒経っても回復しない場合は 503 DATABASE_BUSY と Retry-After: 1 を返します。読み取りリクエストはそのまま再試行できます。書き込みリクエストは(コミット結果を確認できない場合)すでに反映されている可能性があるため、同じ冪等キーで再試行するか、先に確認してください。

API キーの権限(スコープ)は tasks(タスク、利用量)、billing(残高、台帳、チャージキー、過去の注文)、account(アカウント情報、キーのメタデータ、Webhook、セッション一覧)です。キーの作成・変更・失効、連絡先メールアドレスの変更、他デバイスのセッション終了には、さらにメールアドレスとパスワードによるアカウントセッションが必要です。account 権限を持つキーでもこれらの重要な変更は実行できません。一部の猶予対象エンドポイントは期限切れキーも受け付けます(残高、チャージキーの引き換え、更新(延長)履歴、サポートチケットなど)。期限切れキーではタスクを作成できず、自身の認証情報で課金による更新(延長)を承認することもできません。凍結されたアカウントは、新規タスクやチャージキーの引き換えなどの操作を実行できません。サポートチケットは認証済みの顧客 ID を使用し、個別の権限スコープはありません。

ログイン不要の GET /healthz は {"status":"ok"} を返し、API プロセスが稼働していることを示します。GET /readyz は {"status":"ready"} を返し、データベースとマイグレーションマーカーが利用可能であることを示します。異常時は 503 DATABASE_UNAVAILABLE を返します。これら 2 つのエンドポイントは、タスク処理能力が利用可能であることを保証するものではありません。

認証とセッション

メソッドとパス リクエスト 成功レスポンス
POST /v1/portal/register/email ログイン不要、X-SolveHub-Portal: 1。{"email":"ops@example.com"} 204。認証コードは送信キューに追加されます。登録には事前のメール認証が必須です。コードの有効期限は 20 分で 1 回のみ使用でき、再取得すると以前のコードは無効になり、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"}。ログイン用メールアドレスは直ちに確認済みとなるため、未確認のアカウントは作成されません。
POST /v1/portal/account/bind-key アカウントセッション、X-SolveHub-Portal: 1。{"apiKey":"sh_..."} 200 {"customerId":"uuid","keyId":"uuid","merged":true}。未紐付けアカウントの場合:アカウント(ログインメールアドレス、パスワード、TOTP、現在のセッション)全体がそのキーの所属顧客の配下に移され、merged:true となり、再ログインは不要です。その顧客にすでにメールアカウントがある場合は 409 KEY_ALREADY_BOUND を返します。紐付け済みアカウントの場合:自分の顧客のキーのみ貼り付けでき、旧キーの暗号化された平文を保存して後で表示できるようにするためのもので、merged:false となります。他の顧客のキーは 409 KEY_OWNED_BY_OTHER_CUSTOMER を返します。キーが存在しないか取り消し済みの場合は 404 KEY_NOT_FOUND。失敗は送信元ごとにカウントされ、多すぎる場合は 429 BIND_THROTTLED を返します。
POST /v1/portal/session {"apiKey":"sh_..."}、X-SolveHub-Portal: 1 を付与 200 セッションビューを返し Cookie を設定します。キーセッションは元のキーの権限、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 を返し、キーセッションではログインメールアドレスを返しません。
POST /v1/portal/account/claim キーセッションかつ account 権限。{"email":"...","password":"..."} 204。キーの保有者が自分で紐付けでき、管理者の開設コードは不要です。各顧客は 1 回のみ紐付けでき、再送信すると 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 分で、1 回のみ使用できます。通知用メールアドレスはログインメールアドレスと異なってもよく、認証状態はログインメールアドレスにのみ属します。
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 分で、1 回のみ使用できます。通知用メールアドレスを変更すると旧コードは無効になります。無効なコードは 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 が必須です。メールの認証コードとリカバリーコードはいずれも 1 回のみ使用できます。成功するとすべてのアカウントセッションが無効になりますが、API キーは変わりません。無効なコードは一律で 400 RECOVERY_INVALID を返します。
POST /v1/portal/account/totp {"password":"..."} 200 {"secret":"...","uri":"otpauth://..."}。安全に保管し、ログに書き込まないでください。
POST /v1/portal/account/totp/confirm アカウントセッション。{"code":"123456"} 200 {"recoveryCodes":["SHRC-...",...]}。検証に成功すると直ちに 2 段階認証が有効になり、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 キーを貼り付けると、アカウントはそのキーの顧客に帰属します。1 つのアカウントは 1 つの顧客に対応し、その顧客の複数のキーを管理できます。同じ顧客に紐付けられるメールアカウントは 1 つだけです。未紐付けの間は、セッション、セキュリティ設定、紐付けのエンドポイント以外はすべて 403 ACCOUNT_UNBOUND を返します。キーを持っていてメールアカウントがまだない顧客は、引き続きキーでログインし、「セキュリティ」ページでメールアドレスを紐付けることもできます(account/claim を参照)。

パスワードは 12~128 文字の Unicode 文字で、6 種類以上の異なる文字を含み、メールアドレスを含めてはいけません。特殊文字の混在は必須ではありません。セッションビューには authMethod,sessionId,customerId,customerName,customerStatus,keyId,keyLabel,scopes,keyExpiresAt,keyExpired,expiresAt,idleTimeoutSeconds が含まれます。アカウントセッションの authMethod は account、キーセッションは api_key です。セッションはログインから 24 時間で失効します。アカウントセッションは特定の API キーから独立しています。キーセッションはそのキーが取り消されると失効します。TOTP 認証コードは同じタイムステップ内で再利用できません。ログイン失敗には IP 単位とアカウント単位の制限があり、429 LOGIN_THROTTLED を受け取った場合は Retry-After に従ってください。既存アカウントのログインメールアドレスはデフォルトで未認証であり、コンソールの「セキュリティ」ページで認証を済ませるまでセルフサービスでのパスワード復旧はできません。認証アプリを紛失した場合は、使い捨てリカバリーコードでログインする、2FA を無効にする、または認証済みのログインメールアドレスに届くメール認証コードと組み合わせてパスワードを再設定することができます。リカバリーコードも紛失した場合は、管理者に連絡して本人確認を受けてください。リカバリーコードは有効化時または再生成時にのみ表示されるため、サポートチケット、チャット、ログに貼り付けないでください。

**キー漏えい時の対応:**パスワードによるアカウントセッションをまだ保持している場合は、POST /v1/portal/keys/{id}/compromise(account 権限)で漏えいしたキーを緊急に取り消してください。このエンドポイントは最後の 1 本のキーも取り消せますが、通常の DELETE /v1/keys/{id} ではできません。その後 GET /v1/portal/sessions、GET /v1/ledger、タスク一覧を確認し、不審なセッションを取り消して代替キーを作成してください。必要に応じて運営に連絡し、顧客を凍結してもらってください。期限切れになった漏えいキーは、自身の認証情報で課金による更新(延長)を行うことはできなくなります。まだ取り消されていない漏えいキーは、その安全上限の範囲内でタスクを作成できます。そのため、漏えいに気付いたら直ちに取り消してください。漏えいしたキーだけを持ち、アカウントセッションを持たない攻撃者は緊急エンドポイントを呼び出せませんが、取り消しの伝播は複数インスタンスのキャッシュの影響を受けるため、できるだけ早く運営に連絡してください。

新規ユーザーのトライアル残高(Telegram 連携)

メールアドレスとパスワードのアカウントを登録した後、コンソールの「セキュリティ → Telegram 連携」から 1 つの Telegram アカウントを連携・認証できます。認証が完了すると 0.10 USD のトライアル残高が一度だけウォレットに付与され、入金なしで API を利用できます。

メソッドとパス リクエスト 成功時のレスポンス
GET /v1/portal/account/telegram メールアドレス・パスワードのアカウントセッション enabled,status,tgUsername,verifiedAt,trialCredited,trialAmountMicros,trialMaxActive。status は未開始なら空、Telegram 内での確認待ちなら pending、付与済みなら 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 を使用します。1 つの Telegram アカウントは 1 つの SolveHub アカウントにのみ連携でき、1 つのアカウントは 1 つの Telegram アカウントにのみ連携できます。
  • 連携は解除できません。認証後に連携し直したり再登録しても、トライアル残高を再び受け取ることはできません。
  • Bot の返信言語はコンソールの表示言語に従います。bind に {"locale":"zh|en|ja"} を付けるとその言語で返信し、省略時は Telegram クライアントの言語、判別できない場合は英語になります。
  • トライアル残高に有効期限はありませんが、同時実行 1 タスク 分に相当します。認証時にその顧客の max_active が 1 に制限されるため、前のタスクが終わってから次を送信してください。チャージコード、Cregis 入金、注文の確定、プラスの調整など、金額を問わず入金が反映されるとこのシステム設定の制限は自動的に解除され、既定の同時実行数に戻ります。運用側が手動で設定した配额は変更されません。
  • 付与は credit の 1 件の台帳エントリ(備考「新規ユーザーの Telegram 認証特典」)として記録され、reference が一意なため繰り返し実行しても二重に加算されません。
  • 未連携アカウント(status: unbound)は認証成功後に active へ移行し、「API キー」ページでキーを作成できます(customerKeyCreation が false の場合は運用側が発行します)。

アカウントと API キー

メソッドとパス リクエスト/パラメータ 成功レスポンス
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 認証(任意の権限、期限切れキーでも読み取り可) この顧客に適用される単価。構造は GET /v1/prices と同じで、追加で negotiated と listPriceMicros を含みます。後述の「価格」を参照してください。
GET /v1/keys/policy 認証 customerKeyCreation,maxActiveKeys,maxValidityDays,customerRenewal,reminderDays。
GET /v1/keys account {"keys":[APIKeyMeta...]}。一覧には平文を含みません。viewable:true のキーは下記の 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 USD と 20 USD です。空の scopes はすべての権限、空の許可リストは送信元の制限なしを意味します。
GET /v1/keys/{id} 自身のキーまたは account 権限 APIKeyMeta。
POST /v1/keys/{id}/reveal アカウントセッション、X-SolveHub-Portal: 1。TOTP が無効な場合は {"password":"..."}、有効な場合は {"code":"123456"}(ワンタイムコードまたはリカバリーコード) 200 {"apiKey":"sh_..."}。Cache-Control: no-store 付きで、表示のたびに監査ログに記録されます。キーセッションでは 403 ACCOUNT_SESSION_REQUIRED、パスワード誤りは 400 INVALID_PASSWORD、2 段階認証コードの欠落または誤りは 400 TOTP_REQUIRED / 400 TOTP_INVALID を返します。キーの平文が保存されていない場合(旧キー、またはサーバーにデータ暗号化キーが未設定)は 409 KEY_NOT_VIEWABLE を返します。旧キーは 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。通常の取り消しでは、最後の 1 本の有効なキーは取り消せません。
GET /v1/keys/renewal-plans 認証 {"enabled":true,"plans":[{"code":"month","name":"30 天","days":30,"priceMicros":0}],"currency":"USD"}。価格は例であり、必ずリアルタイム値を取得してください。
POST /v1/keys/{id}/renew 有効な自身のキー、有効で account 権限を持つ他のキー、またはアカウントセッション。Idempotency-Key は 8~128 文字。{"plan":"month"} 初回は 201、リプレイ時は 200 で Idempotent-Replayed: true 付き。レスポンスは更新(延長)記録です。期限切れキー自身からのリクエストは 403 RENEWAL_REAUTH_REQUIRED を返します。アカウントセッション、または有効で account 権限を持つ他のキーから更新(延長)できます。
GET /v1/keys/{id}/renewals?limit=50 自身のキーまたは account {"renewals":[...]}。

通知用メールアドレスとログインメールアドレスはそれぞれ個別に認証され、アドレスが同じでも認証状態は共有されません。未認証の通知用メールアドレスには、お知らせ、サポートチケットの返信、キーのリマインダー、財務関連のメールは届きません。キューに入っていてまだ配信されていない旧アドレス宛ての業務メールは、アドレス変更後に破棄されます。すでに送信されたメールは取り消せません。キーのみを使用している顧客は、まず「セキュリティ」ページで account 権限を持つキーを使ってメールアドレスとパスワードを自分で紐付けてから、通知用メールアドレスを設定・認証してください。

APIKeyMeta には keyId,label,hint,status,scopes,ipAllowlist,expiresAt,lastUsedAt,lastUsedIp,createdBy,createdAt,revokedAt,version,spendLimit24hMicros,spendFreezeHourMicros,spendFrozenAt,viewable が含まれます。viewable はサーバーがそのキーの暗号化された平文を保存していることを示し、アカウントセッションで 2 段階認証を行った後に表示できます。取り消すと平文は直ちに削除されます。expiresAt:null は無期限を意味し、状態は active、expired、revoked のいずれかです。spendFrozenAt が空でない場合は、1 時間の累計仮押さえ額がしきい値を超えたため、タスク作成が凍結されていることを示します。2 つの上限額はいずれも正の整数のマイクロ USD で、最大 10,000 USD です。また 1 時間のしきい値は 24 時間の上限を超えることはできません。上限額は 5 分単位のウィンドウで保守的に集計され、最大で約 5 分間余分に制限される場合があります。失敗またはキャンセル後の返金によって安全上限枠は解放されず、作成と返金を繰り返す試行を防ぎます。凍結のきっかけとなったリクエストではタスクは作成されず、ウォレットも変動しません。連絡先メールアドレスが設定されメールサービスが利用可能な場合は通知が送信されますが、メールを凍結発効の前提としないでください。凍結を解除する前に、タスクと台帳を確認してください。ラベルは 1~100 文字です。IP 許可リストは単一アドレスまたは CIDR を受け付け、最大 32 件です。API キーを URL、ブラウザのローカルストレージ、サポートチケットの本文に含めないでください。キーの account 権限では他のキーのメタデータの読み取りと Webhook の管理ができますが、キーの発行や変更はできません。タスク処理用のプロセスには 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 となります。無効または未設定のタイプは、契約価格があっても価格を提示しません。価格の提示とタスク作成は同じルールを使用しますが、2 つのリクエストの間に価格が変更される可能性はあり、最終的な仮押さえ額は作成レスポンスの 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、確認待ち(uncertain)の場合は 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。プロキシ 4 項目 proxyType,proxyAddress,proxyPort と任意のログイン情報。
interstitial websiteURL,proxyType,proxyAddress,proxyPort siteKey(ページの Turnstile sitekey。高速パスを使用可能)、useragent,source(ブール値)、method(GET/POST)、プロキシのログイン情報。
perimeterx websiteURL,websiteKey とプロキシ 4 項目 useragent、プロキシのログイン情報。
datadome websiteURL,captchaUrl とプロキシ 4 項目 useragent; プロキシのログイン情報。
akamai websiteURL とプロキシ 4 項目 useragent; ApiURL、プロキシのログイン情報。
aliyun websiteURL,websiteKey,prefix とプロキシ 4 項目 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 の複雑な構造は、そのタイプの検証ルールに従って送信し、他の CAPTCHA タイプのフィールドを混在させないでください。

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}。チャージキーは 1 回限りで、使用済み/期限切れ/取り消し済みの場合は一律で 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 を含めることができ、少なくとも 1 つのフィールドが必要です 更新後の注文オブジェクト。

チャージは管理者による手動入金、または管理者が発行したチャージキーを顧客が引き換える方法のみに対応しています。顧客による POST /v1/topup-orders は常に 410 TOPUP_ORDERS_DISABLED を返し、GET /v1/topup-orders/instructions は 410 PAYMENT_METHODS_DISABLED を返します。プラットフォームには、銀行カード、Alipay、WeChat、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 認証済み。1 ページあたり最大 50 件のメッセージ {"ticket":Ticket,"messages":[TicketMessage...],"nextBefore":123}。0 以外のカーソルで続きのページを取得します。内部メモは顧客には表示されません。
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 個です。URL は公開アクセス可能な HTTPS 443 の URL である必要があり、認証情報、クエリ文字列、フラグメントは使用できません。作成時とシークレットのローテーション時の signingSecret は 1 回のみ返されます。

メソッドとパス リクエスト/パラメータ レスポンス
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":"..."}。猶予期間中は新旧 2 つの署名が送信される場合があります。
POST /v1/webhooks/{id}/test account 202 {"eventId":123,"status":"pending"}。各顧客はエンドポイント全体で 60 秒ごとに最大 1 件のテスト配信を作成できます。間隔が短すぎる場合は 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 は、タスクの仮押さえ、キーの更新(延長)、手動での減額または取消処理によって、利用可能残高が 5 USD 以上から 5 USD 未満に下がったときに発生します。仮押さえ中の残高は利用可能残高に含まれません。イベントのペイロードには availableMicros と thresholdMicros が含まれます。認証済みの通知用メールアドレスにもメールが届きます。未認証のメールアドレスには届きません。その後残高が 5 USD 以上に補充され、再びしきい値を下回った場合は、新たな通知が発生します。すでにしきい値を下回っていた過去の残高について、本機能のデプロイを理由に通知が後から送信されることはありません。

プラットフォームはエンドポイントに JSON を POST し、ヘッダーは X-SolveHub-Event-ID(10 進数のイベント 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 + "." + 原始请求体字节) の 16 進数値を付けたものです。ローテーションの猶予期間中は、署名ヘッダーがカンマ区切りの 2 つの sha256= 値になる場合があり、いずれか一方を検証できれば構いません。受信側は生のバイト列を読み取った後、タイムウィンドウを検証し、定数時間で署名を比較し、イベント ID で重複排除してから、速やかに 2xx を返してください。2xx 以外の場合は再試行され、配信は重複したり遅れて届いたりする場合があります。イベントのペイロードは最終的な精算の根拠ではありません。タスクイベントを受信したら GET /v1/tasks/{id} で確認してください。

互換エンドポイント

POST /createTask、POST /getTaskResult、POST /getBalance は JSON フィールド clientKey を受け付けます。業務上の成功・失敗にかかわらず 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 はUSD の文字列で、時刻は Unix 秒です。失敗/キャンセル時は errorId:1,errorCode:"ERROR_CAPTCHA_UNSOLVABLE" を返します。
POST /getBalance {"clientKey":"sh_..."} {"errorId":0,"balance":1.25}。単位は USD の浮動小数点数です。財務上の照合には、マイクロ 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 キー全体、チャージキー、パスワード、TOTP シークレット、プロキシの生の認証情報を含めないでください。

DataDome チャレンジ URL ツール

POST /v1/datadome/build-url は有効な Key の tasks 権限と有効なアカウントを必要とします。同期応答で無料、解析タスクは作成しません。websiteURL(2048バイト以内)と body、location、captchaUrl の少なくとも一つを指定します。body は取得した HTML/JSON(最大1 MiB)、後二者は各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秒です。

GET /v1/tasks と GET /v1/usage は任意のクエリ keyId に対応し、認証中の顧客に属する該当キーのタスクを絞り込みます。省略時は従来どおり全キーを合計します。タスク応答の keyId は識別子であり、秘密キーの平文ではありません。古いタスクでは省略される場合があります。GET /v1/ledger は全履歴に対する kind(credit,reserve,capture,refund,fee,reversal,adjustment)に対応します。次ページでも同じ kind を指定してください。

関連ドキュメント

cURL で始めるアカウント作成

最終更新: