{
  "openapi": "3.1.0",
  "info": {
    "title": "Voice API",
    "version": "0.1.0-preview",
    "description": "一般利用準備中のプレビュー仕様です。現在、文字起こしの新規受付は無効で503を返します。有効化後も登録・利用者のAPIキーは不要です。音声の送信には話者の同意を取得してください。1回60秒、IPごと10回/日、全体120回/日・同時4件を上限とする実験サービスです。取得IDは一時的な秘密の閲覧キーです。公開・共有しないでください。"
  },
  "servers": [{ "url": "https://voice.2-38.com" }],
  "security": [],
  "paths": {
    "/v1/health": {
      "get": {
        "operationId": "getVoiceHealth",
        "summary": "API稼働状態と受付可否",
        "responses": { "200": { "description": "enabled=falseの場合は一般受付停止中", "content": { "application/json": { "schema": { "type": "object", "properties": { "enabled": { "type": "boolean" } }, "required": ["enabled"] } } } } }
      }
    },
    "/v1/limits": {
      "get": {
        "operationId": "getVoiceLimits",
        "summary": "現在の利用上限",
        "responses": { "200": { "description": "上限の設定値", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    },
    "/v1/transcriptions": {
      "post": {
        "operationId": "createTranscription",
        "summary": "音声ファイルの非同期文字起こし",
        "description": "PCM16 little-endian / 16kHz / mono のRIFF WAVをリクエストボディで直接送ります。multipartではありません。最大60秒。ブラウザSDKはブラウザが読める音声をこの形式へ変換します。サーバー側で実際のWAV構造・データ量を検証します。",
        "requestBody": { "required": true, "content": { "audio/wav": { "schema": { "type": "string", "format": "binary" } } } },
        "responses": {
          "202": { "description": "受付完了。idで結果をポーリングしてください。", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Job" } } } },
          "400": { "$ref": "#/components/responses/InputError" },
          "413": { "$ref": "#/components/responses/InputError" },
          "415": { "$ref": "#/components/responses/InputError" },
          "429": { "$ref": "#/components/responses/Limited" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/v1/transcriptions/{id}": {
      "get": {
        "operationId": "getTranscription",
        "summary": "非同期文字起こし結果の取得",
        "description": "作成時のランダムIDをそのまま渡してください。結果の有効期間は1時間です。IDを知る人は結果を読めるので、URLの公開やログ保存を避けてください。全件一覧APIはありません。",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "minLength": 43, "maxLength": 128 } }],
        "responses": {
          "200": { "description": "進捗または文字起こし結果", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Job" } } } },
          "404": { "description": "存在しない・期限切れのID" },
          "429": { "$ref": "#/components/responses/Limited" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/v1/realtime": {
      "get": {
        "operationId": "openRealtimeTranscription",
        "summary": "リアルタイム音声入力のWebSocket",
        "description": "wss://voice.2-38.com/v1/realtime へ接続しreadyを待ちます。binary frameでPCM16 little-endian /16kHz/monoを順番に送信。推奨は100ms=3200bytesごと。合計最大60秒。停止はJSON {\"type\":\"stop\"}。受信イベントは ready、transcript {text,final_text,partial_text}、done {text}、error {error:{code,message}}。doneは最終結果、途中結果はtranscriptイベント全体のtextを置換表示します。独自設定やAPIキーは送信しません。ブラウザSDKはマイク取得・変換・接続・後始末を担当します。",
        "responses": {
          "101": { "description": "WebSocket接続確立" },
          "426": { "description": "WebSocket Upgradeが必要" },
          "429": { "$ref": "#/components/responses/Limited" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Job": {
        "type": "object",
        "required": ["id", "status"],
        "properties": {
          "id": { "type": "string", "description": "一時的な閲覧キー。秘密として扱うこと。" },
          "status": { "type": "string" },
          "text": { "type": "string" },
          "error": { "$ref": "#/components/schemas/ErrorDetail" }
        }
      },
      "ErrorDetail": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } } }
    },
    "responses": {
      "InputError": { "description": "音声形式・サイズ・リクエストが不正" },
      "Limited": { "description": "回数または同時実行の上限。再試行は間隔を空けてください。" },
      "Unavailable": { "description": "受付停止中、未設定、または処理サービスの一時的な障害" }
    }
  }
}
