Python SDK bulk user creation from CSV failing with 400 Bad Request

Hey folks,

I’ve been working on a Python script to bulk-create users from a CSV file using the Genesys Cloud Platform SDK. The goal is to automate onboarding for our WFM team since manually adding agents in the UI is tedious.

Here is the relevant snippet:

from genesyscloud import PlatformClient, IdentityClient
from genesyscloud.resources import Users

client = PlatformClient()
client.login("client_id", "secret")

with open('agents.csv', 'r') as f:
 for row in reader(f):
 body = {
 'name': row['name'],
 'email': row['email'],
 'addresses': [{'address': row['phone'], 'type': 'work'}],
 'roles': [{'id': 'agent_role_id'}]
 }
 response, status = client.users.post_users(body=body)
 if status != 201:
 print(f"Failed: {response}")

The script runs but returns a 400 Bad Request error for every user. The error message says “Invalid email format” even though the emails in the CSV are valid.

I have tried:

  • Validating the CSV data manually
  • Using the Identity API instead of Users API
  • Adding a delay between requests
  • Checking the SDK documentation for required fields

The code works for single user creation when I hardcode the values, but fails with the CSV loop. The error log shows:

400: {"message": "Invalid email format", "code": "invalid.parameter"}

I’m not sure if the SDK is stripping special characters or if there is a threading issue. The script is single-threaded so that shouldn’t be the case.

Any ideas on how to debug this? The environment is Python 3.9 with genesyscloud-sdk 3.0.0. Running on US/Central time zone. The CSV has standard columns: name, email, phone, role_id.

The role_id is correct and exists in the tenant. I’ve verified the API token has the right scopes.

I’m stuck on this. The error doesn’t give more details. Is there a way to get verbose error output from the SDK? Or is there a specific format for the email field in the post_users call that I’m missing?

Thanks for any help.

The 400 error usually happens because the divisionId is missing or invalid in the payload. The SDK doesn’t guess which team or division the agent belongs to. You have to provide it explicitly.

Here is how I structure the user creation request. Notice the division_id field. It’s required for voice users.

from platformclientv2 import (
 PlatformClient,
 PostUserRequestBody,
 RoutingEmail,
 RoutingSkill,
 RoutingSkillLevel,
 RoutingUser
)

client = PlatformClient()
client.login("your_client_id", "your_secret")

# 1. Get the division ID first if you don't have it hardcoded
# This assumes you have a known team or division name
team_api = client.get_routing_api()
teams_response = team_api.get_routing_teams()
target_division_id = None
for team in teams_response.entities:
 if team.name == "WFM Agents":
 target_division_id = team.division_id
 break

if not target_division_id:
 raise Exception("Division not found")

# 2. Build the user payload
user_request = PostUserRequestBody()
user_request.email = "newagent@example.com"
user_request.name = "New Agent"
user_request.username = "newagent"
user_request.password = "TemporaryPassword123!"
user_request.activated = True
user_request.division_id = target_division_id # CRITICAL

# 3. Optional: Add routing details if needed immediately
routing = RoutingUser()
routing.skills = []
user_request.routing = routing

try:
 users_api = client.get_users_api()
 created_user = users_api.post_users(body=user_request)
 print(f"User created: {created_user.id}")
except Exception as e:
 print(f"Error: {e}")

The SDK maps division_id to the JSON body. If you omit it, the API rejects the request. Also check if your client ID has the user:write scope. Without it, you get 403, but the error message sometimes looks like a validation failure.

Check the logs for the specific validation error. It usually says divisionId is required.