语音通知 API 开发文档

标准 HTTPS 接口,UTF-8 表单请求、JSON 响应,支持完整内容和模板变量发送。查看认证、参数、多语言示例、模板管理及回执说明。

3分钟快速接入
6种语言代码示例
HTTPS 加密传输
API文档

接口简介

通过 HTTPS 调用语音通知服务,支持 GET / POST,采用 UTF-8 编码。以下示例使用 POST 表单请求与 .json 接口地址。

涵盖发送、余额查询、模板管理和回执推送。

Content-Type: application/x-www-form-urlencoded

请求体使用 URL 编码的表单参数;JSON 是响应格式,不是请求体格式。

接入准备

  1. 注册账户并按要求完成认证。
  2. 在用户中心获取语音通知产品的 API ID / API KEY。
  3. 报备实际通知模板,确认审核通过后,用授权测试号码联调发送与回执。

认证与动态密码

参数类型必填说明
accountstring是语音通知产品的 API ID,在用户中心「云语音 → 语音通知 → 产品总览」查看。
passwordstring是API KEY,或按下方规则生成的动态密码。
timestring条件必填使用动态密码时必填;10 位 Unix 时间戳,单位秒。

可直接使用 API KEY,也可使用动态密码。将以下字段按顺序直接拼接(不加分隔符),以 UTF-8 编码计算 MD5,结果作为 password,并同时提交 time。

操作动态密码计算规则
发送通知MD5(account + APIKEY + mobile + content + time)
余额查询 / 提交模板 / 删除模板MD5(account + APIKEY + time)

发送时,参与签名的 content 必须与实际提交的完整内容或变量字符串一致。凭据仅保存在服务端,勿写入前端页面。

发送语音通知

POST https://api.ihuyi.com/vm/Submit.json

支持全天 24 小时提交。先确定完整内容或模板变量发送方式,再填写对应参数。

请求参数

参数类型必填说明
accountstring是语音通知产品的 API ID,在用户中心「云语音 → 语音通知 → 产品总览」查看。
passwordstring是API KEY,或按下方规则生成的动态密码。
mobilestring是中国内地 11 位手机号码或带区号的固话号码;每次仅提交一个号码。
contentstring否完整内容方式填写已审核模板对应的完整通知内容;模板变量方式只填写变量值,多个变量用英文竖线 | 按模板顺序分隔。
templateidint条件必填模板变量方式必填。调试可使用系统模板 ID 1361。
timestring条件必填使用动态密码时必填;10 位 Unix 时间戳,单位秒。

完整内容方式

提交已审核模板对应的完整语音内容;固定文字、标点及变量须符合模板设置。

content=已审核模板对应的完整通知内容

模板变量方式

系统调试模板 1361:您的订单号是:【变量】。已由【变量】发出,请注意查收。

templateid=1361
content=9633|顺风快递

这里 content 填写两项变量值,按模板顺序以 | 分隔。POST 时仍需对表单参数进行 URL 编码。

多语言代码示例

在服务端设置账户环境变量,替换为授权测试号码和已审核模板对应的完整内容。以下代码只作展示,页面不会发起呼叫。

import os
import requests

url = "https://api.ihuyi.com/vm/Submit.json"
data = {
    "account": os.environ["IHUYI_API_ID"],
    "password": os.environ["IHUYI_API_KEY"],
    "mobile": "YOUR_TEST_MOBILE",
    "content": "已审核模板对应的通知内容",
}

