API 利用にあたっての重要事項

これらを理解した上でご利用ください。

1. 概要と認証方式

Advanced TTS API は 感情表現や読み上げスタイル指定に対応した、より自然な音声合成エンドポイントです。非同期ジョブ方式で、POST してジョブ ID を受け取り → ポーリングで結果を取得します。

現在の提供形態: Advanced TTS は Web UI 向けのベータ機能として提供されています。公開ドキュメントで案内するエンドポイントは /api/advanced-tts/ のみです。認証は 標準 TTS API と同じ token ヘッダー、またはログイン済みのセッション cookie + CSRF トークンに対応しています。

下記サンプルは、token ヘッダーでジョブを投入する流れです。Web UI と同じセッション認証で利用する場合は、ログイン済み cookie と X-CSRFToken を送信してください。

2. エンドポイント・リクエスト仕様

POST https://ondoku3.com/api/advanced-tts/
GET https://ondoku3.com/api/advanced-tts/jobs/{job_id}/

ヘッダー

ヘッダー
Content-Typeapplication/json
tokenアクセストークン(64 文字)。token 認証時は CSRF 不要
X-Job-Tokenジョブ参照トークン。GET ポーリング時は POST レスポンスの job_token をこのヘッダーで送信
Cookiesessionid=...; csrftoken=...(セッション認証時)
X-CSRFTokencookie の csrftoken と同じ値(セッション認証時)
Refererhttps://ondoku3.com/ja/advanced-tts-beta/(セッション認証時)

ボディ(JSON)

フィールド必須説明
textstring必須読み上げるテキスト(無料 400 文字 / 有料 1000-3000 文字)
voicestring任意音声名(下記リストから指定)。デフォルト: Ruby
tonestring任意読み上げスタイル(例: warm and friendly, storytelling)。最大 100 文字
speednumber任意0.5 〜 1.5(デフォルト 1.0)
pitchnumber任意-1.0 〜 1.0(デフォルト 0.0)
modelstring任意flash(高速) / pro(高品質)
seedinteger任意声色を固定する乱数シード(-2147483648 〜 2147483647)

?token={job_token} クエリパラメータでのポーリングはサポートされません。ジョブステータス確認は必ず X-Job-Token ヘッダーで送信してください。

3. サンプルコード(ジョブ送信 → ポーリング)

# 1) TTS ジョブを投入
JOB=$(curl -s \
  -X POST https://ondoku3.com/api/advanced-tts/ \
  -H "Content-Type: application/json" \
  -H "token: $ONDOKU_TOKEN" \
  -d '{"text":"こんにちは、音読さんです。","voice":"Ruby","tone":"warm and friendly"}')
JOB_ID=$(echo "$JOB" | jq -r .job_id)
JOB_TOKEN=$(echo "$JOB" | jq -r .job_token)
sleep "$(echo "$JOB" | jq -r '.min_poll_after_ms / 1000')"

# 2) ジョブ完了までポーリング
while :; do
  R=$(curl -s \
    -H "X-Job-Token: ${JOB_TOKEN}" \
    "https://ondoku3.com/api/advanced-tts/jobs/${JOB_ID}/")
  STATUS=$(echo "$R" | jq -r .status)
  echo "status: $STATUS"
  [ "$STATUS" = "succeeded" ] && break
  [ "$STATUS" = "failed" ] && { echo "$R"; exit 1; }
  sleep "$(echo "$R" | jq -r '(.poll_after_ms // 3000) / 1000')"
done

# 3) MP3 をダウンロード
URL=$(echo "$R" | jq -r .url)
curl -L "$URL" -o output.mp3
import os
import time
import requests

TOKEN = os.environ["ONDOKU_TOKEN"]

# 1) ジョブを投入
res = requests.post(
    "https://ondoku3.com/api/advanced-tts/",
    headers={
        "Content-Type": "application/json",
        "token": TOKEN,
    },
    json={
        "text": "こんにちは、音読さんです。",
        "voice": "Ruby",
        "tone": "warm and friendly",
    },
)
res.raise_for_status()
job = res.json()
job_id, job_token = job["job_id"], job["job_token"]
time.sleep(job["min_poll_after_ms"] / 1000)

# 2) ポーリング
while True:
    r = requests.get(
        f"https://ondoku3.com/api/advanced-tts/jobs/{job_id}/",
        headers={"X-Job-Token": job_token},
    ).json()
    print("status:", r["status"])
    if r["status"] == "succeeded":
        break
    if r["status"] == "failed":
        raise RuntimeError(r)
    time.sleep(r.get("poll_after_ms", 3000) / 1000)

# 3) MP3 をダウンロード
mp3 = requests.get(r["url"], timeout=60).content
with open("output.mp3", "wb") as f:
    f.write(mp3)
