短信网关开放接口
生产可用企业服务器可通过已授权设备和 SIM 卡发送短信,也可以分页获取设备、全部短信、未读短信和已读短信。每个 AppKey 的未读状态相互独立,不影响企业后台。
快速接入
文档更新:2026-09-15通用返回格式
所有接口均返回JSON。HTTP状态码表示请求是否成功,响应体中的code、msg和data用于程序处理。
成功响应
{
"code": 0,
"msg": "OK",
"data": {}
}失败响应
{
"code": 400,
"msg": "invalid_request",
"data": []
}| 字段 | 类型 | 说明 |
|---|---|---|
| code | integer | 0表示成功;失败时通常与HTTP状态码一致 |
| msg | string | 成功时为OK或accepted;失败时为可供程序判断的错误码 |
| data | object / array | 成功时包含业务数据;失败时为空数组 |
Token 鉴权
POST{
"app_key": "sg_xxxxxxxxxxxxxxxxxxxxxxxx",
"app_secret": "BASE64_APP_SECRET",
"grant_type": "client_credentials"
}成功响应 · HTTP 200
{
"code": 0,
"msg": "OK",
"data": {
"access_token": "OPAQUE_ACCESS_TOKEN",
"token_type": "Bearer",
"expires_in": 7200,
"expires_at": "2026-09-15T12:00:00Z",
"app_key": "sg_xxxxxxxxxxxxxxxxxxxxxxxx",
"scope": "devices:read sms:send sms:read"
}
}| 返回字段 | 类型 | 说明 |
|---|---|---|
| data.access_token | string | 短期访问Token;不得记录到普通日志 |
| data.token_type | string | 固定为Bearer |
| data.expires_in | integer | 剩余有效秒数,固定7200 |
| data.expires_at | string | UTC时区的Token失效时间 |
| data.app_key | string | 本Token所属AppKey |
| data.scope | string | 空格分隔的已授权接口权限 |
后续业务请求头
X-Access-Token: OPAQUE_ACCESS_TOKEN
X-App-Key: sg_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json接口一览
/openapi/v1/health
无副作用验证Token、企业权限和短信运行状态。
/openapi/v1/messages
指定企业短信棒创建任务,平台自动选择该棒当前可发送的SIM。
/openapi/v1/devices
分页获取企业可公开设备及脱敏SIM状态。
/openapi/v1/messages
分页获取全部、未读或已读短信。
/openapi/v1/messages/{id}
获取单条入站或出站短信详情。
/openapi/v1/messages/read
把当前AppKey的入站已读水位推进到指定消息。
检查服务状态
GET无副作用检查Token、企业权限和短信下行能力。只有HTTP 200且data.status为ready时,才表示当前应用可以提交短信。
成功响应 · HTTP 200
{
"code": 0,
"msg": "OK",
"data": {
"api_version": "v1",
"product": "simgateway_sms",
"status": "ready",
"scope": "sms:send",
"checked_at": "2026-09-15T10:00:00Z"
}
}| 返回字段 | 类型 | 说明 |
|---|---|---|
| data.api_version | string | 当前开放接口版本 |
| data.product | string | 当前检查的产品标识 |
| data.status | string | ready表示可以提交短信任务 |
| data.scope | string | 本接口验证的权限,固定为sms:send |
| data.checked_at | string | UTC时区的检查时间 |
发送短信
POST| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| device_code | string | 是 | 当前企业有效短信棒设备码 |
| recipient | string | 是 | 短信接收号码 |
| content | string | 是 | 平台不限制短信字符数,支持长短信;长内容由短信棒和运营商处理,暂不支持Emoji等特殊字符 |
| client_message_id | string | 否 | 安全重试时建议传8~128字符稳定编号;省略则平台生成 |
| sim_slot | integer | 否 | 旧调用方兼容字段;通常省略,由平台自动选择 |
{
"device_code": "SG-DEMO-0001",
"recipient": "19900000002",
"content": "接口联调测试"
}首次接受响应 · HTTP 202
{
"code": 0,
"msg": "accepted",
"data": {
"message_id": "sms_123",
"client_message_id": "auto_0123456789abcdef0123456789abcdef",
"status": "queued",
"device_code": "SG-DEMO-0001",
"sim_slot": 0,
"idempotent": false,
"created_at": "2026-09-15 18:30:00"
}
}| 返回字段 | 类型 | 说明 |
|---|---|---|
| data.message_id | string | 平台短信任务ID,用于查询发送结果 |
| data.client_message_id | string | 调用方传入的幂等编号;省略时返回平台生成的编号 |
| data.status | string | 当前任务状态;刚接受时通常为queued |
| data.device_code | string | 实际使用的短信棒设备码 |
| data.sim_slot | integer | 平台在该短信棒上实际选择的SIM卡槽 |
| data.idempotent | boolean | false为首次创建;true为返回既有幂等任务 |
| data.created_at | string | 任务创建时间,格式YYYY-MM-DD HH:mm:ss |
获取设备
GET| 参数 | 默认 | 说明 |
|---|---|---|
| limit | 50 | 每页1~100条 |
| cursor | 空 | 上页返回的不透明 next_cursor |
| device_code | 空 | 按当前企业设备码精确筛选 |
成功响应 · HTTP 200
{
"code": 0,
"msg": "OK",
"data": {
"items": [{
"device_code": "SG-DEMO-0001",
"name": "办公室短信棒",
"online": true,
"last_seen_at": "2026-09-15 18:29:50",
"sip_online": true,
"sim_ready": true,
"call_active": false,
"sims": [{
"sim_slot": 0,
"phone_masked": "*******0001",
"carrier": "中国移动",
"status": "ready",
"sms_ready": true,
"updated_at": "2026-09-15 18:29:50"
}]
}],
"next_cursor": null,
"has_more": false,
"limit": 50
}
}| 返回字段 | 类型 | 说明 |
|---|---|---|
| data.items | array | 当前页短信棒数组 |
| data.next_cursor | string / null | 下一页游标;无下一页时为null |
| data.has_more | boolean | 是否还有下一页 |
| data.limit | integer | 本次请求采用的每页数量 |
| data.items[].device_code | string | 企业可用于调用接口的短信棒设备码 |
| data.items[].name | string | 短信棒名称 |
| data.items[].online | boolean | 最近5分钟内是否有有效心跳 |
| data.items[].last_seen_at | string / null | 最近一次心跳时间 |
| data.items[].sip_online | boolean | SIP是否在线 |
| data.items[].sim_ready | boolean | 设备心跳报告的SIM是否就绪 |
| data.items[].call_active | boolean | 当前是否存在活动通话 |
| data.items[].sims | array | 该短信棒的脱敏SIM状态数组 |
| data.items[].sims[].sim_slot | integer | SIM卡槽编号 |
| data.items[].sims[].phone_masked | string | 只保留末4位的脱敏SIM号码 |
| data.items[].sims[].carrier | string | 运营商名称 |
| data.items[].sims[].status | string | SIM当前状态,例如ready或absent |
| data.items[].sims[].sms_ready | boolean | 该SIM当前是否支持并允许发送短信 |
| data.items[].sims[].updated_at | string | SIM状态更新时间 |
获取全部、未读或已读短信
GET| 参数 | 默认 | 说明 |
|---|---|---|
| read_status | all | all、unread或read;未读/已读只适用于入站短信 |
| direction | 空 | in或out;out不能与unread/read组合 |
| status | 空 | received、sent、delivered、failed等状态 |
| device_code | 空 | 按企业设备筛选 |
| limit | 50 | 每页1~100条 |
| cursor | 空 | 保持其他筛选不变后获取下一页 |
成功响应 · HTTP 200
{
"code": 0,
"msg": "OK",
"data": {
"items": [{
"message_id": "msg_456",
"direction": "in",
"status": "received",
"read_status": "unread",
"device_code": "SG-DEMO-0001",
"sim_slot": 0,
"from": "19900000002",
"to": "19900000001",
"content": "收到,谢谢",
"created_at": "2026-09-15 18:35:00",
"sent_at": null,
"received_at": "2026-09-15 18:35:00",
"error_code": ""
}],
"next_cursor": null,
"has_more": false,
"limit": 50,
"read_status": "all",
"unread_count": 1,
"read_through_message_id": null
}
}| 返回字段 | 类型 | 说明 |
|---|---|---|
| data.items | array | 当前页短信对象数组 |
| data.next_cursor | string / null | 下一页游标;无下一页时为null |
| data.has_more | boolean | 是否还有下一页 |
| data.limit | integer | 本次请求采用的每页数量 |
| data.read_status | string | 本次查询采用的已读筛选:all、unread或read |
| data.unread_count | integer | 当前筛选设备和状态范围内的入站未读总数 |
| data.read_through_message_id | string / null | 当前AppKey已确认处理到的最后一条入站短信 |
短信对象字段
| 返回字段 | 类型 | 说明 |
|---|---|---|
| message_id | string | 短信公开ID;出站为sms_前缀,入站为msg_前缀 |
| direction | string | in为接收短信,out为发送短信 |
| status | string | 短信状态,例如received、queued、sent、delivered或failed |
| read_status | string | 入站为read/unread;出站固定为not_applicable |
| device_code | string | 关联的短信棒设备码 |
| sim_slot | integer | 实际使用或接收短信的SIM卡槽 |
| from | string | 短信发送方号码 |
| to | string | 短信接收方号码 |
| content | string | 短信正文 |
| created_at | string | 平台记录创建时间 |
| sent_at | string / null | 发送时间;未发送或入站短信可能为null |
| received_at | string / null | 接收时间;出站短信通常为null |
| error_code | string | 失败原因代码;无错误时为空字符串 |
获取短信详情
GET把列表或发送接口返回的message_id放入路径。出站短信ID以sms_开头,入站短信ID以msg_开头。
成功响应 · HTTP 200
{
"code": 0,
"msg": "OK",
"data": {
"message": {
"message_id": "sms_123",
"direction": "out",
"status": "sent",
"read_status": "not_applicable",
"device_code": "SG-DEMO-0001",
"sim_slot": 0,
"from": "19900000001",
"to": "19900000002",
"content": "接口联调测试",
"created_at": "2026-09-15 18:30:00",
"sent_at": "2026-09-15 18:30:08",
"received_at": null,
"error_code": ""
}
}
}| 返回字段 | 类型 | 说明 |
|---|---|---|
| data.message | object | 单条短信对象,内部字段与上方短信对象字段表一致 |
确认入站短信已读
POST{
"through_message_id": "msg_456"
}成功响应 · HTTP 200
{
"code": 0,
"msg": "OK",
"data": {
"through_message_id": "msg_456",
"read_at": "2026-09-15 18:40:00",
"idempotent": false
}
}| 返回字段 | 类型 | 说明 |
|---|---|---|
| data.through_message_id | string | 当前AppKey确认处理到的最后一条入站短信ID |
| data.read_at | string | 已读水位更新时间 |
| data.idempotent | boolean | false表示本次推进水位;true表示此前已经处理到该位置或更后 |
把当前 AppKey 的已读水位推进到指定入站消息,表示该消息及更早入站短信均已处理。重复提交幂等,水位不能回退。
常见错误码
| HTTP | msg | 处理 |
|---|---|---|
| 400 | invalid_request | 检查JSON字段、类型和Content-Type |
| 400 | cursor_invalid | 下一页必须保持原筛选条件,或游标已损坏 |
| 400 | read_status_direction_conflict | 未读/已读筛选只能用于入站短信 |
| 401 | app_credentials_invalid | 检查AppKey/AppSecret并重新获取Token |
| 401 | access_token_invalid | 检查X-Access-Token和X-App-Key |
| 403 | scope_denied / ip_denied | 检查产品权限与调用方出口IP |
| 404 | device_not_found / message_not_found | 检查资源是否属于当前企业 |
| 409 | idempotency_conflict | 同一client_message_id不能提交不同内容 |
| 409 | read_cursor_busy / read_cursor_changed | 稍后使用同一through_message_id幂等重试 |
| 503 | openapi_disabled / token_store_unavailable | 联系平台检查产品开关或Token存储 |