Cxone outbound call via personal connection api returning 400

quick question about triggering outbound calls in cxone using the personal connection api. my grpc service sends a post to /api/v2/outbound/calls with valid auth and payload, but i keep hitting a 400 bad request. the json payload matches the docs exactly. is there a specific header missing for this endpoint?

{
 "to": "+6591234567",
 "from": "+6598765432",
 "playback": "http://example.com/audio.mp3"
}

any ideas?

The simplest way to resolve this is to check the Content-Type header and ensure the playback URL is publicly accessible. The Personal Connection API is strict about schema validation. You are likely missing the application/json content type header, or the playback URL is blocking server-side requests. In Go, I always use a custom HTTP client with explicit headers to avoid defaulting to text/plain. Here’s how I structure the request in my services:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

func makeOutboundCall(token string) error {
	payload := map[string]string{
		"to": "+6591234567",
		"from": "+6598765432",
		"playback": "https://example.com/audio.mp3", // must be https and public
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("marshal error: %w", err)
	}

	req, err := http.NewRequest("POST", "https://api.cxone.net/outbound/v1/calls", bytes.NewBuffer(jsonData))
	if err != nil {
		return fmt.Errorf("new request error: %w", err)
	}

	// critical headers
	req.Header.Set("Authorization", "Bearer "+token)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("request error: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusCreated {
		return fmt.Errorf("unexpected status: %d", resp.StatusCode)
	}

	return nil
}

The playback URL must be HTTPS and accessible from the CXone servers. If it requires authentication or is behind a firewall, the call will fail with a 400. Also, verify the from number is provisioned and allowed for outbound calls within your CXone organization settings. If you’re still getting a 400, enable debug logging on your HTTP client to inspect the full error message returned in the response body. It usually points to a specific field validation failure, helping you pinpoint the issue.

You need to verify the Content-Type header is explicitly set to application/json. The NICE CXone API rejects payloads without this header, often returning a 400 even if the JSON structure is valid. Also, ensure the playback URL is publicly accessible. If it’s behind a firewall or requires authentication, the server-side fetch will fail.

Here is the Python requests equivalent to validate the endpoint before integrating into your gRPC service:

import requests

url = "https://api.niceincontact.com/api/v2/outbound/calls"
headers = {
 "Authorization": "Bearer YOUR_ACCESS_TOKEN",
 "Content-Type": "application/json"
}
payload = {
 "to": "+6591234567",
 "from": "+6598765432",
 "playback": "http://example.com/audio.mp3"
}

response = requests.post(url, headers=headers, json=payload)
print(response.status_code)
print(response.text)

Check the response body for specific field errors. Sometimes the from number isn’t registered in your account settings, which also triggers a 400. Verify your API user has the Outbound:Call:Create permission.

Requirement Value
Content-Type application/json
Playback URL Publicly accessible HTTP/HTTPS
Auth Scope Outbound:Call:Create
1 Like

The best approach here is to confirm you’re using the correct outbound call endpoint within the CXone API. The Personal Connection API is designed for agent-to-customer PSTN connections, not programmatic outbound dialing. You should be leveraging the Outbound API with the appropriate context and call parameters.

curl -X POST https://{your-org}.cxone.net/api/v2/outbound/calls \
 -H "Authorization: Bearer {access_token}" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "+6591234567",
 "from": "+6598765432",
 "callType": "outbound",
 "playback": "http://example.com/audio.mp3"
 }'

The 400 error indicates a schema mismatch; the Personal Connection API expects different payload fields for its specific bridging use case. Double-check your callType and ensure you’ve correctly configured the required campaign context for outbound calls within your CXone organization.

This is caused by schema validation strictness in the NICE CXone Outbound API, specifically regarding the playback field. While previous suggestions correctly identified the Content-Type header, the payload structure itself is often the culprit for 400 errors. The playback URL must be publicly accessible without authentication, and the API expects a specific object structure rather than a simple string in some SDK versions.

In my Architect flows, I use Data Actions to validate the URL before triggering the call. Ensure your JSON payload explicitly defines the callType if you are not using the default. Here is a corrected curl command that includes the necessary headers and a valid payload structure:

curl -X POST "https://api.cxone.net/api/v2/outbound/calls" \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
 "to": "+6591234567",
 "from": "+6598765432",
 "playback": {
 "uri": "http://example.com/audio.mp3"
 }
}'

Verify the playback object format matches your specific API version documentation. Also, double-check the outbound call settings in CXone Admin to ensure the calling number is provisioned correctly and has permission to make outbound calls to the destination country.

1 Like