> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tiro.ooo/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocketプロトコル

> リアルタイム文字起こしWebSocketの接続方法、音声フレームのルール、メッセージのフィールド、終了と再接続の手順、エラーreasonとclose codeをまとめたリファレンスです。

エンタープライズ リアルタイム文字起こしAPIは、エンタープライズプランのお客様に個別のお問い合わせで提供する機能です。利用条件は[概要](https://docs.tiro.ooo/ja/developers/realtime-transcription/overview.md)をご覧ください。

このページでは、セッション作成後に `wsUrl` へ開くWebSocket接続のルールを扱います。セッションの作成、取得、一覧、終了のREST APIは[APIリファレンス](https://docs.tiro.ooo/api-reference/realtime-transcription/create-realtime-transcription.md)にあります。

## セッションと接続はどう違いますか？

セッションはRESTで作成する文字起こしの単位で、接続はそのセッションにつながる1本のWebSocketです。セッションの状態は `OPEN` と `ENDED` の2つだけです。接続は、セッションが `OPEN` の間であれば切れても再びつなげられます。

```mermaid theme={"system"}
stateDiagram-v2
    [*] --> OPEN: POST /v1/external/realtime-transcriptions
    state OPEN {
        state "接続なし" as Idle
        state "接続中" as Connected
        [*] --> Idle
        Idle --> Connected: wsUrl に接続、session.started
        Connected --> Idle: 接続切断 (1001, 1006, 1011, 1012, 4029, 4500, 4503 など)
        Connected --> Connected: 新しい接続が既存の接続を置き換え (既存の接続は 4409)
    }
    OPEN --> ENDED: session.end、REST で終了、タイムアウト
    ENDED --> [*]
```

* セッションが `ENDED` になると元に戻せません。文字起こしを続けるには新しいセッションを作成してください。
* 接続が切れても、セッションは `OPEN` のまま残ります。同じ `wsUrl` と `streamToken` で再接続してください。
* セッションが終了した理由は `endReason` で受け取ります。値は[`session.ended`](#session-ended)にまとめています。

## 接続

`POST /v1/external/realtime-transcriptions` のレスポンスにある `wsUrl` に、`Authorization: Bearer <streamToken>` ヘッダーを付けて接続します。

* `wsUrl` は受け取った値をそのまま使ってください。現在は `wss://<host>/v1/external/realtime-transcriptions/{id}/stream` の形ですが、ホストとパスは変わる可能性があります。
* トークンは `Authorization` ヘッダーでのみ受け付けます。クエリ文字列、Cookie、APIキーでは接続できません。そのため、ヘッダーを設定できないブラウザのWebSocket APIでは接続できません。
* Originヘッダーは検査しません。
* `streamToken` は1つのセッションでのみ使え、セッションが `OPEN` の間は再接続にも同じトークンを使います。トークンはセッション作成のレスポンスでしか受け取れず、再発行するAPIはありません。トークンを失くした場合は、セッションを閉じて新しいセッションを作成してください。

Tiroはまず接続を受け付け、問題があれば `error` メッセージを送ってから接続を閉じます。HTTPステータスで拒否するのは次の3つの場合だけです。

| HTTP | 条件 |
| - | - |
| `400` | WebSocketのアップグレード要求ではありません |
| `401` | `Authorization` ヘッダーにBearerトークンがありません |
| `404` | パスがリアルタイム文字起こしのストリームのパスではありません |

接続を受け付けると、Tiroはトークン、セッションの状態、トークンを発行したAPIキー、ワークスペースのポリシーを確認します。セッション中にポリシーが無効になったりAPIキーが削除されたりしても、Tiroは開いている接続を切らず、次の接続から拒否します。

## 音声フレーム

音声はバイナリフレームで、制御メッセージはテキストフレームで送ります。テキストフレーム1つにはUTF-8のJSONオブジェクトを1つ入れます。

| 項目 | 値 |
| - | - |
| 形式 | 16,000 Hz、モノラル、signed 16-bit little-endian PCM。ヘッダーのないrawデータ |
| データ量 | 1秒あたり32,000バイト |
| フレームサイズ | 最大6,400バイト（200 ms）。3,200バイト（100 ms）を推奨。最小サイズはありません |
| 音声の先行量 | 実際の経過時間より最大60秒先まで送れます |

`session.started` を受け取る前に音声を送ってもかまいません。Tiroは文字起こしの準備が整う前に届いた音声を保持し、続けて処理します。

| 違反 | 結果 |
| - | - |
| 6,400バイトを超えるフレーム | `error`（`audio_frame_too_large`）の後、close `1009` |
| 奇数バイトのフレーム | `error`（`invalid_audio_frame`）の後、close `1007` |
| 音声の先行量が60秒を超過 | `error`（`audio_rate_exceeded`）の後、close `4029` |
| JSONでないテキストフレーム | `error`（`invalid_message`、`fatal: false`）。接続は維持されます |
| 未知の `type` | `error`（`unknown_message_type`、`fatal: false`）。接続は維持されます |
| `session.end` の後に送った音声 | エラーなしで無視します |

### 音声の先行量はどう計算しますか？

音声の先行量は、送った音声の長さが実際の経過時間よりどれだけ先行しているかを表します。Tiroはこの値を接続ごとに測り、60秒を超えると接続を閉じます。

* 何も送らない間に余裕はたまりません。1分間何も送らずに2分ぶんの音声を一度に送っても60秒を超えます。
* 再接続すると直前の接続の先行量を引き継ぎます。再接続で上限がリセットされることはありません。
* 60秒を超えると、`error`（`audio_rate_exceeded`）の `retryAfterMs` に超過分が入ります。その時間以上待ってから再接続し、実時間の速度で送ってください。

## メッセージ

すべてのテキストメッセージに `type` フィールドがあります。長さとオフセットは名前が `Ms` で終わる整数ミリ秒、時刻は名前が `At` で終わるISO-8601 UTC文字列です。ロケールは `ko_KR` のような[対応ロケール](https://docs.tiro.ooo/ja/developers/fundamentals/supported-locales.md)の表記を使います。

| 方向 | `type` | タイミング |
| - | - | - |
| クライアント → Tiro | バイナリフレーム | 音声 |
| クライアント → Tiro | [`session.end`](#session-end) | セッションを終了するとき |
| Tiro → クライアント | [`session.started`](#session-started) | 接続ごとに最初のメッセージとして1回 |
| Tiro → クライアント | [`transcript`](#transcript) | 文字起こしの結果 |
| Tiro → クライアント | [`translation`](#translation) | 翻訳の結果 |
| Tiro → クライアント | [`session.ended`](#session-ended) | セッションが終了したとき。セッションの最後のメッセージです |
| Tiro → クライアント | [`error`](#error) | エラー。`fatal: true` ならTiroがすぐに接続を閉じます |

**順序。** 同じ `segmentId` の `transcript` と、同じ `translationId` の `translation` は送られた順に届きます。`isFinal: false` が0回以上届いた後、`isFinal: true` が1回届きます。異なるsegmentの間、そして `transcript` と `translation` の間の順序は保証しません。

**互換性。** Tiroはメッセージの種類とフィールドを追加することがあります。フィールドの削除や、名前、型、意味の変更はしません。クライアントは、未知の `type`、フィールド、`reason`、`endReason`、`status` の値を無視するか、既定の処理をしてください。

### `session.end`

クライアントがセッションを終了するときに送ります。複数回送っても2回目以降は無視します。その後の手順は[終了](#ending)をご覧ください。

```json theme={"system"}
{ "type": "session.end" }
```

### `session.started`

接続ごとの最初のメッセージです。通常は1秒前後で届き、まれに数十秒かかります。

```json theme={"system"}
{ "type": "session.started", "id": "Rt7Yq2PbX9cDk", "resumed": false, "audioOffsetMs": 0 }
```

| フィールド | 型 | 説明 |
| - | - | - |
| `id` | string | セッションID。RESTレスポンスの `id` と同じです |
| `resumed` | boolean | セッションの最初の接続なら `false`、再接続なら `true` |
| `audioOffsetMs` | integer | Tiroが処理を終えた音声の長さです。この接続で送る最初の音声が、セッションのタイムライン上で置かれる位置でもあります。最初の接続では `0` です。使い方は[切断中の音声](#resume-audio)をご覧ください |

### `transcript`

文字起こしの結果です。

```json theme={"system"}
{
  "type": "transcript",
  "segmentId": "Ab3kZ9qLm2XyW-1-17",
  "isFinal": true,
  "text": "오늘 회의는 일정 점검부터 하겠습니다.",
  "locale": "ko_KR"
}
```

| フィールド | 型 | 説明 |
| - | - | - |
| `segmentId` | string | 結果の単位（segment）のID。形式に意味のない文字列です。パースしたり並べ替えの基準にしたりしないでください |
| `isFinal` | boolean | `false` ならまだ変わる可能性のある結果、`true` なら確定した結果 |
| `text` | string | このsegmentの現在の全文。前のメッセージに追加する差分ではありません。空文字列の場合があります |
| `locale` | string \| null | セッションで `transcriptionLocale` を指定した場合は常にその値です。自動検出のセッションでは、このsegmentで検出した言語です。検出できなかった場合や対応リスト外の場合は `null` です |

* 同じ `segmentId` の `isFinal: false` メッセージが届いたら、そのsegmentのテキストを丸ごと置き換えてください。
* `isFinal: true` はsegmentごとにちょうど1回届きます。その後、そのsegmentのメッセージは届きません。
* `isFinal: false` なしで `isFinal: true` だけが届くこともあります。
* segmentの大きさはTiroが決め、保証しません。現在は発話の終わりで区切られます。

### `translation`

翻訳の結果です。セッションで `translationLocale` を指定した場合にだけ届きます。

```json theme={"system"}
{
  "type": "translation",
  "translationId": "t3-9",
  "isFinal": true,
  "locale": "en_US",
  "text": "Today's meeting will start with a schedule review.",
  "sourceSegmentId": null
}
```

| フィールド | 型 | 説明 |
| - | - | - |
| `translationId` | string | 翻訳の断片のID。形式に意味のない文字列です |
| `isFinal` | boolean | `false` ならまだ変わる可能性のある断片、`true` なら確定した断片 |
| `locale` | string | セッションの `translationLocale`。`null` にはなりません |
| `text` | string | この断片の現在の全文。空文字列は届きません |
| `sourceSegmentId` | string \| null | 原文の位置のヒントを入れるための項目です。現在は常に `null` です |

* 置き換えのルールは `transcript` と同じです。同じ `translationId` の `isFinal: false` は以前のテキストを丸ごと置き換え、`isFinal: true` は1回だけ届きます。
* 翻訳の断片は原文のsegmentと1対1で対応しません。1つの断片が複数のsegmentにまたがったり、1つのsegmentが複数の断片に分かれたりします。
* 確定した断片の `text` を届いた順に区切り文字なしでつなげると、翻訳文になります。断片は単語の途中で分かれることがあるため、断片の間に空白を入れないでください。空白だけの確定断片は単語の区切りなので、そのままつなげてください。
* 翻訳は原文の確定より遅れて届くことも、原文の `isFinal: false` より先に届くこともあります。
* 自動検出のセッションでは、`transcript.locale` が `translationLocale` と同じsegmentは翻訳しません。言語を指定したセッションでも、翻訳先の言語で話した部分は翻訳されないことがあります。

### `session.ended`

セッションが終了したことを知らせるメッセージです。セッションの最後のメッセージで、Tiroはこのメッセージの後にclose `1000` で接続を閉じます。このメッセージを受け取ったら再接続しないでください。

```json theme={"system"}
{
  "type": "session.ended",
  "id": "Rt7Yq2PbX9cDk",
  "endReason": "CLIENT_REQUESTED",
  "audioDurationMs": 3605120,
  "endedAt": "2026-11-05T10:01:30Z"
}
```

| フィールド | 型 | 説明 |
| - | - | - |
| `id` | string | セッションID |
| `endReason` | string | 終了理由。下の表をご覧ください |
| `audioDurationMs` | integer | セッション全体でTiroが受け取った音声の長さ |
| `endedAt` | string | 終了時刻 |
| `incomplete` | boolean | 30秒以内に残りの結果を送りきれず、最後の結果の一部が欠けている可能性がある場合にだけ `true` で届きます。結果が完全な場合はフィールド自体がありません |

| `endReason` | 条件 |
| - | - |
| `CLIENT_REQUESTED` | `session.end` を送ったか、RESTでセッションを閉じました |
| `IDLE_TIMEOUT` | 15分間音声が届きませんでした |
| `MAX_DURATION` | 最初の接続から3時間が経ちました |
| `INTERNAL_ERROR` | Tiroがセッションを続けられないと判断しました。現在は、5分以内に接続が3回続けて `stt_unavailable`（`4503`）で閉じられるとこの理由で終わります |

接続がないときに終了したセッションは、このメッセージの送り先がありません。その場合は `GET /v1/external/realtime-transcriptions/{id}` で状態を確認してください。終了したセッションに接続すると `error`（`session_ended`）が届きます。

### `error`

エラーを知らせるメッセージです。

```json theme={"system"}
{
  "type": "error",
  "reason": "audio_frame_too_large",
  "message": "Audio frame exceeds 6400 bytes",
  "retryable": false,
  "fatal": true,
  "maxFrameBytes": 6400,
  "receivedBytes": 32000
}
```

| フィールド | 型 | 説明 |
| - | - | - |
| `reason` | string | 分岐に使う識別子。[WebSocketエラー](#ws-errors)の表をご覧ください |
| `message` | string | 人が読むための英語の説明。文言が変わることがあるため分岐に使わないでください |
| `fatal` | boolean | `true` ならTiroがこのメッセージの直後に接続を閉じます |
| `retryable` | boolean | このメッセージの後に接続が閉じたとき、再接続してよいかを示します。`fatal: false` なら常に `false` です |
| `retryAfterMs` | integer | `audio_rate_exceeded` にだけ付きます。再接続する前に待つ時間です |
| `maxFrameBytes`, `receivedBytes` | integer | `audio_frame_too_large` にだけ付きます。許容サイズと受け取ったサイズです |

## 終了

最後の結果まですべて受け取るには `session.end` を送ってください。

**1. session.end を送る**

最後の音声フレームを送った後、`{"type": "session.end"}` を送ります。その後に送った音声は無視します。

**2. 残りの結果を受け取る**

Tiroが残りの `transcript` と `translation` をすべて `isFinal: true` で送ります。まだ確定していないsegmentと翻訳の断片は、最後のテキストで確定して送ります。

**3. session.ended を受け取る**

Tiroが `session.ended` を送り、close `1000` で接続を閉じます。

`session.ended` を受け取るまで接続を維持してください。残りの結果を送る時間は翻訳を含めて最大30秒です。30秒以内に終わらない場合、Tiroはそれまでに送った結果で `session.ended` を送り、`incomplete: true` を付けます。

RESTでセッションを閉じた場合やタイムアウトに達した場合も、接続があれば同じ順序で終了します。このとき、Tiroに届いたもののまだ文字起こしを始めていない音声は、結果に含まれないことがあります。

WebSocket接続を閉じるだけでは、セッションは `OPEN` のまま残り、ワークスペースの同時セッションの枠を1つ占有します。接続が単に切れた場合、その時点で確定していない結果も受け取れません。

## タイムアウト

| 項目 | 値 | 結果 |
| - | - | - |
| 音声なし | 15分。セッション作成時刻または最後の音声フレームから数え、接続がなくても数えます | セッションが `IDLE_TIMEOUT` で終了します |
| セッションの最大長 | 3時間。最初の接続から数え、切断中の時間も含みます | セッションが `MAX_DURATION` で終了します |
| ping | Tiroが20秒ごとにWebSocket pingを送ります。60秒間pongがなければclose `1001` で接続を閉じます | セッションは `OPEN` のまま残ります |

* テキストメッセージは音声なしのタイマーをリセットしません。
* ミュート中は接続を維持したまま送信を止めてもかまいません。15分以内に再び送ればセッションは続きます。
* Tiroはタイムアウトの時点より遅れてセッションを終了させることがあります。接続のあるセッションは最大1分、接続のないセッションは最大3分ほど遅れます。

## 再接続

セッションが `OPEN` なら、接続が切れても同じ `wsUrl` と `streamToken` で再接続して続けられます。再接続するかどうかは最後に受け取ったメッセージで決め、close codeで分岐しないでください。

```mermaid theme={"system"}
flowchart TD
    A[接続が閉じた] --> B{session.ended を受け取りましたか？}
    B -- はい --> X[セッション終了。再接続しません]
    B -- いいえ --> C{"接続を閉じた error は retryable: false ですか？"}
    C -- はい --> Y[再接続しません]
    C -- いいえ --> D{close 1012 ですか？}
    D -- はい --> E[すぐに再接続]
    D -- いいえ --> F[バックオフしてから再接続]
```

1. `session.ended` を受け取った場合、セッションは終了しています。再接続しないでください。
2. 接続を閉じた `error`（`fatal: true`）が `retryable: false` なら、再接続しないでください。接続が維持されるエラー（`fatal: false`、例: `invalid_message`）はこの判断に含めないでください。
3. それ以外の場合は再接続してください。`retryable: true` の `error` を受け取った場合や、メッセージなしで切れた場合です。close `1012` はサーバーの再起動なのですぐに再接続し、それ以外はバックオフしてください。

バックオフは1秒から始めて2倍ずつ最大30秒まで増やし、±20%のジッターを加えてください。`retryAfterMs` があれば、その時間以上待ってください。セッションが `OPEN` の間は再接続の回数に上限はありません。

再接続に成功すると、`session.started` が `resumed: true` で届きます。セッションがすでに終了していれば、`error`（`session_ended`、`retryable: false`）が届きます。

### 切断中の音声はどう再送しますか？

Tiroは音声の再送を求めません。送れなかった音声はセッションに残らないため、クライアントが自分でためておいて再送する必要があります。

```mermaid theme={"system"}
sequenceDiagram
    participant C as お客様のクライアント
    participant W as Tiro WebSocket

    C->>W: PCM 音声
    W--xC: 接続切断 (メッセージなし、または retryable エラー)
    Note over C: 直近の音声を最大60秒までためておく
    C->>W: 同じ wsUrl に接続 (同じ streamToken)
    W-->>C: session.started {resumed: true, audioOffsetMs}
    C->>W: バッファーの audioOffsetMs 以降の音声
    C->>W: 続けてリアルタイムの音声
    W-->>C: transcript, translation
```

* 切断中は直近の音声を最大60秒までためておいてください。それより古い部分は捨ててください。
* 再接続したら `session.started` の `audioOffsetMs` を確認してください。この値はTiroが処理を終えた音声の長さなので、直前の接続で実際に送った長さより短いことがあります。Tiroが直前の接続の切断に気づく前に新しい接続が既存の接続を置き換えると、`0` になることもあります。
* セッションのタイムラインで `audioOffsetMs` 以降にあたる音声をバッファーから先に送り、続けてリアルタイムの音声を送ってください。こうしても音声の先行量60秒の範囲内に収まります。
* Tiroは再送された音声がすでに受け取った音声かどうかを判定しません。
* close `1012` はメッセージなしで閉じるため、閉じる直前に送ったフレームの一部がTiroに届いていない可能性があります。この場合も `audioOffsetMs` 以降の音声を再送してください。
* 切断の直前まで `isFinal: false` だったsegmentと翻訳の断片は捨ててください。Tiroは新しい接続でそれらを再送しません。

### 同じセッションに2回接続するとどうなりますか？

1つのセッションに接続は1つだけです。同じトークンで新しい接続が来ると、Tiroは新しい接続を使い、既存の接続を閉じます。

* 既存の接続は `error`（`connection_replaced`、`retryable: false`）を受け取り、close `4409` で閉じます。既存の接続のクライアントは再接続しないでください。
* 新しい接続は `session.started` を `resumed: true` で受け取り、セッションを続けます。

モバイルネットワークの切り替えで既存の接続が切れたのにTiroがまだ気づいていない場合でも、新しい接続をすぐに使えるようにこう動作します。

## WebSocketエラー

`reason` は増えることがあります。未知の `reason` を受け取っても、`fatal` と `retryable` の値に従ってください。

| `reason` | `fatal` | `retryable` | close | 状況と対応 |
| - | - | - | - | - |
| `unauthorized` | true | false | `4001` | トークンが正しくない、別のセッションのパスである、またはトークンを発行したAPIキーが削除か無効化されました。新しいセッションを作成してください |
| `realtime_api_not_enabled` | true | false | `4003` | ワークスペースでリアルタイム文字起こしAPIが無効です |
| `session_ended` | true | false | `4004` | すでに終了したセッションです。新しいセッションを作成してください |
| `connection_replaced` | true | false | `4409` | 同じセッションに新しい接続が来ました。この接続だけが終了し、セッションは新しい接続で続きます |
| `audio_frame_too_large` | true | false | `1009` | フレームが6,400バイトを超えました。フレームをもっと小さく分けてください |
| `invalid_audio_frame` | true | false | `1007` | フレームの長さが奇数バイトです。16-bitサンプルの境界で区切ってください |
| `audio_rate_exceeded` | true | true | `4029` | 音声の先行量が60秒を超えました。`retryAfterMs` 以上待ってから再接続し、実時間の速度で送ってください |
| `stt_unavailable` | true | true | `4503` | Tiroが文字起こしエンジンに1秒、2秒、4秒の間隔で3回再接続しても失敗しました。バックオフしながら再接続してください。5分以内に接続が3回続けてこのエラーで閉じられると、セッションは `INTERNAL_ERROR` で終わり、次の接続は `error`（`session_ended`）を受け取ります |
| `internal_error` | true | true | `4500` | 接続単位のサーバーエラーです。セッションは `OPEN` のまま残ります。バックオフしながら再接続してください |
| `invalid_message` | false | false | なし | テキストフレームが正しいJSONではありません。接続は維持されます |
| `unknown_message_type` | false | false | なし | 未知の `type` を送りました。接続は維持されます |

## close code

次の表はログを見るときの参考にしてください。再接続するかどうかは[再接続](#reconnect)のルールで決め、close codeで分岐しないでください。close codeは増えることがあります。

| code | 意味 | 直前のメッセージ |
| - | - | - |
| `1000` | セッション終了 | `session.ended` |
| `1001` | サーバー停止（デプロイ、再起動）、または60秒間pongなし。バックオフしながら再接続してください | なし |
| `1006` | 異常切断。closeフレームがありません | なし |
| `1007` | 音声フレームの形式エラー | `error`（`invalid_audio_frame`） |
| `1009` | 音声フレームが6,400バイトを超過 | `error`（`audio_frame_too_large`） |
| `1011` | Tiroがこの接続でメッセージを送れなかった。クライアントがメッセージを時間内に読み取れないときに起きることがあります。バックオフしながら再接続してください | なし |
| `1012` | サーバー再起動。すぐに再接続してください | なし |
| `4001` | 認証失敗 | `error`（`unauthorized`） |
| `4003` | リアルタイム文字起こしAPIが無効 | `error`（`realtime_api_not_enabled`） |
| `4004` | すでに終了したセッション | `error`（`session_ended`） |
| `4029` | 音声の先行量が60秒を超過 | `error`（`audio_rate_exceeded`） |
| `4409` | 別の接続に置き換えられた | `error`（`connection_replaced`） |
| `4500` | サーバー内部エラー（接続単位） | `error`（`internal_error`） |
| `4503` | 文字起こしエンジンが使用不可 | `error`（`stt_unavailable`） |

## RESTエラー

セッションのREST APIは、[エラー処理](https://docs.tiro.ooo/ja/developers/fundamentals/error-handling.md)の共通形式でエラーを返します。分岐には `detail.reason` を使ってください。`detail.reason` がないレスポンスはHTTPステータスで分岐してください。エンドポイントごとのエラーは[APIリファレンス](https://docs.tiro.ooo/api-reference/realtime-transcription/create-realtime-transcription.md)にあります。

| HTTP | `detail.reason` | 状況と対応 |
| - | - | - |
| 400 | `invalid_request` | セッション作成リクエストの値がルールに合いません。`translationLocale` が `AUTO` の場合や文字起こし言語と同じ場合にも返ります。`detail.fields` を確認してください |
| 400 | `unsupported_language` | 対応していないロケールです。`en-GB` のように対応リストにない地域も拒否します。`detail.field` と `detail.value` を確認してください |
| 400 | なし | 一覧取得の `status` が `OPEN`、`ENDED` のいずれでもありません |
| 401 | なし | APIキーがないか、正しくありません |
| 403 | `insufficient_scope` | キーに必要なスコープがありません。OAuthアクセストークンにもこのレスポンスが返ります |
| 403 | `workspace_bound_key_required` | ワークスペースに紐づかないアカウントのAPIキー、または組織のAPIキーです。ワークスペースに紐づいたキーを使ってください |
| 403 | `workspace_access_denied` | `workspaceGuid` がキーのワークスペースと異なるか、アカウントのAPIキーの所有者がワークスペースのメンバーではありません |
| 403 | `realtime_api_not_enabled` | セッション作成時にだけ返ります。ワークスペースでリアルタイム文字起こしAPIが無効なので、Tiroにお問い合わせください |
| 404 | なし | キーのワークスペースが削除されました |
| 404 | `realtime_transcription_not_found` | セッションが存在しないか、キーのワークスペースに属していません |
| 409 | `concurrent_transcription_limit` | ワークスペースの `OPEN` セッションが10件あります。使っていないセッションを一覧APIで探して閉じてから、もう一度お試しください |
| 429 | なし | APIキーあたり60秒間600回の呼び出し上限を超えました。`Retry-After` の時間だけ待ってください |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.