POST /api/v2/conversations/calls 400 Bad Request: Malformed participant address with valid E.164

I’m running into a weird validation issue when trying to initiate outbound calls via the Genesys Cloud API. I need these calls to trigger specific OpenTelemetry spans in our downstream Data Actions, so the payload structure is strict.

The endpoint is POST /api/v2/conversations/calls. I’m sending a standard call object with a valid E.164 destination number. The number passes our local regex checks (it looks like +15551234567), and it works fine in the GUI.

Here is the JSON body I’m sending:

{
 "to": {
 "phoneNumber": "+15551234567",
 "type": "phoneNumber"
 },
 "from": {
 "phoneNumber": "+18005550199",
 "type": "phoneNumber"
 },
 "wrapUpCode": "default"
}

The API responds with a 400 Bad Request. The error message in the body is:

{
 "message": "Malformed participant address",
 "code": "bad_request",
 "status": 400,
 "errors": [
 "Malformed participant address"
 ]
}

I’ve tried:

  1. Removing the + sign. Still 400.
  2. Adding country code explicitly in a different field structure. Still 400.
  3. Checking for hidden unicode characters in the string. None found.

My Node.js SDK code looks like this:

const apiInstance = new PlatformClient.ConversationsApi();
const call = new PlatformClient.Call();
call.to = { phoneNumber: "+15551234567", type: "phoneNumber" };
call.from = { phoneNumber: "+18005550199", type: "phoneNumber" };

try {
 const data = await apiInstance.postConversationCall(call);
 console.log("Call initiated:", data);
} catch (error) {
 console.error("Error:", error.message);
}

The trace context is being injected correctly into the headers, so that’s not the issue. Is there a specific format requirement for the phoneNumber field that isn’t documented? I’m on API version 2024-01-01.

What am I missing?

The + prefix is the culprit. The Genesys Cloud API validator for /api/v2/conversations/calls expects strict E.164 without the leading plus sign for the to address in many SDK wrappers, or it requires explicit tel: URI scheme if you want to be safe. The GUI handles the normalization automatically, which is why it works there but fails via raw API.

Try stripping the + and wrapping it in tel:.

{
 "to": {
 "phoneNumber": "+15551234567"
 },
 "from": {
 "phoneNumber": "+15559876543"
 },
 "routing": {
 "type": "queue",
 "queueId": "your-queue-id-here"
 }
}

Wait, if you’re hitting 400 on a valid number, check the from address too. It has to be a verified outbound email or phone number in your org settings. If it’s not, the API rejects the whole payload before it even checks the destination.

Also, ensure you’re using the correct OAuth scope. You need conversation:call:write and conversation:call:read. If you’re using a client credential token, make sure the application has the proper permissions.

Here’s a quick curl test to isolate the issue:

curl -X POST "https://api.mypurecloud.com/api/v2/conversations/calls" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
 "to": {
 "phoneNumber": "+15551234567"
 },
 "from": {
 "phoneNumber": "+15559876543"
 },
 "routing": {
 "type": "queue",
 "queueId": "your-queue-id-here"
 }
 }'

If this still fails, check the error response body. It usually points to the specific field. Sometimes the issue is hidden in the routing object if the queue ID is invalid or doesn’t exist.

One more thing. If you’re using the PureCloudPlatformClientV2 SDK, use the CreateCall method. It handles the serialization better than raw JSON.

const platformClient = require('purecloud-platform-client-v2');
const callApi = platformClient.ConversationsApi();

const body = {
 to: { phoneNumber: "+15551234567" },
 from: { phoneNumber: "+15559876543" },
 routing: { type: "queue", queueId: "your-queue-id-here" }
};

callApi.postConversationsCalls(body).then(response => {
 console.log(response.body);
});

Check your logs for the exact error message. It’s usually more helpful than the 400 status code.