response = requests.post(
    url,
    data=data, timeout=10
)
response.raise_for_status()
print(response.json())
# 提交成功不等于呼叫成功,结果请结合回执判断。
<?php
// PHP 7.4+,需启用 cURL 扩展;仅在服务端运行。
$account = getenv('IHUYI_API_ID');
$password = getenv('IHUYI_API_KEY');
if (!$account || !$password) {
    throw new RuntimeException('请配置 IHUYI_API_ID 和 IHUYI_API_KEY');
}
$url = 'https://api.ihuyi.com/vm/Submit.json';
$data = [
    'account' => $account,
    'password' => $password,
    'mobile' => 'YOUR_TEST_MOBILE',
    'content' => '已审核模板对应的通知内容',
];
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($data),
    CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
]);
$result = curl_exec($ch);
$error = curl_error($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($result === false) {
    throw new RuntimeException($error);
}
if ($status < 200 || $status >= 300) {
    throw new RuntimeException('HTTP ' . $status);
}
echo $result;
// 提交成功不等于呼叫成功,结果请结合回执判断。
// Java 11+;保存为 VoiceNotify.java,仅在服务端运行。
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class VoiceNotify {
    public static void main(String[] args) throws Exception {
        String account = System.getenv("IHUYI_API_ID");
        String password = System.getenv("IHUYI_API_KEY");
        if (account == null || account.isBlank()
                || password == null || password.isBlank()) {
            throw new IllegalStateException("请配置 IHUYI_API_ID 和 IHUYI_API_KEY");
        }
        Map<String, String> data = new LinkedHashMap<>();
        data.put("account", account);
        data.put("password", password);
        data.put("mobile", "YOUR_TEST_MOBILE");
        data.put("content", "已审核模板对应的通知内容");
        String body = data.entrySet().stream()
            .map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8)
                + "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
            .collect(Collectors.joining("&"));
        String url = "https://api.ihuyi.com/vm/Submit.json";
        HttpRequest request = HttpRequest.newBuilder(URI.create(url))
            .timeout(Duration.ofSeconds(10))
            .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
            .POST(HttpRequest.BodyPublishers.ofString(body))
            .build();
        HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10)).build();
        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
        if (response.statusCode() < 200 || response.statusCode() >= 300) {
            throw new IllegalStateException("HTTP " + response.statusCode());
        }
        System.out.println(response.body());
        // 提交成功不等于呼叫成功,结果请结合回执判断。
    }
}
// Node.js 22+,使用内置 fetch;仅在服务端运行。
async function main() {
  const { IHUYI_API_ID, IHUYI_API_KEY } = process.env;
  if (!IHUYI_API_ID || !IHUYI_API_KEY) {
    throw new Error('请配置 IHUYI_API_ID 和 IHUYI_API_KEY');
  }
  const url = 'https://api.ihuyi.com/vm/Submit.json';
  const body = new URLSearchParams({
    account: IHUYI_API_ID,
    password: IHUYI_API_KEY,
    mobile: 'YOUR_TEST_MOBILE',
    content: '已审核模板对应的通知内容',
  });
  const response = await fetch(url, {
    method: 'POST',
    body,
    signal: AbortSignal.timeout(10000),
  });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  console.log(await response.json());
  // 提交成功不等于呼叫成功,结果请结合回执判断。
}
main().catch(error => {
  console.error(error.message);
  process.exitCode = 1;
});
// Go 1.20+;仅在服务端运行。
package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "strings"
    "time"
)

func main() {
    account, password := os.Getenv("IHUYI_API_ID"), os.Getenv("IHUYI_API_KEY")
    if account == "" || password == "" { panic("请配置 API ID 和 API KEY") }
    form := url.Values{
        "account": {account}, "password": {password},
        "mobile": {"YOUR_TEST_MOBILE"},
        "content": {"已审核模板对应的通知内容"},
    }
    req, err := http.NewRequest(http.MethodPost, "https://api.ihuyi.com/vm/Submit.json", strings.NewReader(form.Encode()))
    if err != nil { panic(err) }
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    client := &http.Client{Timeout: 10 * time.Second}
    resp, err := client.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    if resp.StatusCode < 200 || resp.StatusCode >= 300 { panic(resp.Status) }
    body, err := io.ReadAll(resp.Body)
    if err != nil { panic(err) }
    fmt.Println(string(body))
}
// .NET 8+;仅在服务端运行。
using System;
using System.Collections.Generic;
using System.Net.Http;

var account = Environment.GetEnvironmentVariable("IHUYI_API_ID")
    ?? throw new InvalidOperationException("请配置 API ID");
var password = Environment.GetEnvironmentVariable("IHUYI_API_KEY")
    ?? throw new InvalidOperationException("请配置 API KEY");
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
using var body = new FormUrlEncodedContent(new Dictionary<string, string> {
    ["account"] = account, ["password"] = password,
    ["mobile"] = "YOUR_TEST_MOBILE",
    ["content"] = "已审核模板对应的通知内容"
});
using var response = await client.PostAsync("https://api.ihuyi.com/vm/Submit.json", body);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());

发送响应

字段类型说明
codeint2 表示提交成功;其他值结合 msg 排查。
msgstring本次请求的结果描述。
voiceidstring提交成功时的发送流水号;失败时可能为 0、空或不返回。
{
  "code": 2,
  "msg": "提交成功",
  "voiceid": "16236437872836"
}

提交成功仅表示平台接受请求,不代表用户已接听。保存 voiceid,通过发送回执关联最终呼叫结果。

余额查询

