Mini Program Integration
WeChat VoIP calling involves four parties: Mini Program, business server, Tange Cloud platform, and device. The Mini Program handles user login, device VoIP authorization, placing/receiving calls, and call cancellation.
Interface ownership:
- WeChat provides:
wx.login,wx.requestDeviceVoIP,wx.getDeviceVoIPList,wmpf-voipplugin (callDevice,onVoipEvent, etc.)- Business server provides: all
/v1/voip/user/*and/v1/user/*HTTP endpoints — implement per Business Server Integration
Read Call flows and Business Server Integration first. For Mini Program application and setup, see WeChat Mini Program Setup.
I. What to Implement
In development order:
| # | Module | Purpose |
|---|---|---|
| 1 | WeChat login | wx.login → business server exchanges for openid |
| 2 | VoIP authorization | SN Ticket → wx.requestDeviceVoIP → report authorization |
| 3 | Authorization status check | wx.getDeviceVoIPList to check if device is authorized |
| 4 | Call device | wmpf-voip plugin callDevice → enter call page |
| 5 | Cancel call | onVoipEvent('cancelVoip') → notify business server |
II. WeChat Login
Call the business server POST /v1/voip/user/wechat-mini-login. The Mini Program first calls wx.login() to get a temporary code, then sends it to the server to exchange for an openid.
const res = await wx.login()
const { data } = await request({
url: `${server}/v1/voip/user/wechat-mini-login`,
method: 'POST',
data: { code: res.code }
})
// data.wx_user_openid is the current user's openidThe server internally calls WeChat jscode2session. The openid is the user identifier for all subsequent VoIP operations.
III. VoIP Device Authorization
Before using a device for calls, the user must complete WeChat-side authorization.
3.1 Get SN Ticket
Call the business server POST /v1/voip/user/sn-ticket:
const { data } = await request({
url: `${server}/v1/voip/user/sn-ticket`,
method: 'POST',
data: { device_id: 'TIRZ00000001' }
})
// data.sn_ticketThe server internally calls WeChat getsnticket.
3.2 Call WeChat Authorization
wx.requestDeviceVoIP({
sn: deviceId,
snTicket: ticket,
modelId: '<ModelID from WeChat IoT console>',
deviceName: deviceId,
success: () => { /* authorized */ },
fail: (err) => {
// errCode 10001 means already authorized — equivalent to success
if (err.errCode === 10001) { /* already authorized */ }
}
})3.3 Report Authorization to Business Server
After authorization succeeds, call the business server POST /v1/voip/user/report-auth:
await request({
url: `${server}/v1/voip/user/report-auth`,
method: 'POST',
data: {
device_id: deviceId,
wx_open_id: openId,
wx_model_id: modelId
}
})After storing, the server pushes callers_update to the device via the downlink channel.
3.4 Check Authorization Status
wx.getDeviceVoIPList({
success: (res) => {
const authed = (res.list || [])
.filter(i => i.status === 1)
.map(i => i.sn)
// authed contains authorized device SNs
}
})status === 1 means authorized. Typically called on the device list page, cross-referenced with the business server device list.
IV. Calling a Device
Use the official wmpf-voip WeChat plugin. Declare it in app.json:
{
"plugins": {
"wmpf-voip": {
"version": "latest",
"provider": "wx069abb402f7b1df9"
}
}
}4.1 Place a Call
const wmpfVoip = requirePlugin('wmpf-voip').default
const { roomId } = await wmpfVoip.callDevice({
sn: deviceId,
modelId: '<WeChat IoT ModelID>',
roomType: 'voice', // 'voice' or 'video'
nickName: 'User',
isCloud: true, // Must be true
payload: JSON.stringify({ // Custom passthrough data
wxa_from: 'app',
call_id: '<unique call ID>'
})
})
// Save call context for cancellation
this.currentCall = { deviceId, roomId }
// Navigate to the VoIP plugin call page
wx.redirectTo({ url: wmpfVoip.CALL_PAGE_PATH })| Parameter | Notes |
|---|---|
sn | Device SN, same as device ID |
modelId | ModelID from WeChat IoT console |
roomType | "voice" or "video" |
isCloud | Must be true — cloud proxy mode |
payload | Custom JSON string, passed through WeChat → server → device. Consider including wxa_from (caller side) and call_id (unique identifier) |
4.2 Call Page
After callDevice succeeds, navigate to wmpfVoip.CALL_PAGE_PATH. The plugin provides the complete call UI. No custom call page development is needed.
V. Cancel Before Answer
When the Mini Program user cancels before the callee answers. Listen to wmpf-voip plugin events:
const wmpfVoip = requirePlugin('wmpf-voip').default
App({
onLaunch() {
wmpfVoip.onVoipEvent((event) => {
if (event.eventName === 'cancelVoip') {
this._handleCancel(event)
}
})
},
_handleCancel(event) {
if (!this.currentCall) return
const { deviceId, roomId } = this.currentCall
this.currentCall = null
// Call business server POST /v1/voip/user/cancel
wx.request({
url: `${server}/v1/voip/user/cancel`,
method: 'POST',
data: { device_id: deviceId, wx_room_id: roomId }
})
}
})The server then pushes call_cancel to the device via the downlink channel.
VI. Delete Authorization on Unbind
When unbinding a device, also remove the VoIP authorization:
// Call business server DELETE /v1/user/device/reset (unbind device)
await request({
url: `${server}/v1/user/device/reset`,
method: 'DELETE',
data: { device_id: deviceId }
})
// Call business server POST /v1/voip/user/delete-auth (remove VoIP auth)
await request({
url: `${server}/v1/voip/user/delete-auth`,
method: 'POST',
data: {
device_id: deviceId,
wx_open_id: openId
}
})The server automatically pushes callers_update to the device.
VII. Complete Flow
1. User login
wx.login → code → POST /v1/voip/user/wechat-mini-login → openid
2. First-time device use:
a. POST /v1/voip/user/sn-ticket → sn_ticket
b. wx.requestDeviceVoIP({ sn, snTicket, modelId })
c. POST /v1/voip/user/report-auth → report authorization
d. Server pushes callers_update → device
3. Call device:
a. wmpfVoip.callDevice({ sn, modelId, roomType, isCloud: true })
b. Get roomId, save currentCall = { deviceId, roomId }
c. wx.redirectTo({ url: CALL_PAGE_PATH })
4. Cancel (before answer):
wmpfVoip.onVoipEvent('cancelVoip') → POST /v1/voip/user/cancelVIII. Implementation Notes
| Point | Detail |
|---|---|
isCloud must be true | WeChat VoIP requires cloud proxy mode |
modelId must match IoT console | Mismatch causes requestDeviceVoIP error |
| SN Ticket issued by server | Do not call WeChat getsnticket directly from the client |
cancelVoip fires only before answer | Post-answer hangup is handled internally by the plugin |
| Payload is passthrough | Custom fields pass through WeChat → server → device transparently; consider wxa_from and call_id |
wx_app_id is optional | All business server APIs accept an optional wx_app_id; if omitted, the server's default AppID is used. Pass it explicitly for multi-app setups |