API ドキュメント
読み上げクラウド API は REST ベースで、Authorization ヘッダーによる API キー認証を採用しています。
クイックスタート
3 ステップで音声を生成できます:
- ダッシュボードで API キーを発行
POST /api/v1/synthesizeを叩く- レスポンスの音声バイナリを保存・再生
curl -X POST https://yomiage.cloud/api/v1/synthesize \
-H "Authorization: Bearer yom_live_xxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"text": "こんにちは、読み上げクラウド です。",
"voice": "ja-JP-Chirp3-HD-Aoede"
}' \
--output hello.mp3認証
すべての API リクエストには Authorization ヘッダーで API キーを送信します:
Authorization: Bearer yom_live_xxxxxxxxxxxxxxxxxxxxxxAPI キーは ダッシュボードのキー管理画面 から発行できます。
API キーは作成時の1回だけ表示されます。安全な場所に保管してください。漏洩した場合は即時失効させて新規発行してください。
POST /api/v1/synthesize
テキストから音声を生成します。
リクエストボディ (JSON)
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| text | string | Yes | 読み上げるテキスト。最大 5,000 字 |
| voice | string | Yes | 音声 ID(例: ja-JP-Chirp3-HD-Aoede) |
| engine | string | No | "google" (デフォルト) または "voicevox" |
| speed | number | No | 速度 0.5〜2.0(デフォルト 1.0) |
| pitch | number | No | ピッチ -10〜+10(デフォルト 0) |
レスポンス
成功時: 音声バイナリ(audio/mpeg または audio/wav)
エラー時: JSON
{
"error": "monthly_limit_exceeded",
"message": "Monthly character limit (50000) exceeded.",
"limit": 50000,
"used": 100013,
"remaining": 0
}レスポンスヘッダー
| ヘッダー | 説明 |
|---|---|
| Content-Type | audio/mpeg (Google) または audio/wav (VOICEVOX) |
| X-Audio-Engine | 使用エンジン(google / voicevox) |
| X-RateLimit-Limit | 月間上限文字数 |
| X-RateLimit-Remaining | 残り文字数 |
GET /api/v1/voices
利用可能な音声の一覧を取得します。
curl https://yomiage.cloud/api/v1/voices \
-H "Authorization: Bearer yom_live_xxxxxxxxxxxxxxxxxxxxxx"{
"voices": [
{
"engine": "google",
"id": "ja-JP-Chirp3-HD-Aoede",
"name": "ja-JP-Chirp3-HD-Aoede",
"group": "Chirp3-HD",
"gender": "FEMALE"
},
...
]
}エラーコード
| HTTP | error | 説明 |
|---|---|---|
| 400 | missing_text / text_too_long / invalid_voice / invalid_json | リクエスト不正 |
| 401 | unauthorized | API キー無効/未指定 |
| 403 | plan_disabled_api | 現在のプランで API 利用不可(要アップグレード) |
| 429 | monthly_limit_exceeded | 月間文字数超過 |
| 500 | synthesis_failed | 音声合成エンジンエラー(upstream 障害等) |
レート制限
現在は月間文字数のみで制限しており、秒間 / 分間のリクエスト制限はありません。
大量のリクエスト(毎秒 100 件以上)を継続的に送る場合は、事前に business@yomiage.cloud までご連絡ください。
長文の扱い
1 リクエストあたりの上限: 5,000 字
text フィールドの最大長は 5,000 字です。 これを超えると HTTP 400 / error: "text_too_long" が返ります。
朗報: 5,000 字以内なら、どんなに長い文や句読点無しの文章でも自動分割します。 「、で区切らないとエラーになる」というのは Chirp3-HD の素の仕様で、読み上げクラウド 側で透過的に解決しています。 クライアント側で句読点ベースの事前分割は不要です。
5,000 字超の場合の対処
5,000 字を超える長文(ブログ記事全文、台本、書籍など)は、クライアント側で文単位に分割して複数回リクエストし、生成した音声を連結してください。
Python サンプル(10,000+ 字を一括音声化)
import os
import requests
API_KEY = os.environ["YOMIAGE_API_KEY"]
ENDPOINT = "https://yomiage.cloud/api/v1/synthesize"
MAX_CHARS_PER_REQUEST = 4500 # 5,000 の安全マージン
def chunk_japanese_text(text: str, max_chars: int = MAX_CHARS_PER_REQUEST) -> list[str]:
"""日本語テキストを「。」優先で安全に分割。max_chars 以下のチャンクに分ける。"""
chunks = []
current = ""
for sentence in text.replace("\n", "").split("。"):
if not sentence:
continue
candidate = current + sentence + "。"
if len(candidate) > max_chars and current:
chunks.append(current)
current = sentence + "。"
else:
current = candidate
if current.strip():
chunks.append(current)
return chunks
def synthesize_long(text: str, voice: str = "ja-JP-Chirp3-HD-Aoede",
output_path: str = "output.mp3") -> None:
"""長文テキストを音声化(自動分割 + 連結)"""
chunks = chunk_japanese_text(text)
print(f"Splitting into {len(chunks)} chunks")
with open(output_path, "wb") as f:
for i, chunk in enumerate(chunks):
res = requests.post(
ENDPOINT,
json={"text": chunk, "voice": voice},
headers={"Authorization": f"Bearer {API_KEY}"},
)
res.raise_for_status()
f.write(res.content)
print(f" [{i+1}/{len(chunks)}] {len(chunk)} chars → ok")
print(f"Done: {output_path}")
# 使用例
long_text = open("article.txt").read() # 10,000+ 字
synthesize_long(long_text)Node.js サンプル
import fs from "fs";
import path from "path";
const API_KEY = process.env.YOMIAGE_API_KEY;
const ENDPOINT = "https://yomiage.cloud/api/v1/synthesize";
const MAX_CHARS = 4500;
function chunkJapaneseText(text, maxChars = MAX_CHARS) {
const chunks = [];
let current = "";
for (const sentence of text.replace(/\n/g, "").split("。")) {
if (!sentence) continue;
const candidate = current + sentence + "。";
if (candidate.length > maxChars && current) {
chunks.push(current);
current = sentence + "。";
} else {
current = candidate;
}
}
if (current.trim()) chunks.push(current);
return chunks;
}
export async function synthesizeLong(text, {
voice = "ja-JP-Chirp3-HD-Aoede",
outputPath = "output.mp3",
} = {}) {
const chunks = chunkJapaneseText(text);
console.log(`Splitting into ${chunks.length} chunks`);
const buffers = [];
for (let i = 0; i < chunks.length; i++) {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${API_KEY}`,
},
body: JSON.stringify({ text: chunks[i], voice }),
});
if (!res.ok) throw new Error(`Chunk ${i+1} failed: ${res.status}`);
const buf = Buffer.from(await res.arrayBuffer());
buffers.push(buf);
console.log(` [${i+1}/${chunks.length}] ${chunks[i].length} chars → ok`);
}
fs.writeFileSync(outputPath, Buffer.concat(buffers));
console.log(`Done: ${outputPath}`);
}
// 使用例
const longText = fs.readFileSync("article.txt", "utf-8");
await synthesizeLong(longText);FAQ
Q: 「、」で事前分割しないと長文エラーになる?
A: 不要です。5,000 字以内なら 読み上げクラウド 側で自動分割します。 Chirp3-HD の「sentence too long」エラーは内部で透過的に処理されます。 ただし 5,000 字超は API ハード制限に当たるため、上記サンプルのような文単位分割が必要です。
Q: チャンク間の音声が不自然に途切れる?
A: 文末(句点)でチャンク分割していれば、ほぼ自然につながります。 どうしても気になる場合は ffmpeg で結合後にクロスフェード処理 (約 0.05 秒) を入れると滑らかになります。
Q: 月間文字数の上限を超えそうなとき
A: 事前に
X-RateLimit-Remaining ヘッダーで残量を確認、もしくは ダッシュボード で使用量を見られます。 残量超えると HTTP 429 / monthly_limit_exceeded が返るので、 その時点でプランアップグレード or 翌月リセット待ちです。サンプルコード
Node.js (axios)
import axios from "axios";
import fs from "fs";
const response = await axios.post(
"https://yomiage.cloud/api/v1/synthesize",
{
text: "こんにちは、読み上げクラウド です。",
voice: "ja-JP-Chirp3-HD-Aoede",
},
{
headers: {
Authorization: `Bearer ${process.env.YOMIAGE_API_KEY}`,
},
responseType: "arraybuffer",
},
);
fs.writeFileSync("hello.mp3", response.data);Python (requests)
import os
import requests
response = requests.post(
"https://yomiage.cloud/api/v1/synthesize",
json={
"text": "こんにちは、読み上げクラウド です。",
"voice": "ja-JP-Chirp3-HD-Aoede",
},
headers={"Authorization": f"Bearer {os.environ['YOMIAGE_API_KEY']}"},
)
response.raise_for_status()
with open("hello.mp3", "wb") as f:
f.write(response.content)cURL(ダウンロード付き)
curl -X POST https://yomiage.cloud/api/v1/synthesize \
-H "Authorization: Bearer $YOMIAGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"こんにちは","voice":"ja-JP-Chirp3-HD-Aoede"}' \
--output hello.mp3