Client Credentials vs Auth Code for server-side reporting in Kotlin?

Hey folks, running into a bit of a blocker with the OAuth setup for a new backend service. I’m building a Kotlin app that needs to pull historical conversation data from Genesys Cloud. The app runs on a server, no user interaction involved, just a scheduled job hitting /api/v2/analytics/conversations/details/queries.

Right now I’m trying to figure out if I should use client_credentials or authorization_code. Since there’s no human logging in to the app, client_credentials seems obvious. But I’ve read some threads saying that for reporting APIs, sometimes you need a specific user context or that client_credentials might be restricted for certain analytics endpoints.

I tried setting up client_credentials first. Here’s the token request I’m making:

val request = HttpRequest.POST("https://api.mypurecloud.com/oauth/token")
 .header("Content-Type", "application/x-www-form-urlencoded")
 .body("grant_type=client_credentials&client_id=${clientId}&client_secret=${clientSecret}")

It returns a token fine. Status 200. But when I use that token to hit the analytics endpoint, I get a 403 Forbidden. The response body is pretty sparse:

{
 "errors": [
 {
 "detail": "Access denied",
 "instanceId": "12345-67890"
 }
 ]
}

I checked the OAuth client settings in Genesys Cloud. The scopes look correct, analytics:report:read is there. I’m wondering if I’m missing a step with the user impersonation or if I actually need to implement an authorization_code flow with a dummy service account user just to get the right permissions?

Does client_credentials actually work for analytics endpoints or is it strictly for admin config changes? If I switch to authorization_code, how do I handle the token refresh on the server side without a user session? Any Kotlin examples or pointers would be appreciated. I’m stuck on why the token is valid but the access is denied.