VOICE API · 中文开发文档
开始使用 Voice API
从创建密钥开始,添加声音、生成音频,再查看用量和费用。 这份指南带你完成一次完整调用。
1. 创建密钥
登录控制台并开通工作区,在“API 密钥”中点击“创建 API 密钥”。只需填写名称,默认永不过期;可选 7、30 或 90 天。完整密钥仅展示一次。
export CASTREADER_API_KEY="YOUR_API_KEY"
# 先查询当前网络的处理区域;需要安装 jq,不发送文本或录音。
export CASTREADER_API_BASE=$(curl --fail --silent --show-error \
'https://voice.castreader.com/v1/route' \
-H "Authorization: Bearer $CASTREADER_API_KEY" | jq -er '.base_url')
# 仅在服务端保存密钥,不要提交到 Git 或放入浏览器前端。身份验证与区域
在每次请求中发送 Authorization: Bearer YOUR_API_KEY。语音生成需要 speech:generate,声音读取需要 voices:read,账单用量查询需要 usage:read。把密钥放在服务端环境变量,不要放进公开仓库或移动端安装包。
同一个账户、Key 和余额可用于两个区域。先由调度接口选择处理区域,再将正文与录音直接发送到返回的地址。界面语言不会改变区域,已有任务的重试应留在原区域。详情见区域调度指南。
2. 添加声音
在我的声音选择“自己录制”“邀请朋友”或“上传音频”。准备单人、无背景音乐的清晰录音,建议 20–30 秒,最大 4 MB。上传他人声音时提供明确授权;邀请朋友时,由对方在录音页面确认授权。
等待状态变为“可用”,试听后复制声音 ID。删除声音会阻止新的生成和旧结果下载。声音准备过程中出现失败时,请查看提示再添加新录音。
curl "$CASTREADER_API_BASE/voices" \
-H "Authorization: Bearer $CASTREADER_API_KEY" \
-H 'Idempotency-Key: my-first-voice-001' \
-F 'name=我的声音' -F 'language=zh' \
-F 'reference_audio=@reference.wav;type=audio/wav' \
-F 'consent_type=self' -F 'subject_name=Your name' \
-F 'consent_confirmed=true' -F 'terms_version=voice-consent-v1' \
--fail-with-body3. 生成第一段音频
将下方的 voice_YOUR_ID 替换为自己的声音 ID。中国区示例直接生成中文音频,无需时间戳。当前可用的合成语言以 GET /v1/models 为准。
curl "$CASTREADER_API_BASE/audio/speech" \
-H "Authorization: Bearer $CASTREADER_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: my-first-speech-001' \
--data '{
"model": "clone-v1",
"voice_id": "voice_YOUR_ID",
"text": "欢迎使用 CastReader,让文字拥有熟悉的声音。",
"language": "zh",
"output_format": "mp3"
}' \
--fail-with-body --dump-header speech.headers --output speech.mp3成功响应为二进制音频。先检查 HTTP 200,再播放文件;失败响应是 JSON。响应头中可取得请求 ID 和可选时间戳地址。
资源繁忙时:使用排队任务
提交后保存任务 ID,按 Retry-After 建议间隔查询。关闭浏览器不会丢失任务。等待不收费;已开始执行的任务需确认停止后才能释放预留金额。
curl "$CASTREADER_API_BASE/jobs" \
-H "Authorization: Bearer $CASTREADER_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: my-first-job-001' \
--fail-with-body --data '{
"model": "clone-v1",
"voice_id": "voice_YOUR_ID",
"text": "欢迎使用 CastReader,让文字拥有熟悉的声音。",
"language": "zh",
"output_format": "mp3"
}'
# 保存返回的 id;后续请求始终使用相同区域的地址。
export JOB_ID="job_RETURNED_ID"
curl "$CASTREADER_API_BASE/jobs/$JOB_ID" \
-H "Authorization: Bearer $CASTREADER_API_KEY" --fail-with-body
# 状态为 succeeded 后,从 chunks 中取得 requestId。
export REQUEST_ID="req_RETURNED_ID"
curl "$CASTREADER_API_BASE/requests/$REQUEST_ID/audio" \
-H "Authorization: Bearer $CASTREADER_API_KEY" \
--fail-with-body --output speech.mp3状态包括 queued、blocked、running、succeeded、failed、cancelled 和 expired。非成功的终态不能当作音频结果。取消使用 DELETE /v1/jobs/{job_id}。
4. 核对计量与扣费
在控制台的「API 账单」中使用支付宝充值。最低支付 ¥7,获得 $1 API 额度;付款后自动确认到账。余额不设有效期,优先使用免费字符,随后按实际成功生成的字符扣费。
在用量按请求 ID 对照字符数、免费字符抵扣、实际扣费和最终状态。金额以账本为准,界面四舍五入不改变实际扣费。
curl "$CASTREADER_API_BASE/requests/$REQUEST_ID" \
-H "Authorization: Bearer $CASTREADER_API_KEY" --fail-with-body
curl "$CASTREADER_API_BASE/usage" \
-H "Authorization: Bearer $CASTREADER_API_KEY" --fail-with-body价格为每百万规范化 Unicode 字符 12 美元。相同内容和相同幂等键只结算一次,下载保留结果不产生新费用。查看完整规则 →
错误与安全重试
| 状态码 | 处理建议 |
|---|---|
| 401 | 检查密钥是否有效、过期或已撤销。 |
| 403 | 核对角色、权限、声音授权及区域归属。 |
| 402 | 检查工作区额度和余额。 |
| 409 | 查询原请求;不要在执行结果未知时创建新任务。 |
| 410 | 结果或任务已过期,原请求不会自动重新生成。 |
| 422 | 检查参数、语言、字符数或录音格式。 |
| 429 / 503 | 按 Retry-After 等待,在同一区域重试同一请求或使用排队任务。 |
网络断开不代表生成失败。优先查询保存的任务 ID 或请求 ID。同一次提交使用同一个 Idempotency-Key;修改文字、声音、格式或时间戳选项时,才为新的任务生成新键。
HTTP 接口参考
| 接口 | 用途 |
|---|---|
GET /v1/models | 模型和语言限制 |
GET /v1/voices | 列出声音 |
POST /v1/voices | 注册授权声音 |
DELETE /v1/voices/{voice_id} | 删除声音 |
POST /v1/audio/speech | 生成完整音频 |
POST /v1/jobs | 创建排队任务 |
GET /v1/jobs/{job_id} | 查询任务 |
DELETE /v1/jobs/{job_id} | 取消任务 |
GET /v1/requests/{request_id} | 读取请求与用量 |
GET /v1/requests/{request_id}/audio | 下载音频 |
GET /v1/requests/{request_id}/timestamps | 读取 v3 时间戳 |
GET /v1/usage | 查询工作区用量 |
Node.js 与 Python
使用任意支持 HTTPS 的服务端客户端。先执行上方的区域查询,将返回地址保存在 CASTREADER_API_BASE;后续调用使用同一地址。对请求设置超时,保存任务 ID、幂等键及错误码,再查询结果。
// Node.js:先提交,保存 id,再轮询。
const response = await fetch(process.env.CASTREADER_API_BASE + '/jobs', {
method: 'POST',
redirect: 'error',
headers: {
Authorization: 'Bearer ' + process.env.CASTREADER_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': 'node-first-job-001',
},
body: JSON.stringify({
"model": "clone-v1",
"voice_id": "voice_YOUR_ID",
"text": "欢迎使用 CastReader,让文字拥有熟悉的声音。",
"language": "zh",
"output_format": "mp3"
}),
signal: AbortSignal.timeout(30000),
});
if (!response.ok) throw new Error(await response.text());
const job = await response.json();
console.log(job.id);import json, os
from urllib.request import Request, urlopen
payload = {"model":"clone-v1","voice_id":"voice_YOUR_ID","text":"欢迎使用 CastReader。","language":"zh","output_format":"mp3"}
request = Request(os.environ['CASTREADER_API_BASE'] + '/jobs',
data=json.dumps(payload).encode(), headers={
'Authorization': 'Bearer ' + os.environ['CASTREADER_API_KEY'],
'Content-Type': 'application/json',
'Idempotency-Key': 'python-first-job-001',
})
with urlopen(request, timeout=30) as response:
job = json.load(response)
print(job['id'])当前未开放的能力
公开预览版不提供实时会话、流式输出、长篇生成、自动充值或延迟 SLA。控制台成员管理、密钥创建与付款需要登录会话,不通过公开 Bearer 接口管理。请以当前能力页及实际返回为准。