403 Forbidden on GET /api/v2/routing/queues with valid Bearer token

GET /api/v2/routing/queues returns 403 Forbidden.

The token is fresh. Refreshed it 10 seconds ago via client credentials flow. Token validation against /api/v2/oauth/token/validate returns 200 OK. Scopes listed in the decoded JWT include admin, routing:queue:read, and routing:queue.

Here is the minimal repro using requests:

import requests
import redis

r = redis.Redis(host='localhost', port=6379, db=0)
token = r.get('gc:access_token')

if not token:
 # Logic to fetch new token omitted for brevity
 pass

headers = {
 'Authorization': f'Bearer {token.decode("utf-8")}',
 'Content-Type': 'application/json'
}

resp = requests.get('https://api.mypurecloud.com/api/v2/routing/queues', headers=headers)
print(resp.status_code)
print(resp.text)

Output:

403
{"errors":["Forbidden"]}

I have checked the user’s role in the admin console. It is Admin. I have also tried using a service account with routing:queue:read scope explicitly granted in the OAuth client configuration. Same result.

The weird part is that GET /api/v2/routing/users/me works fine with the same token. Also GET /api/v2/organizations works. It seems specific to the routing queues endpoint.

I verified the region is correct in the base URL. I am not hitting the rate limit as I am making one request per minute for testing.

Is there a specific scope combination required that is not documented clearly? Or is there a permission check happening at the organization level that blocks queue access even for admins?

I noticed in some old forum posts people mention routing:queue:all but that scope does not appear in the current API reference documentation for v2.

Which exact OAuth scope or permission set is required to successfully call GET /api/v2/routing/queues without receiving a 403 Forbidden error, given that the token is valid and the user has Admin role?

if i remember correctly, check your division id in the header; the token scopes look fine but a missing x-gcc-division-id often triggers a 403 on queue endpoints.

headers = {"Authorization": f"Bearer {token}", "X-GCC-Division-Id": "your_division_id"}

This has the hallmarks of a classic division scope mismatch. The 403 Forbidden response is misleading when the token validation passes. It usually means the token has the right scopes but lacks the specific division context required by the resource.

The suggestion about X-GCC-Division-Id is correct, but it’s often incomplete. If your OAuth client is configured with a specific division scope, you must explicitly pass that division ID. If you omit it, Genesys Cloud defaults to the “default” division, and if the queue isn’t there, you get a 403.

Here is the corrected Postman pre-request script to handle this dynamically using environment variables. This ensures the header is always present and matches the token’s division scope.

// Pre-request Script for Postman Collection
// Ensure the division ID is pulled from the environment
var divisionId = pm.environment.get("divisionId");

if (divisionId) {
 pm.request.headers.add({
 key: "X-GCC-Division-Id",
 value: divisionId
 });
 console.log("Added X-GCC-Division-Id: " + divisionId);
} else {
 console.warn("No divisionId found in environment. Defaulting to root division behavior.");
}

Verify your divisionId variable in Postman matches the division where the queue actually resides. You can confirm the queue’s division by fetching a single queue by ID first: GET /api/v2/routing/queues/{queueId}. The response body will contain a divisionId field. Use that value.

Also, check if your OAuth client is restricted to specific divisions. If it is, the admin scope alone doesn’t grant cross-division access. The token must be issued for a client that has access to that specific division, and the header must match.

Note: If you are using the New Agent Experience, ensure the division ID is not empty. An empty string can sometimes cause unexpected routing errors. Always validate the division ID exists before making the request.

The simplest way to resolve this is… to explicitly set X-GCC-Division-Id. In Five9, queues were global. In GC, they are division-scoped. If your service account lacks division:all, omitting the header defaults to a division you might not access. Add X-GCC-Division-Id: <division_id> to your headers. Verify the ID matches the queue’s resource.