一、那通电话响了,证据却没了
凌晨 1:40,便利店老板阿凯的手机响了------自建值班系统外呼提示「门口发生告警」。他从床上弹起来,让妻子马上报警,自己冲下楼。门没坏,货架却空了一角;更糟的是,店里那台摄像头的本地卡被人抽走了,App 里也翻不到当晚片段。
电话叫醒了人,却叫醒不了证据。
家庭店铺、社区值班、连锁夜班最怕的不是「没镜头」,而是链路断成两截:能打进电话的系统,未必留得住云录像;能存云录像的系统,未必能在重大事件时把人叫醒。 本文把「云存储留证 + 消息回调编排外呼」串成一条重大事件触达链路:讲清各能力怎么分工,再给可运行的开通、回调、外呼与取证代码,最后补上生产环境注意点。
二、为什么「只开电话」或「只开云存」都不够?
2.1 重大事件的真实 SLA:叫醒 + 留证 + 可复盘
安防类业务里,所谓「重大事件」通常不是「动了一次树影」,而是这几类(字段名以平台事件定义为准):
| msgType | 含义 | 为什么算重大 |
|---|---|---|
human / hoveringAlarm |
人形 / 徘徊 | 有人、在踩点或滞留 |
videoBlind |
视频遮挡 | 镜头被挡、喷漆、贴纸 |
offline(需订阅 deviceStatus) |
设备离线 | 可能剪线、断电、卡被拔 |
gasAlarm / urgencyAlarm 等 |
燃气 / 紧急按钮 | 人身财产高风险 |
对这类事件,业务方真正买的不是「又一个推送红点」,而是三条 SLA:
- 叫醒:人必须在几分钟内感知(电话 > 短信 > App);
- 留证:设备离线或本地卡丢失后,仍能回看关键片段;
- 可复盘:值班、客服、运营能按设备+时间把「谁被叫了、当时有没有片」串起来。
2.2 能力怎么分工:云存、回调、外呼、资源提醒各管一段
重大事件链路里,几块能力建议这样配合(控制台「电话提醒」在本文中按资源类提醒使用,例如额度、套餐、资源状态相关触达):
| 能力 | 在链路中的角色 |
|---|---|
| 视频云存储 | openCloudRecord 开通后,事件/连续录像落在云端,负责留证与事后回看 |
| 消息回调 | setMessageCallback 把 alarm / deviceStatus POST 到你的 HTTPS,告警进入业务系统 |
| 值班外呼/短信 | 在回调编排里按白名单调用语音或短信通道,完成高优先级叫醒 |
| 控制台电话提醒 | 资源类提醒(额度/套餐/资源状态等),与设备告警值班编排分开配置即可 |
推荐组合:
text
重大事件 = 回调编排叫醒 + 云存储留证 + 工单可复盘
(资源类电话提醒按需开通,服务运维侧资源感知)
2.3 推荐架构:云存 + 回调外呼并轨
text
┌──────────────┐ 告警事件 ┌────────────────────┐
│ 摄像机/NVR │ ───────────────► │ 开放平台云端 │
└──────────────┘ │ ├─ 事件云存储写入 │
│ └─ 消息回调推送 │
└─────────┬──────────┘
│ setMessageCallback
▼
┌────────────────────┐
│ 你的桥接服务 │
│ ├─ 白名单/冷却/幂等 │
│ ├─ 查询云片段取证 │
│ └─ 调语音/短信外呼 │
└─────────┬──────────┘
│
┌────────────────────────┼────────────────┐
▼ ▼ ▼
「人被叫醒」 「云端有片」 「流水可复盘」
值班外呼/短信 云存储套餐生效 工单/值班台
- 视频云存储:把套餐开到通道上,事件发生时云端落片,设备离线仍可回放------解决「有没有片」。
- 消息回调 :订阅
alarm/deviceStatus,把设备事件拉进你的编排层------解决「事件进不进系统」。 - 值班外呼 :桥接在判定重大
msgType后拨号/发短信;联系人、频次、话术由业务侧配置------解决「人醒不醒得了」。 - 资源类电话提醒:需要关注额度或套餐状态时,在控制台按资源提醒开通,和告警值班流并行、互不干扰。
下面进入从开通云存、登记回调,到桥接里外呼与取证的完整实操。
三、从开通到「外呼响了且云端有片」
3.0 准备清单(10 分钟)
- 注册视频开放平台开发者账号,创建应用,拿到
appId/appSecret。 - 设备绑定到该应用资产下,确认在线。
- 在资源中心确认账号下有可用的云存储额度 ;如需关注额度/套餐状态,可按需开通控制台资源类电话提醒。
- 准备一台公网可达的 HTTPS 服务(联调可用隧道,生产用正式域名证书),以及一套可用的语音/短信外呼凭证(用于告警值班叫醒)。
- 请求走现行 OpenAPI:
POST {OPENAPI_BASE}/{method},请求体含system+params+id(签名为time + nonce + appSecret的 MD5)。
环境变量示例:
bash
# .env
APP_ID=lcdxxxxxxxxx
APP_SECRET=your_app_secret
OPENAPI_BASE=https://openapi.example.com/openapi # 以你平台文档域名为准
DEVICE_ID=TESTQWERXXXX
CHANNEL_ID=0
STRATEGY_ID=10003 # 云存储套餐 strategyId,以控制台/套餐表为准
CALLBACK_URL=https://bridge.example.com/v1/callback
# 告警值班叫醒:语音/短信外呼通道(示意)
VOICE_API_URL=https://voice.example.com/call
VOICE_API_KEY=your_voice_key
DUTY_PHONES=13800000001,13800000002
3.1 签名与最小 OpenAPI 客户端(先贴代码)
javascript
// openapi-client.js
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');
function calcSign(time, nonce, appSecret) {
// 约定:time:{time},nonce:{nonce},appSecret:{appSecret} → MD5 小写 32 位
const raw = `time:${time},nonce:${nonce},appSecret:${appSecret}`;
return crypto.createHash('md5').update(raw, 'utf8').digest('hex');
}
async function callOpenApi(method, appId, appSecret, params = {}, baseUrl) {
const time = Math.floor(Date.now() / 1000);
const nonce = uuidv4();
const body = {
system: {
ver: '1.0',
appId,
time,
nonce,
sign: calcSign(time, nonce, appSecret),
},
id: uuidv4(),
params,
};
const res = await fetch(`${baseUrl}/${method}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const json = await res.json();
if (!json.result || json.result.code !== '0') {
const msg = json.result
? `${json.result.code} ${json.result.msg}`
: JSON.stringify(json);
throw new Error(`OpenAPI ${method} failed: ${msg}`);
}
return json.result.data;
}
module.exports = { callOpenApi, calcSign };
签名自测(与常见文档标准案例对齐):
javascript
// sign-selftest.js
const assert = require('assert');
const { calcSign } = require('./openapi-client');
assert.strictEqual(
calcSign(
1706511734,
'f5a1ae2d-c09c-4d39-a744-83a5c2c653c2',
'test123456789test123456789'
),
'fd37b62889e4757c58b8f3bf05fb9976'
);
console.log('sign ok');
踩坑 1 :time 与服务器误差超过约 5 分钟、或 nonce 在短窗口内重复,会直接签名/防重失败------联调先跑自测,再查业务参数。
3.2 拿 accessToken(别每次业务都刷)
javascript
// get-token.js
require('dotenv').config();
const { callOpenApi } = require('./openapi-client');
(async () => {
const data = await callOpenApi(
'accessToken',
process.env.APP_ID,
process.env.APP_SECRET,
{},
process.env.OPENAPI_BASE
);
console.log('accessToken:', data.accessToken);
console.log('expireTime(s):', data.expireTime);
})();
Token 一般有效约 3 天;业务侧做缓存,遇到过期错误码再刷新。每次告警都重新 accessToken,只会白白消耗配额。
3.3 开通云存储:先查额度,再开到通道
重大事件留证,优先选事件云存储 (告警触发落片,成本更可控);若合规要求「全时段可回看」,再上连续云存储,并用 rules 控制录像时段(仅连续套餐生效)。
javascript
// open-cloud.js
require('dotenv').config();
const { callOpenApi } = require('./openapi-client');
async function main() {
const appId = process.env.APP_ID;
const appSecret = process.env.APP_SECRET;
const base = process.env.OPENAPI_BASE;
const strategyId = process.env.STRATEGY_ID; // 如 10003,以套餐表为准
const deviceId = process.env.DEVICE_ID;
const channelId = process.env.CHANNEL_ID || '0';
const token = (await callOpenApi('accessToken', appId, appSecret, {}, base))
.accessToken;
// 1) 查该套餐剩余可开通次数
const quota = await callOpenApi(
'queryCloudRecordCallNum',
appId,
appSecret,
{ token, strategyId: Number(strategyId) },
base
);
console.log('剩余可开通次数 callNum =', quota.callNum);
if (!quota.callNum || quota.callNum <= 0) {
throw new Error('云存储额度不足:请先在控制台购买/领取套餐额度');
}
// 2) 开通到指定通道(场景1:消耗账号未使用额度;库存复用见 deviceCloudId)
await callOpenApi(
'openCloudRecord',
appId,
appSecret,
{
token,
deviceId,
channelId,
strategyId: String(strategyId),
// activateNow: true, // 已有套餐使用中时,是否立即切到新套餐
},
base
);
// 3) 回查通道套餐状态
const list = await callOpenApi(
'deviceCloudList',
appId,
appSecret,
{ token, deviceId, channelId },
base
);
console.log('通道云存储列表:', JSON.stringify(list, null, 2));
const current = await callOpenApi(
'getDeviceCloud',
appId,
appSecret,
{ token, deviceId, channelId },
base
);
console.log('当前生效套餐:', current);
// strategyStatus: -1 未开通 / 0 过期 / 1 使用中 / 2 暂停
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
踩坑 2 :额度在账号上 ≠ 设备已生效。很多人只买了套餐,没调 openCloudRecord,结果外呼叫醒了人、云端仍无片。务必用 deviceCloudList / getDeviceCloud 确认 cloudStatus=1(使用中)或 strategyStatus=1。
踩坑 3 :同一通道可排队多个套餐;默认新套餐进队列,不一定立刻顶替旧套餐。需要立刻按新规格落片时,显式传 activateNow: true。
3.4 设备告警叫醒:回调白名单 + 值班外呼编排
告警值班叫醒建议落在桥接服务里:先收齐事件,再按策略外呼。控制台「电话提醒」按资源类提醒理解与开通即可,和本节的告警值班流分开看。
text
setMessageCallback(alarm,deviceStatus)
→ 桥接服务白名单 / 冷却 / 幂等
→ 异步:语音/短信外呼 + 云片段取证
推荐策略(写在桥接配置里):
| 层级 | 建议触发外呼的类型 | 建议降噪 |
|---|---|---|
| P0 重大 | human、hoveringAlarm、videoBlind、紧急/燃气类 |
--- |
| P1 关注 | 夜间时段的 videoMotion(业务侧按小时窗过滤) |
白天全量动检可只记日志 |
| P2 运维 | offline(电话或短信二选一) |
频繁上下线抖动做冷却 |
配置原则:
- 白名单告警类型:宁缺毋滥,减少无效叫醒。
- 多联系人分级:店主 + 值班 + 物业,维护在业务通讯录。
- 频次控制:同一设备同类告警冷却(如 5~15 分钟);外呼通道自身的频控一并打开。
- 先云存、再外呼:外呼模板可当天调通,云存套餐生效后再做完整验收------留证与叫醒两项都勾。
- 资源类电话提醒:需要感知额度/套餐状态时单独开通,与告警值班编排并行即可。
3.5 用回调把「叫醒」和「留证」写进同一条流水
桥接服务同时做两件事:快速回 200 ;异步完成 值班外呼 + 云片段取证,供值班台一键回放。
先登记回调:
javascript
// set-callback.js
require('dotenv').config();
const { callOpenApi } = require('./openapi-client');
(async () => {
const appId = process.env.APP_ID;
const appSecret = process.env.APP_SECRET;
const base = process.env.OPENAPI_BASE;
const token = (await callOpenApi('accessToken', appId, appSecret, {}, base))
.accessToken;
await callOpenApi(
'setMessageCallback',
appId,
appSecret,
{
token,
status: 'on',
callbackUrl: process.env.CALLBACK_URL,
callbackFlag: 'alarm,deviceStatus',
basePush: '2', // 联调期建议先不干扰终端 App 推送策略排查
},
base
);
const current = await callOpenApi(
'getMessageCallback',
appId,
appSecret,
{ token },
base
);
console.log('当前回调配置:', current);
})();
告警推送体(普通报警)关键字段:
json
{
"id": 2447736561,
"appId": "lcdxxxxxxxxx",
"did": "TESTQWERXXXX",
"cid": 0,
"msgType": "human",
"time": 1475052555,
"cname": "门口枪机",
"remark": "",
"token": "f2dc8c09eeae4b5bad6abf522c93d825",
"desc": {}
}
说明:token(云录像 token)并非所有机型都会带 ------文档约定常见为特定平台类型设备在告警推送中携带;没有 token 时,用时间窗查 getCloudRecords 兜底。
桥接服务完整示例:
javascript
// bridge-server.js
require('dotenv').config();
const express = require('express');
const { callOpenApi } = require('./openapi-client');
const app = express();
app.use(express.json({ limit: '1mb' }));
const MAJOR = new Set([
'human',
'hoveringAlarm',
'videoBlind',
'gasAlarm',
'urgencyAlarm',
'offline',
]);
// 简易冷却:同一 did+msgType 10 分钟内只落一条「重大流水」
const coolDownMs = 10 * 60 * 1000;
const lastHit = new Map();
function formatLocal(tsSec) {
const d = new Date(tsSec * 1000);
const pad = (n) => String(n).padStart(2, '0');
return (
`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +
`${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
);
}
async function getAdminToken() {
const data = await callOpenApi(
'accessToken',
process.env.APP_ID,
process.env.APP_SECRET,
{},
process.env.OPENAPI_BASE
);
return data.accessToken;
}
async function fetchEvidence(did, cid, alarmTime, cloudToken) {
const adminToken = await getAdminToken();
const base = process.env.OPENAPI_BASE;
const appId = process.env.APP_ID;
const appSecret = process.env.APP_SECRET;
// 路径 A:推送带 cloudToken → queryCloudRecordByToken
if (cloudToken) {
try {
const byToken = await callOpenApi(
'queryCloudRecordByToken',
appId,
appSecret,
{
token: adminToken,
deviceId: did,
cloudToken,
},
base
);
return { mode: 'byToken', record: byToken };
} catch (e) {
console.warn('queryCloudRecordByToken 失败,降级时间窗查询:', e.message);
}
}
// 路径 B:告警时刻前后各扩 2 分钟,倒序取最近片段
const begin = formatLocal(alarmTime - 120);
const end = formatLocal(alarmTime + 120);
const data = await callOpenApi(
'getCloudRecords',
appId,
appSecret,
{
token: adminToken,
deviceId: did,
channelId: String(cid),
beginTime: begin,
endTime: end,
count: 5,
},
base
);
return { mode: 'byTimeWindow', records: data?.records || [] };
}
app.post('/v1/callback', async (req, res) => {
// 关键:先回 200,再异步处理;多次无响应会被停推
res.status(200).json({ ok: true });
const body = req.body || {};
const did = body.did || body.deviceId || body.msgDeviceId;
const cid = body.cid != null ? body.cid : body.channelId;
const msgType = body.msgType;
const alarmTime = Number(body.time) || Math.floor(Date.now() / 1000);
const cloudToken = body.token; // 注意与 accessToken 字段同名不同义
if (!MAJOR.has(msgType)) {
console.log('[skip non-major]', msgType, did);
return;
}
const key = `${did}:${msgType}`;
const now = Date.now();
if (lastHit.has(key) && now - lastHit.get(key) < coolDownMs) {
console.log('[cooldown]', key);
return;
}
lastHit.set(key, now);
setImmediate(async () => {
try {
const evidence = await fetchEvidence(did, cid, alarmTime, cloudToken);
// 告警值班叫醒:桥接侧调语音/短信通道;资源类电话提醒在控制台单独配置
const phones = (process.env.DUTY_PHONES || '')
.split(',')
.map((s) => s.trim())
.filter(Boolean);
const callResult = await placeDutyCall({
phones,
did,
msgType,
cname: body.cname,
});
// 写入工单/值班台:叫醒结果 + 片段元数据同一条流水
console.log(
JSON.stringify(
{
event: 'MAJOR_EVENT',
did,
cid,
msgType,
alarmTime,
phoneAlert: callResult,
evidence,
},
null,
2
)
);
} catch (e) {
console.error('evidence/call pipeline failed:', e.message);
}
});
});
/** 示意:替换为你方云呼叫 / 短信网关 SDK */
async function placeDutyCall({ phones, did, msgType, cname }) {
if (!phones.length) return { skipped: true, reason: 'no duty phones' };
const text = `重大告警 ${msgType},设备 ${cname || did},请立即查看云端录像。`;
// 真实项目里:失败重试、主备号轮询、接通状态回写工单
const res = await fetch(process.env.VOICE_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.VOICE_API_KEY}`,
},
body: JSON.stringify({ phones, text, bizId: `${did}:${msgType}:${Date.now()}` }),
});
if (!res.ok) throw new Error(`voice call failed: ${res.status}`);
return res.json();
}
app.listen(process.env.PORT || 3000, () => {
console.log('bridge listening');
});
主流程可以画成这样:
3.6 联调验收清单(建议按顺序勾)
text
[ ] 签名自测通过
[ ] accessToken 可获取且已缓存
[ ] queryCloudRecordCallNum.callNum > 0
[ ] openCloudRecord 成功,getDeviceCloud.strategyStatus == 1
[ ] setMessageCallback + getMessageCallback 地址一致,外网可访问
[ ] 桥接侧 DUTY_PHONES / 语音或短信通道联调通过
[ ] 人为触发人形/遮挡(或离线)后:回调入日志 + 外呼接通
[ ] 同窗口 getCloudRecords 能查到 type=1000(事件云录像)或对应片段
[ ] 拔掉本地卡 / 模拟设备离线后,云端片段仍可查(留证闭环)
[ ] (可选)控制台资源类电话提醒:额度/套餐状态触达单独验收
踩坑 4 :回调地址写成 http://127.0.0.1 或内网 IP------平台推送达不到,桥接与外呼都不会被触发。
踩坑 5 :回调里同步调一长串 OpenAPI 再外呼再返回------超时多了可能影响推送稳定性。必须「先 200,再异步」。
踩坑 6 :把推送体里的 token(cloudToken)当成 accessToken 去调业务接口------字段同名不同义,会直接鉴权失败。
踩坑 7:验收时把「资源类电话提醒」和「告警值班外呼」混在同一条用例里------建议分两条用例,结论更清晰。
3.7 最小「重大事件」验收脚本(可定时跑)
javascript
// smoke-major-event.js
require('dotenv').config();
const { callOpenApi } = require('./openapi-client');
async function main() {
const appId = process.env.APP_ID;
const appSecret = process.env.APP_SECRET;
const base = process.env.OPENAPI_BASE;
const deviceId = process.env.DEVICE_ID;
const channelId = process.env.CHANNEL_ID || '0';
const token = (await callOpenApi('accessToken', appId, appSecret, {}, base))
.accessToken;
const cloud = await callOpenApi(
'getDeviceCloud',
appId,
appSecret,
{ token, deviceId, channelId },
base
);
const end = new Date();
const begin = new Date(end.getTime() - 24 * 3600 * 1000);
const fmt = (d) => {
const p = (n) => String(n).padStart(2, '0');
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(
d.getHours()
)}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
};
const records = await callOpenApi(
'getCloudRecords',
appId,
appSecret,
{
token,
deviceId,
channelId,
beginTime: fmt(begin),
endTime: fmt(end),
count: 10,
},
base
);
console.log('云存储生效信息:', cloud);
console.log(
'近24h云片段数:',
(records && records.records && records.records.length) || 0
);
console.log(
'提示: 告警值班外呼请查桥接日志/语音通道明细;本脚本验证留证侧就绪。资源类电话提醒可在控制台按需验收。'
);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
四、边界、性能与生产注意事项
4.1 能力边界:资源提醒与告警值班编排分开配置
| 通道 | 触发源 | 典型用途 |
|---|---|---|
| 控制台电话提醒 | 额度、套餐、资源状态等(资源类提醒) | 运维侧资源感知 |
| 回调 + 值班外呼 | 设备 alarm / deviceStatus |
重大事件叫醒与工单编排 |
| App 推送 | 终端 App | 日常辅助感知 |
值班外呼适合「重大事件叫醒」:频次、号段、主备联系人放在业务配置中心;资源类电话提醒按控制台说明开通,两者并行、验收用例分开即可。
4.2 误报与额度:两道闸门都要有
| 风险 | 表现 | 对策 |
|---|---|---|
| 动检刷屏 | 一夜上百通无效外呼 | 外呼只放行 P0 类型;桥接冷却;通道频控 |
| 云存空转 | 开了连续套餐却只关心事件 | 重大场景优先事件云存储;连续套餐用 rules 限时段 |
| 取证延迟 | 告警瞬间片段尚未索引完 | queryCloudRecordByToken 失败后延迟 3~10 秒再 getCloudRecords |
| 回调不稳定 | 服务宕机未回 200 | 健康检查;恢复后重新确认 setMessageCallback |
| 多租户串单 | 一个 callbackUrl 服务多家 | 自建 deviceId → tenant 路由(托管 state 很有用) |
4.3 性能与可靠性建议
- 回调路径:解析 JSON → 入队(Redis/SQS)→ 立刻 200;取证、外呼、写库全部异步。
- Token 缓存 :进程内或 Redis 缓存
accessToken,剩余寿命小于 1 小时再续。 - 幂等 :以推送
id(告警消息 id)做唯一键,避免平台重推导致重复外呼/工单。 - 证据生命周期:推送里的抓图 URL 往往短时有效,重大事件应尽快转存到自己的对象存储。
- 安全:回调接口校验来源(IP 允许列表 / 签名校验若平台提供)、HTTPS 强制、密钥不进仓库。
4.4 上线前「破坏性」自测(强烈建议)
- 拔本地存储卡后触发人形:桥接应外呼,云片段仍应能查。
- 临时断电摄像头:应收到
offline(若已订阅),外呼策略按 P0/P1 设定验证。 - 用纸遮挡镜头:验证
videoBlind是否进入外呼白名单。 - 连续挥手制造动检:验证冷却与频次是否生效。
- (可选)额度/套餐状态变化时,确认资源类电话提醒触达正常。
五、总结与延伸
重大事件触达不是「多接一个推送」,而是一条完整闭环:
- 云存储负责留证------人走了、卡没了、设备挂了,关键片段还在不在;
- 消息回调 + 值班外呼负责叫醒------事件进系统、人被及时触达;
- 取证查询负责复盘------叫醒之后,值班台能否一键打开那几秒画面;
- 控制台电话提醒 按资源类提醒按需使用------服务额度/套餐等运维感知。
留证、叫醒、复盘三者齐套,夜班才站得住;资源提醒与告警值班流分开配置,联调也更省事。
延伸阅读(对照你所用平台的现行文档目录即可,勿翻「旧版本协议」):
- 消息回调:
setMessageCallback/getMessageCallback、事件消息类型与格式定义 - 云存储开通与查询:
queryCloudRecordCallNum、openCloudRecord、deviceCloudList、getDeviceCloud - 云录像取证:
queryCloudRecordByToken、getCloudRecords/queryCloudRecords - 设备能力开关(减少误报):PaaS 设备优先
setDeviceCameraStatus(如motionDetect/aiHuman等,以能力集为准) - 控制台「电话提醒」:按资源类提醒说明开通与验收
如果你正在做家庭店铺防盗、社区值班或连锁夜班巡检,建议先打通「云存额度 → 开通云存 → 回调登记 → 值班外呼白名单 → 取证流水」最小闭环,再谈多租户分流和工单系统。选型时重点确认:视频云存储、告警消息回调、云片段查询可用,并备好稳定的语音/短信通道;资源类电话提醒可按运维需要叠加。
附:本文涉及的现行接口速查
| 步骤 | 方法名 | 作用 |
|---|---|---|
| 鉴权 | accessToken |
获取管理员 token |
| 额度 | queryCloudRecordCallNum |
查套餐剩余开通次数 |
| 开通 | openCloudRecord |
给通道开通云存储 |
| 回查 | deviceCloudList / getDeviceCloud |
确认套餐生效 |
| 回调 | setMessageCallback / getMessageCallback |
登记/查询消息推送地址 |
| 取证 | queryCloudRecordByToken / getCloudRecords |
按 token 或时间窗查云片段 |
| 叫醒 | (业务侧)语音/短信 API | 在回调异步链路中外呼值班号 |