WFM Schedule API 400 Error: TIMEZONE_OFFSET mismatch on Europe/London

import requests

headers = {
 "Authorization": f"Bearer {OAUTH_TOKEN}",
 "Content-Type": "application/json"
}

payload = {
 "schedule_id": "wfm_sched_001",
 "start_date": "2024-06-03T08:00:00.000Z",
 "end_date": "2024-06-03T16:00:00.000Z",
 "items": [
 {
 "resource_id": "ext_agent_99",
 "shift_template_id": "tpl_london_08",
 "timezone": "Europe/London"
 }
 ]
}

res = requests.post(
 "https://api.mypurecloud.com/api/v2/wfm/schedules",
 headers=headers,
 json=payload
)
print(res.status_code)
print(res.text)

Returns a hard 400. The SCHEDULE_API rejects the payload immediately. Error payload looks like this:
{"error_code":"invalid_shift_mapping","message":"TIMEZONE_OFFSET mismatch for Europe/London. Expected +00:00, received +01:00"}

The system’s running on BST right now. The WORKFORCE_MANAGEMENT_ENDPOINT seems to be checking against a hardcoded UTC calendar instead of pulling the actual daylight saving rules. Swapped the start_date to local time. Same result. The API documentation claims automatic DST_HANDLING, but the VALIDATION_GATE is clearly parsing the string and comparing it to a static offset table.

Environment details:

  • Platform: Genesys Cloud EMEA-PROD-04
  • SDK: genesys-cloud-python 3.2.1
  • Target Endpoint: /api/v2/wfm/schedules
  • Integration Type: custom python polling script
  • Key Configurations: SCHEDULE_API, SHIFT_TEMPLATES, TIMEZONE_OFFSET, OAUTH_TOKEN, WORKFORCE_MANAGEMENT_ENDPOINT

Stripped the shift_template_id and passed a raw shift_id. Validation still doesn’t pass. The routing side accepts these exact tokens and pushes calls through without blinking. WFM side is doing jack all with the SCHEDULE_PAYLOAD structure. Console stays empty. Architect flow isn’t even triggered because the API gate kills it first.

curl -X POST "https://api.mypurecloud.com/api/v2/wfm/schedules" \
-H "Authorization: Bearer $OAUTH_TOKEN" \
-H "Content-Type": application/json" \
-d '{"schedule_id":"test_02","start_date":"2024-06-03T08:00:00Z","timezone":"Europe/London"}'

Still throws the offset mismatch. Logs aren’t showing anything on the backend. Just the raw JSON error back.