CXone Personal Connection API outbound call 400 Bad Request

Does anyone know the exact payload structure for triggering an outbound call via the CXone Personal Connection API? I am sending a POST to /api/v2/outbound/campaigns/{id}/executions with a valid auth token, but I keep getting a 400 Bad Request. My JSON includes the contactId and contactSpec, yet the error message is generic.

Here is the snippet. The documentation is vague on required nested fields for contactSpec.

import requests
headers = {'Authorization': 'Bearer <token>', 'Content-Type': 'application/json'}
payload = {
 'contactId': '12345',
 'contactSpec': {
 'address': '+1234567890',
 'type': 'voice'
 }
}
requests.post(url, headers=headers, json=payload)

The logs show no specific validation failure. Am I missing a required attribute in contactSpec?

The root cause here is the mismatch between the contactSpec structure in the v2 Outbound Campaign execution API and the Personal Connection trigger. The endpoint /api/v2/outbound/campaigns/{id}/executions expects a specific schema that includes contactId, contactSpec with contactId and contactData, and often campaignId if not in the path. However, for Personal Connection, you should not use the campaign execution endpoint. You need to use the Personal Connection specific endpoint or ensure the campaign is configured for manual triggers. If you are trying to trigger a Personal Connection via API, you likely need to use /api/v2/outbound/contacts/{contactId}/personal-connections or verify that the contactSpec contains the required contactId and contactData fields with the correct media type. Here is the correct payload structure for a standard outbound execution if you are stuck on that path, but note that Personal Connections often require a different approach via the outbound/campaigns/{id}/executions only if the campaign is set to allow manual execution.

import requests

headers = {
 'Authorization': f'Bearer {token}',
 'Content-Type': 'application/json'
}

payload = {
 "contactId": "12345678-1234-1234-1234-123456789012",
 "contactSpec": {
 "contactId": "12345678-1234-1234-1234-123456789012",
 "contactData": {
 "phoneNumber": "+1234567890"
 }
 }
}

response = requests.post(
 f'https://api.mypurecloud.com/api/v2/outbound/campaigns/{campaign_id}/executions',
 headers=headers,
 json=payload
)
print(response.status_code)
print(response.text)
  • Verify campaign allows manual execution
  • Check contactData schema matches media type
  • Ensure valid OAuth scope for outbound execution
  • Confirm contact exists in the correct list

The simplest way to resolve this is to bypass the campaign execution endpoint entirely. Personal Connection triggers require a distinct payload structure that the standard outbound API does not accept.

Use the specific Personal Connection trigger endpoint instead. Send a POST to /api/v2/engagements/outbound/personal-connections with the contact ID and reason code in the body.

Check the response headers for the engagement ID. This approach avoids the schema mismatch causing your 400 errors and provides direct tracking for sentiment analysis pipelines.

This is typically caused by the endpoint mismatch highlighted above. You are hitting the campaign execution API instead of the specific Personal Connection trigger. The schema validation fails because the fields do not align with that path.

The correct endpoint is /api/v2/engagements/outbound/personal-connections. This route expects a simpler payload structure designed specifically for ad-hoc outreach rather than scheduled campaign runs.

Use this curl example to verify the payload. Ensure your token has the outbound:campaign:execute scope. The response will return the engagement ID immediately upon success.

curl -X POST "https://api.mypurecloud.com/api/v2/engagements/outbound/personal-connections" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{"contactId": "user_id", "reasonCode": "follow_up"}'

I typically get around this by ensuring the contactId in the payload matches the exact UUID format of the target user. The endpoint /api/v2/engagements/outbound/personal-connections is strict about schema validation. Verify the contact exists in the correct org scope.

{
 "contactId": "uuid-here",
 "reasonCode": "Follow up"
}