Common call failure causes
Device calls Mini Program: business server calls WeChat /wxa/business/iot/voip/call fails
Confirm whether the device has passed WeChat review. If not, you cannot call the release Mini Program; you can call the trial Mini Program.
Reference for error codes: WeChat WeChat VoIP calling plugin error codes.
Use the official documentation as the source of truth; its list may be incomplete.
Below are additional codes we have collected.
Backend-returned error codes
| errCode | Description |
|---|---|
| 1 | Invalid roomId |
| 2 | Invalid device deviceId |
| 3 | Invalid voip_id |
| 4 | Invalid voipToken (face-verify mode) |
| 5 | Failed to create WeChat VoIP calling room |
| 7 | Invalid openId |
| 8 | openId not authorized (face-verify mode) |
| 9 | openId not authorized for the device (hardware mode), or not a userId contact (face-verify mode) |
| 12 | Mini Program RTC capability review not completed; temporarily unavailable in the release build |
| 13 | Hardware calls WeChat: voipToken error |
| 14 | WeChat calls hardware: voipToken error |
| 15 | Unpaid / arrears |
| 17 | voipToken does not match modelId |
| 19 | openId does not match the Mini Program appId (the same user has different openIds across Mini Programs) |
| 20 | Invalid openId |
| 22 | Invalid chargeType |
| 23 | Device license expired |
| 24 | Device license not activated |
| 31 | Device not reviewed; cannot call the release build |
| -202 | Developer server did not respond correctly to the callback |
| 61007 | Mini Program authorization issue in server-side mode |
| 10008 | Usually sn_ticket expired |
Does callback errcode != 0 end the call?
No.
As long as the call-initiation API succeeds and WeChat enters the ringing flow, callback responses with errcode != 0 do not directly terminate the call.
Some older WeChat documents state that non-zero errcode means “no ringing and call canceled”. Actual behavior no longer follows that rule.
Conflicts when two WeChat users call the same device
The WeChat platform does not support multiple users calling the same device at the same time. When two WeChat users call the same device, the calls can interfere with each other in the following ways:
CASE 1: The device receives a second call while ringing
- User A calls the device, and the device is ringing.
- User B calls the device, and the device rejects User B's call.
- The device then answers User A's call, but the call cannot connect.
CASE 2: The device rejects a second call during an active call
- User A calls the device, the device answers, and the call proceeds normally.
- User B calls the device, and the device rejects User B's call.
- User A's active call is then interrupted.
CASE 3: The device ignores a second call during an active call
- User A calls the device, the device answers, and the call proceeds normally.
- User B calls the device. The device ignores the call, while User B leaves it ringing without taking further action.
- About 30 seconds after the device receives User B's call notification, User A's active call is interrupted.
Check whether the device is idle before initiating a call. Choose one of the following approaches based on your business API design:
- Option 1 (recommended): The Mini Program calls a business-server endpoint that initiates the call. The business server first queries the device status and proceeds only when the device is idle; otherwise, it returns a device-busy result to the Mini Program.
- Option 2: The Mini Program first calls a device-availability endpoint provided by the business server. That endpoint proxies
GET /v1/device/wxvoip-call-status. After the device is reported as idle, the Mini Program requests the business server to initiate the call.
/v1/device/wxvoip-call-status is a server-side API protected by TGV1 application credentials. The Mini Program must not call it directly or store server credentials such as access_id or secret_key.
The business server can also serialize call-initiation requests or use a short-lived distributed lock keyed by device_id to further reduce the race window. This is an optional enhancement.
These approaches have the following limitations:
- Once two calls have been initiated and both Mini Programs are ringing, subsequent interference can occur even if the device was genuinely idle when the calls were initiated.
- Call status reporting and cleanup are delayed. They cannot prevent simultaneous calls in every case and may temporarily misclassify an idle device as being in a call.
- Status lookup and call initiation are not atomic; concurrent requests may still observe the device as idle at the same time.
We recommend the approaches above because they address most call-conflict scenarios. In theory, preventing the Mini Program from initiating a call requires checking whether the device is currently being called by a Mini Program. However, maintaining this state may introduce more problems.
How can the device receive upright downlink video instead of video rotated by 90°?
For the device to receive an upright 0° downlink video stream, WeChat must encode a 0° stream and the device must select that stream for subscription. The WeChat version must be later than 8.0.54, and the VoIP plugin version must be 2.4.5 or later. The Mini Program frontend should add version-checking logic. The WeChat-side configuration entry differs by call direction. For details, see the official VoIP Video Stream Guide.
Mini Program calls device
Set encodeVideoRotation to 1 when the Mini Program calls the WeChat VoIP plugin's callDevice API:
const { roomId } = await plugin.callDevice({
roomType: 'video',
sn: deviceId,
modelId,
encodeVideoRotation: 1,
});Device calls Mini Program
When the business server calls WeChat POST /wxa/business/iot/voip/call, pass encodeVideoRotation=1 through query:
POST https://api.weixin.qq.com/wxa/business/iot/voip/call?access_token=<ACCESS_TOKEN>{
..., // Other fields
"query": "encodeVideoRotation=1"
}Issue device call credentials after join_voip_room
For either call direction, after receiving WeChat's join_voip_room notification, add down_video_rotation to the request parameters when calling POST /v1/token/wxvoip to issue peer_id and token:
{
..., // Other fields
"down_video_rotation": 1
}