VoxAgent Product and AI Skill Summary

VoxAgent is a phone voice runtime for AI Agents. It lets AI Agents make outbound calls, receive inbound calls, and run real-time phone conversations through number resources, real-time voice runtime, webhook/SSE events, trial workflows, and production access control.

VoxAgent AI Skill

VoxAgent publishes an AI-readable Skill named vox-phone-notification. The Skill turns natural-language notification requests into TeddyMobile Vox phone notifications. It supports no-credential dry-run validation, promotion trial phone calls, post-trial formal setup guidance, formal outbound phone notifications, HMAC outbound API examples, and callback server examples.

AI agents should read https://vox-ai.teddymobile.cn/product.md first for product positioning, then https://vox-ai.teddymobile.cn/docs.md for the API contract, then https://vox-ai.teddymobile.cn/skills.md for the AI Skill guide and https://vox-ai.teddymobile.cn/.well-known/ai-skills.json for the structured Skill manifest.

AI-readable product overview: https://vox-ai.teddymobile.cn/product.md AI-readable Skill guide: https://vox-ai.teddymobile.cn/skills.md AI Skill manifest: https://vox-ai.teddymobile.cn/.well-known/ai-skills.json Download VoxAgent Skill: https://vox-ai.teddymobile.cn/skills/vox-phone-notification-skillhub.zip

VoxAgent Complete Public API Documentation Mirror

This visually hidden section is a complete API documentation mirror for AI crawlers that only read the homepage HTML. The canonical documentation is also available at /docs, /docs.md, /docs.json, and /llms.txt. It includes outbound call API, HMAC authentication, request headers, request body parameters, response examples, webhook callback protocol, and SSE streaming contract.

# Vox平台-API接入文档V1.0.4



[TOC]

## 1、修订记录

| 版本   | 修订内容                               | 修订人 | 修订时间   |
| ------ | -------------------------------------- | ------ | ---------- |
| V1.0.1 | 编写初稿                               | 李欢   | 2026-03-19 |
| V1.0.2 | 完善接口规范                           | 李欢   | 2026-03-26 |
| V1.0.3 | 外呼接口增加扩展字段,实现额外扩展功能 | 李欢   | 2026-05-11 |
| V1.0.4 | 外呼接口增加botType和agentProfile配置  | 李欢   | 2026-05-20 |

## 2、概述

### 2.1 接入流程

1. 商家与泰迪熊移动签订相关合作授权协议。
2. 商家通过统一平台注册企业账号,并提交资质认证。
3. 商家联系泰迪熊审核账号资质,并分配相关权限。
4. 泰迪熊提供企业账号appId和签名秘钥。

### 2.2 安全机制

#### 2.2.1 通讯安全

- 泰迪熊移动商家开放平台基于https协议搭建,并要求合作商家同样采用https协议
- 泰迪熊移动商家开放平台通过IP白名单机制限制访问来源,非白名单无法访问服务。
- 泰迪熊移动商家开放平台会根据访问商家检测访问量和访问频率,超出预定数值将自动发出预警,必要时会临时切断商家访问,为避免此情况发生,请在申请阶段如实告知预计访问量。

#### 2.2.2 会话安全

- 泰迪熊移动商家开放平台采用签名校验安全机制,通过接口信息和客户唯一secret生成签名。

#### 2.2.3 生成签名方式

将参与生成签名的参数按顺序拼接字符串,按对应加密方式获得签名。

##### 加密方式

hmac-sha256

##### 参数

|   参数    |  类型  |      描述      |                             备注                             |
| :-------: | :----: | :------------: | :----------------------------------------------------------: |
|  method   | String |    请求方式    | 需转为大写,如:GET/PUT/POST/DELETE/OPTIONS/HEADER等HTTP协议中定义的method |
|   path    | String |    接口路径    |                       例:/vox/api/xx                        |
| uriParams | String |    uri参数     | uri中"?"后的部分,不包括"?",例如:key1=value 1&key2 = value 2 |
|   appid   | String | 企业账号appId  |                         由泰迪熊分配                         |
|  dateGMT  | String |    请求时间    |      GMT格式的时间,必须与HTTP Header中的HMAC-DATE一致       |
|  secret   | String | 企业账号的密钥 |                         由泰迪熊分配                         |