print(f"saved: output.mp3 ({len(mp3)} bytes)")
import { writeFile } from "node:fs/promises";

const TOKEN = process.env.ONDOKU_TOKEN!;

// 1) ジョブを投入
const submit = await fetch("https://ondoku3.com/api/advanced-tts/", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    token: TOKEN,
  },
  body: JSON.stringify({
    text: "こんにちは、音読さんです。",
    voice: "Ruby",
    tone: "warm and friendly",
  }),
});
type AdvancedTTSJobResponse = {
  job_id: string;
  job_token: string;
  status: "pending" | "running" | "succeeded" | "failed";
  min_poll_after_ms: number;
  poll_url: string;
};

type AdvancedTTSPollResponse = {
  job_id: string;
  status: "pending" | "running" | "succeeded" | "failed";
  poll_after_ms?: number;
  url?: string;
  pk?: number;
  seed?: number;
  code?: string;
  error?: string;
};

const job = (await submit.json()) as AdvancedTTSJobResponse;

// 2) ポーリング
let result: AdvancedTTSPollResponse;
await new Promise((resolve) => setTimeout(resolve, job.min_poll_after_ms));
while (true) {
  const r = await fetch(`https://ondoku3.com/api/advanced-tts/jobs/${job.job_id}/`, {
    headers: { "X-Job-Token": job.job_token },
  }).then((res) => res.json() as Promise);
  console.log("status:", r.status);
  if (r.status === "succeeded") { result = r; break; }
  if (r.status === "failed") throw new Error(JSON.stringify(r));
  await new Promise((resolve) => setTimeout(resolve, r.poll_after_ms ?? 3000));
}

// 3) MP3 をダウンロード
if (!result.url) throw new Error("audio URL is missing");
const mp3 = Buffer.from(await (await fetch(result.url)).arrayBuffer());
await writeFile("output.mp3", mp3);
console.log(`saved: output.mp3 (${mp3.byteLength} bytes)`);

4. レスポンス例

POST レスポンス(202 Accepted):

{
  "job_id": "YOUR_JOB_ID",
  "job_token": "YOUR_JOB_TOKEN",
  "status": "pending",
  "min_poll_after_ms": 4550,
  "poll_url": "/api/advanced-tts/jobs/YOUR_JOB_ID/"
}
フィールド説明
job_idstringジョブ ID(UUID)
job_tokenstringこのジョブのポーリングに必要な参照トークン
statusstring投入直後の状態。通常は pending
min_poll_after_msnumber初回ポーリングまで待つ推奨ミリ秒
poll_urlstringポーリング先の相対 URL。アクセス時は POST レスポンスの job_tokenX-Job-Token ヘッダーで送信する

GET ポーリング(処理中):

{
  "job_id": "YOUR_JOB_ID",
  "status": "pending",
  "poll_after_ms": 1000
}

GET ポーリング(成功時):

{
  "job_id": "YOUR_JOB_ID",
  "status": "succeeded",
  "url": "https://storage.googleapis.com/ondoku3/voice/...",
  "pk": 12345,
  "seed": 123456789
}

GET ポーリング(失敗時):

{
  "job_id": "YOUR_JOB_ID",
  "status": "failed",
  "code": "internal_error",
  "error": "内部サーバーエラーが発生しました"
}
フィールド説明
job_idstringジョブ ID(UUID)
statusstringpending / running / succeeded / failed
poll_after_msnumber処理中に返る、次回ポーリングまで待つ推奨ミリ秒
urlstring成功時のみ返る音声ファイル URL
pknumber成功時のみ返る生成履歴(Sentence)の ID
seednumberseed が保存されている場合のみ返る、生成に使われた乱数シード
codestring失敗時のみ返るエラーコード
errorstring失敗時のみ返るエラーメッセージ

5. 音声リスト(25 種類)

Advanced TTS API の voice パラメータに指定できる音声名 25 種類。各音声のサンプルは 音声サンプル記事で試聴できます。

女性(12 音声)

音声名読み仮名
Annaアンナ
Chloeクロエ
Ellisエリス
Emmaエマ
Floraフローラ
Irisアイリス
Lenaレナ
Lunaルナ
Misaミサ
Rubyルビー
Sophieソフィー
Tinaティナ

男性(13 音声)

音声名読み仮名
Ashアッシュ
Chrisクリス
Edenエデン
Grayグレイ
Hopeホープ
Hugoヒューゴ
Kaiカイ
Leoレオ
Noahノア
Reidリード
Royロイ
Samサム
Yannヤン

6. エラー・案内レスポンス

