My config is not working… i tried hitting POST /api/v2/users/skills with a batch payload to update proficiencies.
sent this json {"items": [{"userId": "x", "skillId": "y", "proficiency": 90}]} and got 400 Bad Request: invalid batch structure.
docs are vague. i’m guessing the structure since payload looks right to me.
you might want to look at the actual schema for the batch endpoint. i’ve been wrestling with similar 400s while building our ServiceNow sync pipelines, and it’s usually a subtle format mismatch rather than a logic error. the POST /api/v2/users/skills endpoint expects a specific wrapper that isn’t just a simple array of items.
also, double check your auth. are you using an admin token with admin:users:write scope? if you’re using a user token, it’ll reject the batch immediately. i ran into this last week when our script tried to push updates from a service account that only had read access to user profiles.
here’s the exact payload structure that worked for me. notice the items array needs to be strictly typed.
{
"items": [
{
"userId": "12345",
"skillId": "67890",
"proficiency": 90
}
]
}
if that still fails, try hitting it with curl first to rule out any SDK serialization quirks. sometimes the PureCloud SDK wraps the payload in an extra object if you’re not passing the raw body correctly.
curl -X POST "https://api.mypurecloud.com/api/v2/users/skills" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"userId": "12345",
"skillId": "67890",
"proficiency": 90
}
]
}'
one thing i learned the hard way is that proficiency is an integer, not a float. sending 90.5 might cause a silent validation fail depending on the version. keep it whole. also, make sure the user and skill ids actually exist and are active. if the skill is archived, the batch will throw a 400 too.
It depends, but generally the batch endpoint expects a slightly different wrapper than what’s being sent here. the error invalid batch structure usually points to a mismatch in the top-level object keys or missing required fields for the specific resource type. when working with user skills, the payload needs to explicitly define the operation type for each item, not just the data. the docs can be light on the exact JSON shape for bulk ops, but the pattern is usually {"items": [{"operation": "create", "data": {...}}]} or similar depending on the version.
try restructuring the payload to include the operation field inside each item object. also, ensure the proficiency value is an integer, not a float or string, as the validator is strict on types. here’s a corrected example:
{
"items": [
{
"operation": "create",
"data": {
"userId": "x",
"skillId": "y",
"proficiency": 90
}
}
]
}
if you’re updating existing skills, use "operation": "update" instead. another gotcha is that some endpoints require the skillId to be a string, even if the UI shows it as a number. double-check the schema definition in the swagger docs for UserSkill. if that still fails, check the X-Genesys-Request-Id header in the response and cross-reference it with the server logs if you have admin access. sometimes the error message is generic but the logs show a specific field validation failure. also, make sure your access token has the user:skill:write scope.
i usually solve this by checking the batch operation type first. the error invalid batch structure almost always means you’re missing the operation field inside each item object. genesys cloud’s batch endpoints are strict about this. you can’t just send userId, skillId, and proficiency. you need to wrap that data in an object that tells the api what to do. for user skills, the operation is typically assign or update. the payload should look like this:
{
"items": [
{
"operation": "assign",
"userId": "x",
"skillId": "y",
"proficiency": 90
}
]
}
without that operation key, the parser chokes. it doesn’t know if you’re adding, removing, or updating. also, watch out for the proficiency scale. if your organization uses a different scale (like 1-5 instead of 0-100), sending 90 might trigger a validation error later, even if the structure is right. check your skill configuration in the admin portal to confirm the max value.
another gotcha is the scope. even if the structure is perfect, a 400 can sometimes mask a permission issue if the token lacks admin:users:write. but the “invalid batch structure” message is pretty specific to the json shape. double-check that the top-level key is items and not data or payload. some other apis use different wrappers. genesys is picky. i’ve seen teams spend hours debugging auth when it was just a missing operation field. it’s a small detail but it breaks the whole batch.
You might want to look at the operation field. it’s required for batch updates. missing it triggers that 400. also, check if you’re using the correct endpoint for proficiency changes vs assignments.
- batch operation types
- user skill schema
- admin:users:write scope