##### 代码示例

```
public class SignatureHelper {
   private static String signatureHmacSHA256(String message, String secret) {
       try {
           Mac hasher = Mac.getInstance("HmacSHA256");
           hasher.init(new SecretKeySpec(secret.getBytes(), "HmacSHA256"));
           byte[] hash = hasher.doFinal(message.getBytes("UTF-8"));
           // to base64
           return DatatypeConverter.printBase64Binary(hash);
      } catch (NoSuchAlgorithmException e) {
 
      } catch (InvalidKeyException e) {
 
      }
       return null;
  }
 
   /**
    * @param method   HTTP Method,例如:GET/PUT/POST/DELETE/OPTIONS/HEADER等HTTP协议中定义的method,必须是大写。
    * @param path     接口路径,例如:/sm/api/statistic/event,必须以"/"开头。
    * @param uriParams uri中"?"后的部分,不包括"?",例如:key1=value 1&key2 = value 2,参数字符串要按照各参数名称的字符顺序进行排列。
    * @param appid     主账号的appid
    * @param dateGMT   GMT格式的时间,必须与HTTP Header中的HMAC-DATE一致
    * @param secret   主账号的密钥
    * @return 生成好的签名
    */
   public static String buildSignature(String method, String path, String uriParams, String appid, String dateGMT, String secret) {
       StringBuilder s = new StringBuilder();
       s.append(method.toUpperCase() + "\n");
       if (!path.startsWith("/")) {
           path = "/" + path;
      }
       s.append(path + "\n");
       if (uriParams == null) {
           uriParams = "";
      }
       s.append(sortParam(uriParams.split("&")) + "\n");
       s.append(appid + "\n");
       s.append(dateGMT + "\n");
       s.append("HMAC-APPID:" + appid + "\n");
       String message = s.toString();
       return buildSignature(message, secret);
  }
  
  private static String sortParam(String[] params) {
        Arrays.sort(params);
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < params.length; i++) {
            builder.append(params[i]);
            if (i < params.length - 1) {
                builder.append("&");
            }
        }
        return builder.toString();
   }
 
   public static String buildSignature(String message, String secret) {
       return signatureHmacSHA256(message, secret);
  }
}
```

```
// 加密Demo
class SignatureHelperTest {
 
   @Test
   void buildSignature() {
       String appid = "demouser";
       String secret = "demosecret";
       
       String method = "POST";
       String path = "/sms/api/xx";
       String uriParams = "a=b&x=y";
 
       //此处生成的GMT格式时间在发起HTTP请求时会使用到
       SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
       sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
       String dateGMT = sdf.format(new Date());
       
       //获取签名
       String signature = SignatureHelper.buildSignature(method, path, uriParams, appid, dateGMT, secret);
       System.out.println(signature);
       
       //j+DiLfTZoYyviAjSXejL0RyAvPHa8z4YR72n2/YUD4I=
  }
}
```



### 2.3 域名信息

| 环境     | 域名地址                   |
| -------- | -------------------------- |
| 生产环境 | https://vox.teddymobile.cn |

### 2.4 术语解释

### 2.5 公共参数

- HTTP请求头必须添加5个HMAC-xxx参数

|       参数名        |  类型  |    描述    |                             备注                             |
| :-----------------: | :----: | :--------: | :----------------------------------------------------------: |
|     HMAC-APPID      | String |   appId    |                     泰迪熊分配的appId。                      |
|      HMAC-DATE      | String |  请求时间  | GMT格式的时间,必须与签名时生成的GMT时间保持一致。务必确保服务器时钟准确,时钟偏移过大会导致身份认证失败。 |
|   HMAC-SIGNATURE    | String |    签名    |       例:j+DiLfTZoYyviAjSXejL0RyAvPHa8z4YR72n2/YUD4I=       |
|   HMAC-ALGORITHM    | String |  加密算法  |                      固定值 hmac-sha256                      |
| HMAC-SIGNED-HEADERS | String | 签名头信息 |                      固定值 HMAC-APPID                       |