Advanced TTS では、リクエスト直後の HTTP エラーだけでなく、ジョブ投入後のポーリング結果として status=failed の JSON が返る場合があります。Web UI では code に応じて案内音声を再生しますが、API レスポンス自体に案内音声 URL は含まれません。

HTTPcode原因
400validation_errortext 形式不正 / 短すぎる
400invalid_voice不明な voice 名
400text_too_longプラン上限超過
400invalid_speed / invalid_pitch範囲外
400invalid_tokentoken ヘッダーが不正、または一致するユーザー設定がない
403(HTML)CSRF 不一致 / 未ログイン
429quota_exceeded利用可能な文字数不足。Web UI では案内音声とプラン案内を表示
429rate_limitedレート制限超過。retry_after 秒後に再試行。Web UI では案内音声を再生
200status=failedポーリング時のジョブ失敗。HTTP ステータスではなく JSON の status / code を確認

7. 文字数上限・レート制限

1 リクエストの文字数上限

プラン上限
無料400 文字
有料(標準)1,000 文字
有料(Beta 文字数拡張オプトイン)3,000 文字

レート制限

Advanced TTS 専用のレート制限は、現在 shadow mode で観測中です。この専用制限ではまだリクエストを遮断せず、超過しても 429 は返しません。正式適用後は、下記の値を超えた場合に rate_limited の JSON と Retry-After ヘッダーを返す予定です。

対象単位予定制限補足
ジョブ作成 POST /api/advanced-tts/ユーザー ID(未ログイン時は IP)30 回 / 60 秒
180 回 / 1 時間
有料・無料などのユーザーステータスでは分けません
ステータス確認 GET /api/advanced-tts/jobs/{job_id}/ログインユーザーまたはジョブ参照トークン + job_id120 回 / 60 秒同じジョブへの過剰ポーリングを抑制します
ステータス確認の合計ログインユーザーまたはジョブ参照トークン600 回 / 60 秒複数ジョブの同時ポーリングを抑制します。API トークン認証またはログイン済みセッションで作成したジョブを X-Job-Token ヘッダーで確認する場合、所有者ユーザーではなくジョブ参照トークン単位で扱います
存在しないジョブ / 権限なしジョブの確認IP30 回 / 60 秒不正な job_id の総当たりを抑制します

既存の文字数不足は quota_exceeded の JSON で返ります。現行の汎用レート制限に当たった場合は rate_limited の JSON で返ります。Web UI では案内音声を再生しますが、API クライアントは HTTP ステータスだけでなく JSON の code を見て処理してください。

429 のレスポンス例:

{
  "code": "rate_limited",
  "error": "レート制限を超えました。しばらく経ってから再試行してください。",
  "retry_after": 55
}

プラン詳細・価格は 料金ページ、利用条件は 利用規約 を参照してください。

8. 使用上の注意事項

認証情報の管理

入力テキスト・生成音声の取り扱い

リトライ指針

HTTP / 状況対応
429 (Rate limit)retry_after 秒、または最低 5 秒待ってから再試行
5xxexponential backoff(2 秒 → 4 秒 → 8 秒、最大 3 回)
4xx(400・403 等)リトライしない。CSRF トークンや voice 名を確認
ジョブ status=failedcode を確認。生成失敗は同じ seed でリトライしても同じ結果になることがあるため、seed を変えて再試行
ジョブが pending のまま長時間5 分以上 pending の場合はサーバー側で滞留している可能性。新規ジョブとして再投入

ポーリング推奨間隔

同時実行・並列度

タイムアウト推奨値

音声ファイル URL の有効期限

CORS(ブラウザから直接叩く場合)

コンテンツポリシー

以下の用途での利用を禁止します:

詳細は 利用規約 を確認してください。

生成音声の著作権・商用利用

9. 問い合わせ前に

不具合や予期しない挙動を確認したら、まず以下を試してください:

  1. エラー・案内内容を確認: エラー・案内レスポンス 表で対応を確認
  2. Web UI で再現するか確認: Advanced TTS ページ で同じテキスト・voice・tone を試す
  3. CSRF / Cookie を確認: 403 が返る場合は再ログインしてセッションを取り直す
  4. 残文字数を確認: 設定ページ で月間文字数の消費量を確認
  5. 最小ペイロードで疎通テスト: {"text":"テスト","voice":"Ruby"} で 202 が返るか
  6. seed を変えて再試行: 生成失敗は seed 依存の可能性があるため、seed を変えるか省略

上記で解消しない場合は お問い合わせ からご連絡ください。再現に必要な以下の情報を添えていただけるとスムーズです:

変更履歴について: Advanced TTS はベータ機能です。API 仕様は予告なく変更される可能性があります。大きな変更は 音読さんトップ 等でアナウンスする場合がありますが、軽微な変更はサイレントに行われることがあります。