POST /api/v2/outbound/contactlists returns 400 INVALID_VALUE on valid CSV payload

Stumbled on a weird bug today with the CXone Outbound API. I am attempting to create a new contact list via POST /api/v2/outbound/contactlists. The request returns a 400 Bad Request with an INVALID_VALUE error code. This is frustrating because the JSON structure matches the Swagger definition exactly. I have verified that the contactListId is unique and the name is non-null.

Here is the payload I am sending:

{
 "contactListName": "Q3_Campaign_Test",
 "contactListType": "CSV",
 "description": "Automated import via WFM sync",
 "contactListSettings": {
 "duplicateCheckEnabled": true
 }
}

The error response body is generic:

{
 "errorCode": "INVALID_VALUE",
 "message": "Invalid value provided for field."
}

I am using the standard Python SDK genesyscloud_platform_client. I have tried disabling duplicate checks and changing the list type to CSV_UPLOAD, but the error persists. The documentation is sparse on what constitutes an invalid value for the settings object. Is there a hidden schema requirement for contactListSettings that is not documented? Or is this a known issue with the v2 endpoint?

Thanks.

If I recall correctly, the Outbound API is stricter than the standard user endpoints. The error usually stems from how the CSV content is encoded or the metadata attached to it.

Cause: The INVALID_VALUE error on contact list creation typically indicates that the contactListType is missing or that the importData object contains a malformed CSV string. The API expects the CSV data to be Base64 encoded within the importData payload, not raw text. It also requires explicit column mapping if the headers don’t match the standard Genesys Cloud schema exactly.

Solution:

  1. Encode your CSV. Read the file content and encode it to Base64.
  2. Structure the payload correctly. Ensure contactListType is set to IMPORT.
  3. Define column mappings. If your CSV headers differ from standard fields (like firstName, lastName, phoneNumber), you must provide a contactListColumnMappings array.

Here is the corrected JavaScript logic for your Chrome extension’s content script:

const csvContent = "firstName,lastName,phoneNumber\nJohn,Doe,+14165550199";
const base64Csv = btoa(unescape(encodeURIComponent(csvContent)));

const payload = {
 "name": "Toronto_BPO_List",
 "contactListType": "IMPORT",
 "importData": {
 "data": base64Csv,
 "mappings": [
 { "name": "firstName", "type": "string", "sourceColumn": "firstName" },
 { "name": "lastName", "type": "string", "sourceColumn": "lastName" },
 { "name": "phoneNumber", "type": "phone", "sourceColumn": "phoneNumber" }
 ]
 }
};

// Use the PureCloud SDK or direct fetch with proper OAuth header
const response = await fetch("https://api.mypurecloud.com/api/v2/outbound/contactlists", {
 method: "POST",
 headers: {
 "Content-Type": "application/json",
 "Authorization": `Bearer ${accessToken}`
 },
 body: JSON.stringify(payload)
});

Verify the sourceColumn values match your CSV headers exactly. Case sensitivity matters. If you skip the importData object entirely, the list is created empty, which is a valid alternative if you plan to upload later.