- 响应体

  | 参数名 |  类型  | 是否必填 |     描述     |  备注   |
  | :----: | :----: | :------: | :----------: | :-----: |
  |  code  |  int   |    是    |    状态码    | 成功:0 |
  |  msg   | String |    否    |   返回说明   |         |
  |  data  | Object |    否    | 具体业务数据 |         |
  |  time  |  long  |    是    |   响应时间   | 时间戳  |
  
  

## 3、业务接口

### 3.1 发起外呼

发起一个 outbound call(外呼)请求。

**接口地址**:`/vox/v1/outbound`

**请求方法**:`POST`

**请求参数**:

通话类bot请求示例:

```
{
  "appId": "d63dd1e9-3aa3-4f88-8d3e-2be7461dff56",
  "botid": "bot_10001",
  "callee": "131****1234",
  "requestId": "66016fe1fa414ca48596aad35c457106"
}
```

通知类bot请求示例:

```
{
  "appId": "d63dd1e9-3aa3-4f88-8d3e-2be7461dff56",
  "botid": "bot_10001",
  "callee": "131****1234",
  "requestId": "req_20260313144300001",
  "extra": "{\"notification\":{\"text\":\"您好,这是一条通知\",\"times\":2}}"
}
```

自定义bot请求示例:

```json
{
  "appId": "d63dd1e9-3aa3-4f88-8d3e-2be7461dff56",
  "botid": "",
  "callee": "131****1234",
  "requestId": "66016fe1fa414ca48596aad35c457106",
  "botType": "custom",
  "extra": "{\"agent_profile\":{\"name\":\"小美\",\"gender\":\"女\",\"age\":25,\"role\":\"销售顾问\",\"communicationStyle\":[\"热情\",\"专业\",\"亲切\"],\"background\":\"春季新品推广活动\",\"goals\":\"了解客户购买意向,促成交易\",\"skills\":\"产品介绍、需求挖掘、促成交易\",\"workflow\":\"问候 -> 了解需求 -> 介绍产品 -> 处理异议 -> 促成合作\",\"constraint\":\"保持礼貌、尊重对方意愿、不强制推销\",\"openingPrompt\":\"您好,我是小美,春季新品推广活动的销售顾问\"}}"
}
```

**请求字段说明**:

| 字段                     | 类型       | 必填 | 说明                                     | 示例                                 |
| ------------------------ | ---------- | ---- | ---------------------------------------- | ------------------------------------ |
| appId                    | string     | 是   | 身份标识                                 | d63dd1e9-3aa3-4f88-8d3e-2be7461dff56 |
| botid                    | string     | 是   | 机器人 ID(平台侧生成),当botType为"custom"时非必填 | `10001`                              |
| callee                   | string     | 是   | 被叫号码(用户手机号)                   | `13800138000`                        |
| requestId                | string     | 是   | 请求 ID(由调用方生成,用于幂等性保证)  | `66016fe1fa414ca48596aad35c457106`   |
| botType                  | string     | 否   | Bot 类型,当前仅支持 "custom"(自定义Bot) | `custom`                             |
| extra                    | JSONString | 否   | 扩展功能字段                             |                                      |
| extra.voiceType          | string     | 否   | TTS音色类型编码。<br/>可选值及适用场景:<br/>• `0` - 知愈(女):情绪安抚、心理陪伴、售后回访、不知道选什么<br/>• `1` - 安辰(男):给长辈/老人做的任何语音内容<br/>• `2` - 景珩(男):商务沟通、企业合作、科普讲解类内容<br/>• `3` - 知言(女):发通知、公告、正式播报类内容<br/>• `4` - 星苒(女):日常闲聊、陪伴、电商带货、生活服务类内容 | `0`                                  |
| extra.agent_profile      | Object     | 否   | 自定义Bot配置,当botType为"custom"时必填 |                                      |
| extra.agent_profile.name | string     | 是   | Bot名称                                  | `小美`                               |
| extra.agent_profile.gender | string   | 是   | Bot性别                                  | `女`                                 |
| extra.agent_profile.age  | int        | 是   | Bot年龄                                  | `25`                                 |
| extra.agent_profile.role | string     | 是   | Bot角色定位                              | `销售顾问`                           |
| extra.agent_profile.communicationStyle | array | 是 | 沟通风格列表                           | `["热情", "专业", "亲切"]`           |
| extra.agent_profile.background | string | 是 | 业务背景                               | `春季新品推广活动`                   |
| extra.agent_profile.goals | string    | 是   | Bot目标                                  | `了解客户购买意向,促成交易`          |
| extra.agent_profile.skills | string   | 是   | Bot技能                                  | `产品介绍、需求挖掘、促成交易`       |
| extra.agent_profile.workflow | string | 是   | 工作流程                                 | `问候 -> 了解需求 -> 介绍产品 -> 处理异议 -> 促成合作` |
| extra.agent_profile.constraint | string | 是 | 约束条件                               | `保持礼貌、尊重对方意愿、不强制推销` |
| extra.agent_profile.openingPrompt | string | 是 | 开场白                                 | `您好,我是小美,春季新品推广活动的销售顾问` |
| extra.notification       | Object     | 否   | 通知类bot相关的额外配置内容              |                                      |
| extra.notification.text  | string     | 是   | 通知内容,extra.notification不为空时必填 | 您好,这是一条通知                    |
| extra.notification.times | int        | 否   | 播放次数,默认为播放1次                  | 2                                    |