POST https://api.ihuyi.com/vm/GetNum.json
参数类型必填说明
accountstring是语音通知产品的 API ID,在用户中心「云语音 → 语音通知 → 产品总览」查看。
passwordstring是API KEY,或按下方规则生成的动态密码。
timestring条件必填使用动态密码时必填;10 位 Unix 时间戳,单位秒。
字段类型说明
codeint2 表示查询成功。
msgstring查询结果描述。
numint账户余额值,成功时返回。
{
  "code": 2,
  "msg": "提交成功",
  "num": 123456
}

模板管理

提交模板

POST https://api.ihuyi.com/vm/AddTemplate.json
参数类型必填说明
accountstring是语音通知产品的 API ID,在用户中心「云语音 → 语音通知 → 产品总览」查看。
passwordstring是API KEY,或按下方规则生成的动态密码。
contentstring是模板内容,长度为 15–500 个字符;可用 【变量】 标记可替换内容。
timestring条件必填使用动态密码时必填;10 位 Unix 时间戳,单位秒。

响应包含 code、msg;添加成功(code=2)时还返回整数类型 templateid。添加成功后,仍需等待审核结果再发送。

删除模板

POST https://api.ihuyi.com/vm/DelTemplate.json
参数类型必填说明
accountstring是语音通知产品的 API ID,在用户中心「云语音 → 语音通知 → 产品总览」查看。
passwordstring是API KEY,或按下方规则生成的动态密码。
templateidint是需要删除的模板 ID。
timestring条件必填使用动态密码时必填;10 位 Unix 时间戳,单位秒。

响应字段为 code、msg;code=2 表示删除成功。

发送回执推送

提供并绑定服务端接收 URL。平台向该地址 POST 表单数据,采用 UTF-8 编码。

Content-Type: application/x-www-form-urlencoded
字段类型说明
codeint呼叫结果;2 表示成功,其余为失败状态。
msgstring呼叫状态描述。
mobilephonestring接收号码。
voiceidstring与发送响应对应的流水号。
report_timestring回执时间,例如 2017-08-02 14:31:51。
talktimeint通话时长,单位秒。

接收端记录数据后应及时输出纯文本 success(不含引号),复杂业务异步处理。未确认接收时,每个回执最多推送 3 次,每次间隔叠加 60 秒;需处理重复推送。

呼叫状态码

code含义
2成功
0未知错误
-1关机
-2停机
-3暂时无法接通
-4正在通话
-5空号
-6无人接听
-8呼入限制
-9网络忙
-10呼出限制
-11线路忙
-12用户拒接
-13被叫忙

模板审核状态推送

同样通过 POST 表单推送到绑定的接收 URL,UTF-8 编码。

字段类型说明
codeint2 表示审核成功;0 表示驳回。
msgstring审核状态描述;驳回时查看具体原因。
templateidstring本次审核的模板 ID。

成功接收后输出纯文本 success。未确认接收时最多推送 3 次,每次间隔叠加 60 秒。

接口状态与错误码

发送接口

code含义
0提交失败
2提交成功
400访问 IP 不合法
401账户未填写
402密码未填写
403接收号码未填写
4030接收号码在黑名单中
404缺少语音内容
405账户或密码校验失败
4050账户被冻结
40505尚未签订合同
4051剩余条数不足
4052请求 IP 与备案 IP 不一致
406接收号码格式不正确
407语音内容包含敏感字符
4071尚未报备模板
4072发送内容与已报备模板不匹配
40722变量长度超过模板设置
4077发送内容尚未在运营商报备
408单个号码当日累计发送超过 50 条,被自动冻结;需调整请联系客服
4080同一号码一秒内发送超过 1 条
4081同一号码一分钟内发送超过 10 条
4086提交失败

余额与模板接口

适用接口code含义
余额 / 模板接口400 / 401 / 402访问 IP 不合法 / 未填写账户 / 未填写密码
余额 / 模板接口405 / 4050凭据校验失败 / 账户被冻结
余额 / 模板接口40501 / 40502动态密码已过期 / 动态密码校验失败
提交模板404 / 4041缺少模板内容 / 内容长度不在 15–500 字符范围内
提交模板406 / 4066未充值不能提交模板 / 添加频率超限(每分钟最多 10 次)
提交模板407 / 408模板包含敏感字符 / 模板已存在
删除模板404模板 ID 未填写或不存在

以上为接口业务 code,应与 HTTP 状态码分别处理。完整定义见官方接口文档。

立即开始使用语音通知 API

注册送10条调试额度 · 3分钟快速接入 · 免费技术支持