Skip to content

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-voip plugin (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:

#ModulePurpose
1WeChat loginwx.login → business server exchanges for openid
2VoIP authorizationSN Ticket → wx.requestDeviceVoIP → report authorization
3Authorization status checkwx.getDeviceVoIPList to check if device is authorized
4Call devicewmpf-voip plugin callDevice → enter call page
5Cancel callonVoipEvent('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.

js
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 openid

The 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:

js
const { data } = await request({
  url: `${server}/v1/voip/user/sn-ticket`,
  method: 'POST',
  data: { device_id: 'TIRZ00000001' }
})
// data.sn_ticket

The server internally calls WeChat getsnticket.

3.2 Call WeChat Authorization

js
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:

js
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

js
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:

json
{
  "plugins": {
    "wmpf-voip": {
      "version": "latest",
      "provider": "wx069abb402f7b1df9"
    }
  }
}

4.1 Place a Call

js
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 })
ParameterNotes
snDevice SN, same as device ID
modelIdModelID from WeChat IoT console
roomType"voice" or "video"
isCloudMust be true — cloud proxy mode
payloadCustom 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:

js
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:

js
// 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/cancel

VIII. Implementation Notes

PointDetail
isCloud must be trueWeChat VoIP requires cloud proxy mode
modelId must match IoT consoleMismatch causes requestDeviceVoIP error
SN Ticket issued by serverDo not call WeChat getsnticket directly from the client
cancelVoip fires only before answerPost-answer hangup is handled internally by the plugin
Payload is passthroughCustom fields pass through WeChat → server → device transparently; consider wxa_from and call_id
wx_app_id is optionalAll 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

WeChat VoIP calling