合音语音 HEYIN 开放API接入文档
HEYIN 开放 API
公共音色、私有音色注册、同步与异步合成、鉴权下载和用量查询。按量预付费,适合脚本、工作流和你的自有产品。
https://www.heyintts.cn/api/open文档版本 2026-11-07 · 接口规范JSON · 下载Markdown
网页与下载版使用同一内容源
快速开始
通过服务端HTTP请求使用公共音色或注册Key私有音色。生产地址统一为 https://www.heyintts.cn/api/open。
- 打开开发者控制台,创建API Key,明文只展示一次。
- 使用
/account查询余额/额度、/clone/models查询能力、/clone/balance查询单价;余额不足再充值。 - 无需注册私有音色即可从
/library/voices选取公共音色,参考下方完整示例保存第一份音频。
请求头使用 X-API-Key,也支持 Authorization: Bearer <key>。站内登录Token与API Key用途不同。Key通过 HEYIN_API_KEY 环境变量传入服务端程序,不放在URL、浏览器公开代码或日志里。
每笔业务固定保存参数和 request_id,网络重试使用原记录。示例中的业务文件包含请求参数,请按业务保存,不包含API Key;新业务换新文件名,已终态失败的异步任务重新提交需新ID。
接口参考
相对路径基于生产地址。所有账户、私有资源、合成、历史和任务接口均需API Key;只读 /clone/catalog 与 /clone/catalog/voices 无需Key,供选型和报价。
| 方法 | 路径 | 鉴权 | 功能 |
|---|---|---|---|
| GET | /account | API Key | 返回当前 Key 的只读账户、额度和计费信息。 |
| POST | /clone/register | API Key | 注册克隆音色;按当前Key的有效音色配额原子占位。 |
| POST | /clone/synthesize | API Key | 使用当前 API Key 名下的克隆音色合成语音。 |
| GET | /clone/catalog | 公开只读 | 无需Key的只读脱敏目录;不调用鉴权、更新最后调用时间或消耗积分。 |
| GET | /clone/catalog/voices | 公开只读 | 公开目录复用正式Key目录的可用性/公开模型/价格筛选,不泄露私有音色。 |
| GET | /clone/voices | API Key | 返回当前 API Key 名下注册的全部克隆音色。 |
| DELETE | /clone/voices/{voice_id} | API Key | 删除当前 API Key 名下的克隆音色(同时删除云侧声音)。 |
| GET | /clone/models | API Key | 返回可用克隆模型列表 + 情感指令预设(供客户端展示)。 |
| GET | /clone/balance | API Key | 返回当前 API Key 的预付费余额(三块拆分)、单价与充值包目录。 |
| GET | /library/voices | API Key | 分页浏览网页端当前可见、已审核通过的声音库音色。 |
| POST | /library/synthesize | API Key | 使用已审核、当前可见的公共音色合成,并按真实付费成本结算创作者收益。 |
| POST | /clone/jobs | API Key | 提交Key私有音色任务;提交阶段不扣费。 |
| POST | /library/jobs | API Key | 公共音色审核、上下架与余额在执行时重新检查。 |
| GET | /jobs/{job_id} | API Key | 仅返回当前Key任务,成功结果使用历史鉴权URL。 |
| GET | /jobs/{job_id}/audio | API Key | 同站点跳转,下载目标再次校验Key;不在URL里传密钥。 |
| GET | /history | API Key | 列出当前 API Key 最近 7 天的合成历史。 |
| GET | /history/{history_id}/audio | API Key | 按当前 Key 鉴权下载历史音频,支持二进制或 Base64。 |
| GET | /timeline/capabilities | API Key | 按当前Key查询时间线资格;节点即时状态由受理时重新检查。 |
| GET | /history/{history_id}/timeline | API Key | 实时读取时间线状态和公开文档,不把逐字数组放入合成回执。 |
| POST | /history/{history_id}/alignment | API Key | 已有成功音频补对齐或重试,不重新合成及扣费。 |
| GET | /history/{history_id}/subtitles | API Key | 下载四种字幕,JSON仅含公开协议字段。 |
| GET | /history/{history_id}/audio-with-timeline | API Key | 在独占临时目录导出副本,保持原文件与合成账单。 |
同步默认返回JSON中的 audio_base64,按Base64解码保存;公共音色用正整数 shared_voice_id,私有音色用本Key注册的 voice_id。站内私有音色不能直接作为Key的私有音色使用。
私有音色合成参数
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
text | 是 | string;最长 100000 | 合成文本 |
request_id | 否 | string;最长 64;默认 "" | 幂等键(重试传同一值不会重复扣费) |
voice_id | 是 | string | 克隆音色 ID(clone_xxx) |
rate | 否 | number;最小 0.5;最大 2;默认 1 | 语速 0.5-2.0 |
instruction | 否 | string;最长 200;默认 "" | 情感指令 |
language_type | 否 | string;最长 20;默认 "Auto" | 语种 |
output_format | 否 | string;可选 pcm / wav / mp3 / opus;默认 "wav" | 输出格式 pcm/wav/mp3/opus |
sample_rate | 否 | integer;可选 24000 / 44100 / 48000;默认 24000 | 采样率 Hz(克隆音频最低 24kHz) |
response_format | 否 | string;可选 base64 / url;默认 "base64" | 返回音频编码或鉴权下载地址 |
timeline_mode | 否 | string;可选 off / native / auto / forced;默认 "off" | 可选时间线模式,默认关闭 |
pause_profile | 否 | string;可选 general / audiobook / broadcast / ad;默认 "general" | 停顿预设:general/audiobook/broadcast/ad(见 ADR-0217) |
公共音色合成参数
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
text | 是 | string;最长 100000 | 合成文本 |
request_id | 否 | string;最长 64;默认 "" | 可选幂等键 |
shared_voice_id | 是 | integer | 声音库音色 ID |
rate | 否 | number;最小 0.5;最大 2;默认 1 | 语速 0.5-2.0 |
instruction | 否 | string;最长 200;默认 "" | 情感指令 |
language_type | 否 | string;最长 20;默认 "Auto" | 语种 |
output_format | 否 | string;可选 pcm / wav / mp3 / opus;默认 "wav" | 输出格式 |
sample_rate | 否 | integer;可选 24000 / 44100 / 48000;默认 24000 | 采样率 Hz(克隆音频最低 24kHz) |
pause_profile | 否 | string;可选 general / audiobook / broadcast / ad;默认 "general" | |
response_format | 否 | string;可选 base64 / url;默认 "base64" | |
timeline_mode | 否 | string;可选 off / native / auto / forced;默认 "off" |
text 请求模型原始最多100000字符,同步默认最多3000个非空白有效字,异步默认最多8000个有效字,服务端硬限32000;实际时间线上限见 /timeline/capabilities,同步配置另见 /account.limits.max_synth_chars。请求时间线时完整原文还须不超过32000个Unicode码点。英文限长按字符计算,计费另按规则折算。instruction 最长200字符,language_type 最长20字符,request_id 最长64字符。
注册采用multipart/form-data:参考音频建议3~30秒有效人声,1KB~50MB,整个请求仍受50MiB上限约束,须为表单留余量;不要自行设置缺少boundary的Content-Type。默认模型standard,实际需选择目录中 registration_allowed=true 且非维护的能力。注册费以余额接口为准,默认2000积分。
普通JSON成功响应如下;费用仅为说明字段的示例,实际以调用返回为准。
{"success":true,"audio_base64":"...","format":"mp3","voice_name":"示例","cost":24,"remaining_points":976,"history_id":"hist_xxx","shared_voice_id":123,"price_per_char":6}shared_voice_id 与 price_per_char 为公共音色响应字段。私有音色没有这两个字段;两者均返回费用、剩余积分及历史ID。音频格式为pcm/wav/mp3/opus;PCM为s16le裸音频,Opus请求44100Hz时转换为48000Hz输出。
使用示例
场景包括公共音色、私有音色注册、异步任务、鉴权下载、串行批量和错误重试。Node使用ESM的 .mjs 文件;Python需安装requests。Bash示例依赖curl 7.76+、jq、Python3与Linux base64;Windows使用PowerShell 7.2+版本。
所有示例都检查错误并设置超时。Node/Python在临时网络错误、429/502/503、同ID处理中409时最多尝试3次;参数冲突、鉴权或余额错误直接退出。Bash/PowerShell失败立即终止,按错误说明等待后保留原ID与参数重试。
无需注册私有音色;目录没有音色时明确退出。 Node.js 20+;保存为example.mjs,设置HEYIN_API_KEY后运行 node example.mjs。
首次调用按返回报价扣费。业务文件保存请求ID;同一业务重试保留文件和参数,新业务使用新文件名。不要将API Key放入浏览器公开代码。
import { readFile, writeFile } from "node:fs/promises";
import { randomUUID } from "node:crypto";
const BASE = "https://www.heyintts.cn/api/open";
const KEY = process.env.HEYIN_API_KEY;
if (!KEY) throw new Error("请先设置HEYIN_API_KEY环境变量");
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const json = payload => ({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(payload)});
async function business(file, payload) {
try {
const old = JSON.parse(await readFile(file, "utf8"));
const {request_id, ...previous} = old;
if (!request_id || JSON.stringify(previous) !== JSON.stringify(payload)) throw new Error("业务文件参数不一致,请为新业务使用新文件名");
return old;
} catch (error) {
if (error.code !== "ENOENT") throw error;
const value = {...payload, request_id:randomUUID()};
await writeFile(file, JSON.stringify(value), {flag:"wx"}); return value;
}
}
async function request(path, options = {}, binary = false) {
const url = new URL(path.startsWith("/") && !path.startsWith("/api/") ? BASE + path : path, BASE);
if (url.origin !== new URL(BASE).origin) throw new Error("拒绝向其他域发送API密钥");
for (let attempt = 0; attempt < 3; attempt++) {
let r;
try { r = await fetch(url, {...options, headers:{"X-API-Key":KEY,...options.headers}, signal:AbortSignal.timeout(600000), redirect:"error"}); }
catch (error) { if (attempt === 2) throw error; await sleep(1000 * 2 ** attempt); continue; }
if (r.ok) { if(binary) return r; const data=await r.json(); if(data.success===false)throw new Error(data.error||"服务返回失败"); return data; }
const message = await r.text();
const temporary = [429,502,503].includes(r.status) || (r.status===409 && message.includes("正在处理中"));
if (!temporary || attempt === 2) throw new Error("HTTP " + r.status + ": " + message);
const retry = Number(r.headers.get("Retry-After"));
await sleep(Math.min(60,Math.max(1,Number.isFinite(retry)&&retry>0?retry:2**attempt))*1000);
}
}
async function save(data, file = "out.mp3") {
const audio = data.audio_base64 ? Buffer.from(data.audio_base64,"base64")
: Buffer.from(await (await request(data.audio_url, {}, true)).arrayBuffer());
await writeFile(file, audio);
console.log({file,cost:data.cost,remaining_points:data.remaining_points,history_id:data.history_id});
}
const { voices } = await request("/library/voices");
if (!voices?.length) throw new Error("当前没有可用的公共音色");
const payload = await business("public.json", { shared_voice_id: voices[0].shared_voice_id,
text: "你好,欢迎使用合音。", output_format: "mp3" });
await save(await request("/library/synthesize", json(payload)));账户、公共音色与历史
GET /account 返回当前Key名称、状态、余额、音色配额、单次字数及限流配置。只读查询免费,仍计入Key请求限额。
GET /library/voices 返回已审核、可见、未下架、未删除、未过期且支持开放API的公共音色。支持 page/page_size(默认1/20,最多50)、keyword(最长200)、category、lang、gender、age_group、scene/scene_key、model、grade。scene_key优先,model使用公开能力代号。
返回 voices、total、page、page_size;音色包含 shared_voice_id、name、avatar_url、description、model、price_per_char、category、language、gender、age_group、scenes、quality_grade、is_new_voice、creator_name、total_usage、preview_url。公共音色不会复制到私有列表;合成时重新校验可用性及价格。本人使用自己的公共音色仍计费,但不产生创作者收益。
GET /clone/voices 返回当前Key的私有音色,包含voice_id、voice_name、model_key、status、created_at、language、expires_at、expired、visibility,兼容保留lang、expire_at、last_synth_at、is_expired。
GET /history?page=1&page_size=20&status=succeeded 返回当前Key最近7天进入执行阶段的记录;status可为空、processing、succeeded、failed。前置鉴权、参数或审核拒绝不保证产生历史。每条包含history_id、request_id、type、展示信息、char_count、cost、status、output_format、sample_rate、created_at、has_audio及失败信息。
异步合成与鉴权下载
将对应同步参数提交到 POST /clone/jobs 或 POST /library/jobs,返回HTTP202,保存job_id。提交只排队不扣费,执行时检查音色、文本、余额和当前Key状态。结果固定为URL模式。
{"success":true,"job_id":"job_xxx","status":"queued","created_at":1793318400,"expires_at":1793923200,"result":null,"error":null}每2秒查询 GET /jobs/{job_id};状态为queued、processing、succeeded或failed。成功时result包含费用、history_id和audio_url;失败时error包含status_code与message。每Key最多5个未完成任务,平台队列默认100个;查询也计入请求限额。任务与音频历史各保留7天,任务终态后清理正文。
同Key、同request_id和同参数重复提交返回原任务,参数不同返回409。终态failed不会因重复提交同ID重新执行;修正原因后使用新的业务ID。未提供ID时每次提交均为新任务。
response_format=url 的同步结果不返回audio_base64,而返回形如 /api/open/history/hist_xxx/audio 的audio_url。以站点源拼接地址,避免重复拼接/api/open,下载仍携带同Key。该地址不是公开播放链接。
GET /history/{history_id}/audio 默认返回二进制,传 response_format=base64 返回JSON。文件清理后410,不存在、非本Key或非成功记录404。历史查询本身只展示保留窗口内记录,不能依赖永久留存。
GET /jobs/{job_id}/audio 成功时307跳转至同站点历史接口,未成功409。客户端必须保留鉴权头;示例直接下载result.audio_url,避免不同HTTP库的重定向鉴权差异。
配额与生命周期
每Key默认最多100个有效私有音色,实际配额见/account。已删除、过期音色不占配额。注册后或最近一次成功合成后,连续30天无成功合成才进入清理流程;每次成功合成刷新计时。主动删除立即释放配额。
账号默认最多5个有效Key,以控制台显示为准。Key一旦吊销立即失效,无法继续查询、合成或下载;重建Key会产生新的资源归属,不代表自动迁移旧音色和历史。
模型目录与情感控制
公开能力代号包括standard、balanced、emotion、pro、v3及兼容项turbo、premium;V5开放后使用v5。可用性、注册资格、价格、语言及维护状态实时查询 /clone/models;未创建Key可浏览 /clone/catalog。不根据历史日期硬编码注册资格。
目录包含catalog_version、models、compat_models;每项包含key、name、cost_per_char、preset_mode、emotion_support、language_support、sample_rates、formats、supports_rate、max_chars、registration_allowed、maintenance和inline_tag_support。带Key的模型目录还包含presets。
preset_mode=instruction 支持自由风格指令;preset_mode=tag 从当前目录选择正文语气标签,不等同于任意自然语言指令。inline_tag_support.tags提供tag、label、category、default;单次最多100个标签。目录内合法标签不朗读、不参与限长和计费;V5自由提示的计费见下文。
正文可使用 [pause:1.5]:每处0.3~5秒,最多8处,合计不超过30秒;合法停顿不朗读、不参与限长及计费,纯停顿正文不可合成。pause_profile为general/audiobook/broadcast/ad,默认general。
HEYIN Natural V5 接入
V5 对外代号为 v5,以当前Key的 /clone/models 返回为准。公开目录未列出时不代表灰度Key已获得权限,未授权调用返回403。功能默认关闭,开放范围与注册资格均由目录和实际调用校验。
私有音色注册沿用 POST /clone/register,multipart表单传 model_key=v5;合成使用注册返回的本Key voice_id,不在合成时更换模型。公共音色可用 GET /library/voices?model=v5 筛选,再将 shared_voice_id 传给原 /library/synthesize 或 /library/jobs。站内私有音色不能直接用于第三方Key。
表演提示可写在正文中,例如 [带着笑意说]你好,欢迎使用合音。。能力目录的 inline_tag_support.mode=freeform 表示自由提示,direction_presets 提供内置快捷提示。提示不可为空、嵌套、跨行或缺括号,最多100处;必须有实际台词。停顿继续使用 [pause:1.5]。
当前V5基础单价为30积分/计费字,始终以模型报价与合成回执为准;公共音色使用其 price_per_char。目录内语气标签和明确匹配的内置提示按现行规则免计费,自定义自由提示不一律免计费。网页估算不执行生成,最终费用以 cost 为准。V5继续沿用API余额、幂等重试、失败退款、异步任务和鉴权下载,不自动迁移已有音色或改变旧模型费用。
V5不额外承诺原生时间线;需要字幕时先查询时间线资格和模式。下载地址只返回合音鉴权地址,不返回第三方服务地址或云侧音色标识。
已获V5权限的Key可使用以下注册示例;先设置环境变量 HEYIN_API_KEY,不要把真实Key写入代码或URL。失败时先检查HTTP状态与错误内容,不要使用未成功响应中的音色ID。
curl --fail-with-body --max-time 180 \
-H "X-API-Key: $HEYIN_API_KEY" \
-F 'file=@voice.wav' -F 'voice_name=我的音色' \
-F 'model_key=v5' -F 'prompt_lang=zh' -F 'denoise=false' \
-F 'request_id=v5-register-business-001' \
'https://www.heyintts.cn/api/open/clone/register'随后以返回的 voice_id 替换下方占位值,将JSON提交至 /clone/synthesize。长文本可提交 /clone/jobs 并按异步章节轮询与下载;新的业务使用新的request_id,网络重试则保留原ID与参数。
{"voice_id":"clone_返回的业务音色ID","text":"[带着笑意说]你好,欢迎使用合音。","request_id":"v5-synth-business-001","output_format":"mp3","response_format":"url"}正在获取模型与报价…
API定价与费用估算
预付费按量计费,无固定Free订阅套餐。单价以 /clone/balance、/clone/models 和公共音色目录price_per_char为准。充值目录与页面共用后端公开报价;注册、同步和异步实际执行均以调用时校验为准。
计费规则:中文、数字和其他字母每个计1字;ASCII英文字母每2个计1字、奇数向上取整;标点符号另每2个计1字、奇数向上取整;空白不计费。合法停顿和当前能力目录语气标签先剥离。你好[pause:1.5]世界 为4个计费字,单价6时24积分。
基础兑换率为1元=10000积分;5积分/字时1000计费字为5000积分、约0.50元,6积分/字时为6000积分、约0.60元,均未计赠送折扣。估算不发起合成,最终费用以cost为准。
充值包/赠送以目录packs为准;按量充值最低10元、金额为10的倍数。API专用余额默认按积分包→赠送→按量余额扣减;已绑定统一账户的Key按实际账户规则扣减。控制台用量为累计净消耗,不是当月额度,退款计入净额。
正在获取单价…
时间线与字幕下载
合成可选 timeline_mode,默认 off。支持 native 原生时间戳、auto 优先原生并按Key资格异步对齐、forced 外置对齐。请求前查询 GET /timeline/capabilities?model=emotion 获取当前Key资格及同步/异步上限;只支持公开模型代号。功能尚未启用返回503;forced无资格403、节点离线503、队列满429,均在合成扣费前拒绝。
auto 无外置资格、节点不可用或准入队列满时回退原生;没有可验证结果返回unavailable。原生可能是词级,查看granularity;要求中文逐字可选forced。运行中节点掉线仍可能失败,不保证受理即完成逐字对齐。
当前外置节点只开放中文/英文,见external_languages;其它明确语种或可识别的其它文字,forced在扣费前422拒绝,auto回退原生。供应商原生模式的语种继续由音色能力决定。
{"shared_voice_id":123,"text":"你好,欢迎使用。","request_id":"timeline-demo-001","output_format":"mp3","response_format":"url","timeline_mode":"auto"}音频成功即可使用,响应增加timeline_status、timeline_url和timeline_poll_after_ms;保持原cost、remaining_points与音频字段。状态为pending/processing/ready/partial/failed/unavailable。按建议间隔轮询,429遵守Retry-After;GET /history/{history_id}/timeline返回最新状态及可用文档。异步合成jobs在音频完成时succeeded,时间线可继续pending,后续任务查询反映最新时间线状态。
四种字幕在 GET /history/{history_id}/subtitles?format=json 下载,format还支持srt/vtt/ass。JSON含完整逐字/词时间;SRT/VTT按句输出,ASS支持字词时序。GET /history/{history_id}/audio-with-timeline?format=auto 返回内嵌MP3/WAV副本;format=wav请求WAV,Opus/已知采样率PCM经解码校验后可封装WAV。原音频不变;常规播放器不保证展示自定义内嵌字幕,需要支持协议的客户端解析。
查询文档沿用schema_version=1,时间为全音频整数毫秒。text_start/text_end针对返回文档text,为Unicode码点左闭右开索引;服务端会去首尾空白并规范化合法标签,不应直接索引未处理的请求原字符串。JavaScript须按码点转换,不能直接套UTF-16下标。quality包含text_coverage和missing_text_ranges;无法可靠定位的字保持partial,不能按字数均分时间。partial导出需显式allow_partial=true,否则409。
已有音频可 POST /history/{history_id}/alignment,请求体 {};失败或partial时传 {"retry":true} 重试。需要服务端保留的完整原文和可信历史关联,旧版历史缺关联返回422;旧长音频缺可信分段也返回422,不猜时间或重新合成。单资源最多三次申请/重试,间隔至少30秒,超过429。对齐不重新扣取合成费用;更改朗读文字或声音需要新音频版本。
所有查询和下载均需原Key鉴权,同账号其它Key无权读取。资源过期410、版本变化409、未知或异Key404,Key吊销401。下载地址不含Key,不应作为公开分享链接。沿用历史7天保留期,请及时保存音频及字幕;重试、状态查询与导出仍计入Key请求限流。
默认off保持旧幂等摘要;显式时间线模式参与参数摘要,同ID改变模式409。已有音频补对齐走alignment接口,避免改合成参数后重复计费。时间线独立失败不会回退已成功音频或再次合成;检查timeline_error_code与retryable处理。
下载完整Python时间线示例:安装requests,设置HEYIN_API_KEY及HEYIN_SHARED_VOICE_ID后运行。示例固定保存业务参数和request_id,先下载原音频再等待时间线;重复运行同一输出目录复用原任务,新业务使用新的HEYIN_OUTPUT_DIR。示例需要已开放该能力的Key,默认只接受HTTPS同源下载。
错误处理与安全重试
| HTTP | 处理方式 |
|---|---|
| 400 | 检查文本、停顿、音色配额和能力资格;字数错误含TTS_TEXT_TOO_LONG |
| 401 | Key缺失、无效或已吊销;检查环境变量与请求头 |
| 402 | 余额不足或消费额度不足;核对账户后处理 |
| 403 | 能力不允许新注册或内容不可对外使用 |
| 404 | 资源不存在、无权限或已经过期 |
| 409 | 参数冲突、同ID处理中或任务尚未成功,分别处理 |
| 410 | 原结果已清理,核对业务后使用新ID;旧任务提交亦可能返回 |
| 413 | HTTP请求体过大,压缩参考音频并为表单留余量 |
| 422 | 字段类型、范围、枚举或内容/样本校验失败 |
| 429 | 请求限流、排队已满或等待超时,按Retry-After退避 |
| 500/502/503 | 合成失败、维护或暂时不可用;已扣费用失败自动退款,异常由补偿继续处理 |
常见错误detail是字符串、包含code/message的对象,或字段校验数组,必须先检查HTTP状态。不要在错误响应上读取audio_base64。
{"detail":{"code":"API_BUSY","message":"请求较多,请稍后重试"}}同步建议固定request_id:同Key同接口同参数重放原成功结果,不重复扣费;参数不同409,仍处理中409。失败退款后可复用原同步ID重试。不同同步接口不能复用同ID;幂等记录默认7天,超期无去重保证,业务侧保存订单与音频结果。
默认每Key每10秒20次请求,查询、轮询和下载也计数。云调用跨worker共享全局及每Key上限,有限排队;具体配置通过/account读取。429按Retry-After退避;网络超时先复用原参数和ID,不立即换ID重新扣费。异步终态失败的重提规则见异步章节。