**响应示例**:

```json
{
  "code": 0,
  "msg": "success",
  "data": {
    "requestId": "66016fe1fa414ca48596aad35c457106",
    "status": "accepted"
  }
}
```

**响应字段说明**:

| 字段           | 类型   | 说明                                                 |
| -------------- | ------ | ---------------------------------------------------- |
| code           | int    | 响应码,0 表示成功                                   |
| msg            | string | 响应消息                                             |
| data.requestId | string | 请求 ID,与请求中的 requestId 一致                   |
| data.status    | string | 任务状态:`accepted`(已成功接收) \| failed(失败) |

**HTTP 状态码**:

- `202 Accepted` - 请求已被接受处理

## 4、Webhook 回调

### 4.1 SSE 协议方式实现

 Vox通过 HTTP POST + SSE(Server-Sent Events)流式交互协议与第三方开发者系统进行实时双向通信。

#### 4.1.1 协议概述

- **方向**:Vox 作为 HTTP Client 主动发起请求,第三方系统作为 HTTP Server 提供 API
- **传输方式**:单次 HTTP POST 请求,第三方返回 `text/event-stream` 持续流式响应
- **会话连续性**:通过 `conversation_uuid` 维护,而非长连接
- **适用场景**:需要流式输出、支持打断的多轮对话场景

#### 4.1.2 接口地址

由第三方开发者自行提供 HTTPS 端点地址,在创建机器人时配置。

#### 4.1.3 请求方法

`POST`

#### 4.1.4 请求头

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| Content-Type | String | 是 | `application/json` |
| Accept | String | 是 | `text/event-stream` |

#### 4.1.5 请求体

```json
{
    "turn": 6,
    "calltype": "inbound",
    "callee": "18600013645",
    "caller": "+8652780515543",
    "callid": "4e0c4ecf-1ad6-42c3-b343-e1eb90ee18c6",
    "requestid": "1ad64ecf-b343-42c3-1ad6-e1eb90eeb343",
    "message": "好,请问你是哪里的人?"
}
```

**字段说明**:

| 字段 | 类型 | 必填 | 说明 | 示例 |
|------|------|------|------|------|
| message | String | 是 | 用户输入文本(电话接通后第一次请求为"") | `"我想了解套餐"` |
| callid | String | 是 | 通话的唯一id标识 |  |
| requestid | String | 是 | 本次请求的唯一id标识 |  |
| caller | String | 是 | 主叫号码 |  |
| callee | String | 是 | 被叫号码 |  |
| calltype | String | 是 | inbound-呼入  outbound-呼出 |  |
| turn | int | 是 | 通话轮次,接通后第一次为1 |  |

