NICE CXone GET /agents/states returning empty array — agent not showing as logged in

Struggling to understand why the CXone REST API is returning an empty array for agent states when I know for a fact that agents are logged in and taking calls. I am building a lightweight Svelte status widget for our internal portal. The goal is to poll the agent status in real-time.

Context:

I have a SvelteKit server route (src/routes/api/agents/+server.ts) that uses the Fetch API to call the NICE CXone endpoint. I am using a valid OAuth access token generated via the Authorization Code Flow. The token works perfectly for other endpoints like /api/v2/interactions/search.

Here is the relevant code snippet from my server function:

export async function GET() {
 const token = 'Bearer <valid_access_token>';
 const response = await fetch('https://api.us.nice.incontact.com/ic3api/agents/states', {
 headers: {
 'Authorization': token,
 'Content-Type': 'application/json'
 }
 });

 const data = await response.json();
 return new Response(JSON.stringify(data), {
 headers: { 'content-type': 'application/json' }
 });
}

The HTTP status code is 200 OK. No errors. However, the JSON payload is always:

[]

I have verified the following steps:

  1. The agents are logged in via the CXone desktop client.
  2. The agents are assigned to skills and queues.
  3. The token has the agent scope.

I also tried adding query parameters like ?status=available and ?status=busy, but the result remains an empty array. Is there a specific header or query parameter required to return active sessions? Or is this endpoint deprecated in favor of the Conversations API?

Question:

Why is GET /ic3api/agents/states returning an empty array despite valid authentication and active agent sessions? How do I correctly query the current login state of agents using the CXone REST API in a Node.js environment?

1 Like

Make sure you are hitting the correct endpoint for real-time presence. The /api/v2/agents endpoint returns configuration data, not live state. You need to use the Real-Time Presence API specifically. If you are seeing an empty array, it’s usually because the query parameters are missing the specific divisionId or the agent is not explicitly tagged with a presence entity that your OAuth token has scope to read.

Here is a suggested approach using the CXone JavaScript SDK, which handles token management and pagination. This is generally more solid than raw fetch calls in SvelteKit for data integrity.

  1. Install the SDK: npm install nice-cxone-sdk
  2. Use the getPresenceUsers method with explicit pagination.
const cxone = require('nice-cxone-sdk');

// Initialize client (ensure you have the correct OAuth scopes: presence:read)
const presenceApi = new cxone.PresenceApi();

try {
 // Get first page of users with 'Available' status
 const result = await presenceApi.getPresenceUsers({
 presenceEntityId: 'Available',
 expand: ['agentState'],
 pageSize: 25
 });

 if (result.entities) {
 result.entities.forEach(user => {
 console.log(`User: ${user.name}, State: ${user.agentState.name}`);
 });
 } else {
 console.log("No agents found in this state.");
 }
} catch (error) {
 console.error("Error fetching presence data:", error);
}

Verify your OAuth token has the presence:read scope. If you are still getting empty results, check the Division filter. The API defaults to the root division if not specified, but your agents might be in a nested division. Add divisionId to the request if needed. This avoids the CORS and token refresh headaches of client-side polling.

2 Likes

I think the presence endpoint requires the divisionid query param to filter results, otherwise it returns empty for multi-division tenants. try appending ?divisionid={your_division_id} to your request.

The official documentation states that the /agents/states endpoint can be sensitive to scope validation. While the divisionId is relevant for multi-division tenants, an empty array often indicates your OAuth token is missing the necessary permissions. Specifically, ensure your token includes the agent:read scope, and potentially presence:read depending on your tenant configuration.

I’ve encountered similar issues where a valid token, lacking the correct scope, results in silent failures. Verify the token scopes in the CXone admin interface under Applications → API Credentials.

If you’re using the CXone Web Services SDK (WSDK), ensure your client is configured correctly. While the base path is handled by the SDK, you might need to explicitly specify the division ID if applicable.

const agentService = new cxone.AgentService(platformClient);
const response = await agentService.getAgentStates({
 divisionId: 'your-division-id',
 includeStateDetails: true // Equivalent of 'expand'
});

Without includeStateDetails, you might receive agent objects without state information, appearing as an empty result.

Remember to check the CXone documentation for the most up-to-date scope requirements and parameter options.

1 Like

It depends, but generally… the empty array issue is rarely about the endpoint itself but rather how the authentication context intersects with division filters in a multi-tenant setup. When building custom integrations, I see this pattern often. The GET /agents/states endpoint can be strict. If your OAuth token has the necessary agent scopes but lacks visibility into the specific division where agents are logged in, the API returns [] instead of an error.

You must explicitly pass the divisionId query parameter. Without it, the API attempts to scope results to the token’s default division, which might be empty if your service account is not assigned to that division’s user group. ensure your OAuth token includes both the agent and presence:read scopes. The presence:read scope is often required to resolve the agent IDs.

Here is a corrected curl example demonstrating the required parameters:

curl -X GET "https://api.us.nice.incontact.com/ic3api/agents/states?divisionId=your_division_id" \
 -H "Authorization: Bearer {your_oauth_token}" \
 -H "Accept: application/json"

In my integrations, I parse the response and map the agent ID to the actual status name. If the array remains empty after adding the divisionId, verify that the agents are actually logged into a presence entity that is visible to your service account’s division. Sometimes, agents log into a global presence, but the API filters by division visibility. Check the division field in the agent configuration via the agent details API to confirm alignment. This step is critical for reliable polling integrations. If you continue to have issues, investigate the user group assignments associated with your OAuth client to ensure it has the appropriate permissions within the relevant division.