Getting 401 Unauthorized on CXone /api/v2/authorization/oauth2/token with client_credentials

I’m trying to set up a background script to pull WFM adherence data from CXone. The docs say I should use the client_credentials grant type for server-to-server calls, so I don’t have to deal with user tokens expiring every hour. It feels like the right move for a scheduled job.

I’ve got my client ID and secret from the developer portal. I’m making a POST request to the token endpoint. Here is the Python code I’m using:

import requests

client_id = "my-client-id-123"
client_secret = "my-secret-456"

url = "https://api.mynice.com/api/v2/authorization/oauth2/token"

payload = {
 "grant_type": "client_credentials"
}

response = requests.post(url, data=payload, auth=(client_id, client_secret))
print(response.status_code)
print(response.text)

I expect to get a JSON response with an access_token. Instead, I’m getting a 401 Unauthorized. The response body is just:

{
 "message": "Unauthorized"
}

I’ve double-checked the credentials. I can log in to the CXone portal with the admin account that generated these keys, so they aren’t expired or revoked. I also tried adding the Content-Type: application/x-www-form-urlencoded header explicitly, but that didn’t change anything.

Is there something missing from the payload? The Genesys Cloud docs mention a scope parameter, but the CXone docs for this endpoint are a bit light on details. Do I need to request specific scopes like analytics:read in the initial token request? Or is the endpoint path different for CXone compared to Genesys Cloud?

I’m stuck on this authentication step before I can even start querying the adherence metrics. Any help would be appreciated.

Check your grant_type value in the body. It needs to be client_credentials, not client-credentials with a hyphen. That tiny typo triggers the 401 immediately.