#### 4.1.6 SSE 响应协议

**Media Type**: `text/event-stream`

**响应块类型**:

**1. 文本流块**(持续返回文本片段)

```text
data: {"id":"1ad64ecf-b343-42c3-1ad6-e1eb90eeb343",
"created":1678901234,"message":"你好"}
```

继续:

```text
data: {"id":"1ad64ecf-b343-42c3-1ad6-e1eb90eeb343",
"created":1678901234,"message":",我愿意倾听你。"}
```

**2. 完成标记**(必须发送)

```text
data: [DONE]
```

**响应字段说明**:

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | String | 是 | 消息唯一标识,与请求体中requestid一致,原样返回 |
| created | Long | 是 | 消息创建时间戳 |
| message | String | 是 | 非空文本片段,Vox 按到达顺序拼接并切句 |
| action  | JSON | 否 | 扩展功能字段,例:{"cmd": "hangup"}表示需要主动挂断 |

#### 4.1.7 交互流程

**1. 通话开始**(call.started)

```
Vox -> 第三方:POST /developer-api
Request:
{
    "turn": 1,
    "calltype": "inbound",
    "callee": "18600013645",
    "caller": "+8652780515543",
    "callid": "4e0c4ecf-1ad6-42c3-b343-e1eb90ee18c6",
    "requestid": "1ad64ecf-b343-42c3-1ad6-e1eb90eeb343",
    "message": ""
}

第三方 -> Vox: SSE Stream
data: {"id":"1ad64ecf-b343-42c3-1ad6-e1eb90eeb343",
"created":1678901234,"message":"您好"}
data: {"id":"1ad64ecf-b343-42c3-1ad6-e1eb90eeb343",
"created":1678901234,"message":",我愿意倾听你。"}
data: [DONE]
```

**2. 用户说话**(asr.transcript)

```
Vox -> 第三方:POST /developer-api
Request:
{
    "turn": 2,
    "calltype": "inbound",
    "callee": "18600013645",
    "caller": "+8652780515543",
    "callid": "4e0c4ecf-1ad6-42c3-b343-e1eb90ee18c6",
    "requestid": "550e8400-e29b-41d4-a716-446655440000",
    "message": "我想办理宽带业务"
}

第三方 -> Vox: SSE Stream
data: {"id":"550e8400-e29b-41d4-a716-446655440000",
"created":1678901234,"message":"好的"}
data: {"id":"550e8400-e29b-41d4-a716-446655440000",
"created":1678901234,"message":",请问您需要办理哪种宽带套餐?"}
data: [DONE]
```

**3. 用户打断**(barge-in)

当用户打断时:
1. Vox 主动关闭当前 SSE 流
2. 标记旧 response 为废弃
3. 基于新 transcript 发起下一轮 HTTP + SSE 请求

#### 4.1.8 错误处理

| HTTP 状态码 | 含义 | Vox 处理方式 |
|------------|------|----------------------|
| 401 | 认证失败 | 结束通话或播放兜底文案 |
| 400 | 请求参数错误 | 记录协议错误并结束通话 |
| 429 | 限流 | 记录并播放兜底文案 |
| 500 | 第三方内部错误 | 记录并播放兜底文案 |

**SSE 中断处理**:
- 首包前中断:视为本轮失败
- 中途文本流中断且未收到 `[DONE]`:只播放已切出的内容,结束当前轮

#### 4.1.9 特殊说明

1. **打断语义**:第三方无需提供 cancel API,Vox 通过关闭当前 SSE 连接完成打断
3. **会话管理**:Vox 不维护电话级长连接,每轮对话独立发起 HTTP 请求
4. **文本切句**:Vox 负责对接收到的文本流进行切句和 TTS 播放

## 5、附录

### 5.1通用状态码

| http状态码 | 含义                       | 备注                             |
| ---------- | -------------------------- | -------------------------------- |
| 401        | 未知用户,身份认证未通过   | 需联系泰迪熊配置开放平台用户信息 |
| 403        | 无接口访问权限,鉴权未通过 | 需联系泰迪熊开通接口权限         |