CXone Client Credentials: 401 on /api/v2/oauth/token despite correct payload

Building a simple token service for CXone. I’m hitting the auth endpoint with the client credentials flow. The docs state: “Send a POST request to /api/v2/oauth/token with the grant_type set to client_credentials.” My curl looks solid.

POST /api/v2/oauth/token HTTP/1.1
Host: api.mypurecloud.com
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=abc123&client_secret=xyz789

Getting a 401 Unauthorized back.

{
 "message": "Bad credentials",
 "status_code": 401
}

I’ve verified the client_id and secret in the portal. They’re active. I’ve also checked the expiration. It’s not expired. Is there a specific scope required for this endpoint to accept the creds? Or is the Content-Type wrong? Tried application/json too but that just gives a 400.

Running this from a container in Amsterdam. Timezone isn’t an issue. The clock is synced. Just trying to get the initial access token. Why is it rejecting the secret?