Calendar API returns 400 Bad Request error when adding new events

Issue with Calendar Event Creation

I built a script that pulls my work schedule and adds it to my Google Calendar. It worked great for months, but now I’m getting this error:

googleapiclient.errors.HttpError: <HttpError 400 when requesting https://www.googleapis.com/calendar/v3/calendars/primary/events?alt=json returned "Bad Request". Details: "[{'domain': 'global', 'reason': 'badRequest', 'message': 'Bad Request'}]">

I haven’t modified the code at all. Some sources online suggest it could be related to timezone settings, but I’m not certain. The only thing I’ve updated is my browser driver.

from __future__ import print_function
import datetime
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials

from selenium import webdriver
from selenium.webdriver.common.by import By
import re

# Initialize variables
shift_count = 0
shifts = []

# User credentials
user_email = "my_email"
user_password = "my_password"

user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

chrome_options = webdriver.ChromeOptions()
chrome_options.headless = True
chrome_options.add_argument(f'user-agent={user_agent}')
chrome_options.add_argument("--window-size=1920,1080")
chrome_options.add_argument('--ignore-certificate-errors')
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--no-sandbox')
browser = webdriver.Chrome(executable_path="chromedriver.exe", options=chrome_options)

# Open scheduling webpage
browser.get("https://app.tamigo.com/Shift/Pages/EmployeeShifts.aspx")

# Insert login info
email_input = browser.find_element(By.ID, 'Username')
email_input.send_keys(user_email)

password_input = browser.find_element(By.ID, 'Password')
password_input.send_keys(user_password)

# Log in
login_button = browser.find_element(By.ID, 'login-btn').click()

# Retrieve the shift table
table = browser.find_element(By.XPATH, '//*[@id="employeeShiftsGrid"]/tbody')

# Extract shift data
for row in table.find_elements(By.TAG_NAME, "tr"):
    shift_count += 1
    date = browser.find_element(By.XPATH, "//*[@id='employeeShiftsGrid']/tbody/tr[{}]/td[4]".format(shift_count)).text
    time = browser.find_element(By.XPATH, "//*[@id='employeeShiftsGrid']/tbody/tr[{}]/td[5]".format(shift_count)).text
    shifts.append([date, time])

# Clean up date and time strings
for index in range(len(shifts)):
    shifts[index][0] = re.sub('\D', '', shifts[index][0])
    shifts[index][1] = re.sub('\D', '', shifts[index][1])

# Adjust time if any break exists
for index in range(len(shifts)):
    if len(shifts[index][1]) > 8:
        shifts[index][1] = shifts[index][1][:-1]

# Google Calendar API setup
SCOPES = ['https://www.googleapis.com/auth/calendar']

creds = None
if os.path.exists('token.json'):
    creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
            'C:/Users/user/Desktop/calendar/credentials.json', SCOPES)
        creds = flow.run_local_server(port=0)
    with open('token.json', 'w') as token_file:
        token_file.write(creds.to_json())

calendar_service = build('calendar', 'v3', credentials=creds)

# Fetch existing events
current_time = datetime.datetime.utcnow().isoformat() + 'Z'
existing_events = calendar_service.events().list(calendarId='primary', timeMin=current_time,
                                      maxResults=100, singleEvents=True,
                                      orderBy='startTime').execute()
event_list = existing_events.get('items', [])

# Remove past work events
for event in event_list:
    event_start = event['start'].get('dateTime', event['start'].get('date'))
    if event['summary'] == "Work Shift":
        calendar_service.events().delete(calendarId='primary',
                                eventId=event['id']).execute()

# Create new calendar events from shifts
for i in range(len(shifts)):
    end_hour = str(shifts[i][1][4]) + str(shifts[i][1][5])
    start_year = int(str(shifts[i][0][4]) + str(shifts[i][0][5]) + str(shifts[i][0][6]) + str(shifts[i][0][7]))
    start_month = int(str(shifts[i][0][2]) + str(shifts[i][0][3]))
    start_day = int(str(shifts[i][0][0]) + str(shifts[i][0][1]))
    start_hour = int(str(shifts[i][1][0]) + str(shifts[i][1][1]))
    start_minute = int(str(shifts[i][1][2]) + str(shifts[i][1][3]))
    end_year = start_year
    end_month = start_month
    end_day = start_day
    end_hr = int(str(shifts[i][1][4]) + str(shifts[i][1][5]))
    end_min = int(str(shifts[i][1][6]) + str(shifts[i][1][7]))
    
    # Handle overnight shifts
    if int(end_hour) >= 0 and int(end_hour) < 4:
        new_event = {
            'summary': 'Work Shift',
            'start': {
                'dateTime': '{}-{:02d}-{:02d}T{:02d}:{:02d}:00'.format(start_year, start_month, start_day, start_hour, start_minute),
                'timeZone': 'Europe/Copenhagen',
            },
            'end': {
                'dateTime': '{}-{:02d}-{:02d}T{:02d}:{:02d}:00'.format(end_year, end_month, end_day+1, end_hr, end_min),
                'timeZone': 'Europe/Copenhagen',
            }
        }
        new_event = calendar_service.events().insert(calendarId='primary', body=new_event).execute()
    else:
        new_event = {
            'summary': 'Work Shift',
            'start': {
                'dateTime': '{}-{:02d}-{:02d}T{:02d}:{:02d}:00'.format(start_year, start_month, start_day, start_hour, start_minute),
                'timeZone': 'Europe/Copenhagen',
            },
            'end': {
                'dateTime': '{}-{:02d}-{:02d}T{:02d}:{:02d}:00'.format(end_year, end_month, end_day, end_hr, end_min),
                'timeZone': 'Europe/Copenhagen',
            }
        }
        new_event = calendar_service.events().insert(calendarId='primary', body=new_event).execute()

Can anyone provide insights into what might be the problem?