DFO API batch job fails 401 mid-stream despite valid initial token

We’ve got a Python worker pulling message history from the DFO API to sync with our internal CRM. The script grabs a token using client_credentials, then loops through a batch of 500 interaction IDs. It works fine for the first 200 or so requests. Then, suddenly, the API starts throwing 401 Unauthorized errors.

The weird part is the token doesn’t actually expire at that exact second. The access token TTL is set to 3600 seconds. The batch takes about 10 minutes to run. So the token should still be valid. But the gateway rejects it.

I tried adding a refresh check. The logic looks something like this:

if current_time > token_expiry - 300:
 refresh_token()
 set_new_headers()

Still hitting 401s. I logged the exact timestamp of the failure. The token was valid for another 20 minutes.

Is there a sliding window or a concurrent session limit I’m missing? The docs say the token is valid until expiry. But the API seems to invalidate it early under load.

I also checked the response headers. No Retry-After. Just a plain 401.

Here’s the failing request snippet:

requests.get(
 "https://api.nice.com/v2/interactions/messages",
 headers={"Authorization": f"Bearer {access_token}"},
 params={"interactionId": msg_id}
)

The token is definitely being sent. I printed the header before the call. It matches the one I got from /oauth2/token.

Maybe the DFO endpoint has a stricter validation? Or is it a cache issue on the gateway side?

I can’t just refresh every request. That’ll tank our rate limits. And refreshing on every 401 feels hacky.

Anyone else seen this behavior with long-running batch jobs? The token claims to be valid, but the API says no. It’s like the server has a different clock. Or maybe it’s revoking tokens after a certain number of requests regardless of time.

I’ve checked the NICE CXone status page. No incidents.

What’s the proper way to handle this? I don’t want to poll the token endpoint every second. That’s wasteful.

Also, the error body is empty. Just 401. No details. Makes debugging hard.

Is there a way to get more verbose auth logs? Or is this a known quirk with the DFO API specifically?

We’re running this from Mexico City. Timezone shouldn’t matter. The token expiry is UTC. My server is UTC.

I’m out of ideas. The token is valid. The API says it’s not.