Press "Enter" to skip to content

Add events to Confluence calendar with API

Do you have a need to allow automation to add events to your confluence calendars? This article will outline how to add simple events to Confluence using the API. This should be pretty straight forward, however the Confluence API does not have specific endpoints for interacting with the Calendar. Atlassian has noted via this feature request they don’t have this functionality on their roadmap, however they’ve posted hints how it could be achieved.

I had a need to schedule week long events for the purpose of assigning on-call rotation forecasting out 6 months. While this could be done manually, it would be much easier to feed a script a list of users, a start date and end date, and allow it to populate. In this article I’ll show the fundamentals of adding a basic event to the on-prem version of confluence. This has not been tested with the SaaS offering.

To begin, we first need a bit of information about the calendar we’d like to add events to. Confluence uses a series of subcalendars and child subcalendars of different types to make up a calendar. So we need to know the child sub calendar ID of the calendar you’d like to interact with. To get this simply navigate to:https://<YOUR_CONFLUENCE_INSTANCE>/rest/calendar-services/1.0/calendar/subcalendars.json

This will give you a JSON array of all the calendars you have access to. Search the output to find the calendar, by name. Once you’ve located the calendar, look at the property subCalendar located under childSubCalendars. You’ll find the id property. This is what we need to interact with it via the API.

If your still not sure if this is the correct calendar, lets take a look at it in depth by looking for events that exist on it. Surely if we can find events using the subCalendar ID, it’s the right calendar. You can find events by going to: https://<YOUR_CONFLUENCE_INSTANCE>/rest/calendar-services/1.0/calendar/events.json?subCalendarId=<SUB_CALENDAR_ID>&userTimeZoneId=US%2FPacific&start=2023-07-30T16%3A06%3A56Z&end=2023-07-10T16%3A06%3A56Z

Again, replace with your URL and insert your subCalendar ID. Optionally you can modify the timezone and start and end dates if you’d like. This will give you an output of events which are on the subCalendar. If these match what you expect to see on the calendar, congratulations! If you’re still not sure, add an event using the traditional confluence interface and then refresh the events output page and find your event in the output.

Now that we have the correct subCalendar ID, we can proceed into the code. I’ve written this in Python, but you can use this as an outline if you want to use something else.

First we import the libraries we need, then we define two functions. The first is to lookup the user and grab their user ID.

import requests
import getpass
import urllib
import json

from datetime import datetime

## Functions ##

def get_confluence_user_id(user):
    r = requests.get(f"{confluence_url}/rest/api/user?username={user}", auth=(username,password))
    user_dict = json.loads(r.text)
    return user_dict['userKey']

The trick to interacting with the calendars it to ensure the parameters are url encoded. We’re essentially going to pass the data to confluence exactly like we would if using the native confluence interface. In Python we can use urllib. Specifically urllib.parse.quote_plus

You can see this in the second and final function which does the work to add an event to the calendar.

def add_oncall_event_to_calender(payload):
    reqUrl = f'{confluence_url}/rest/calendar-services/1.0/calendar/events.json'

    what = urllib.parse.quote_plus(payload['what'])
    startDate = urllib.parse.quote_plus(payload['startDate']) # must be in DD-MMM-YYYY format
    startTime= '' #urllib.parse.quote_plus(arrow.utcnow().format('h:MM A'))
    endDate = urllib.parse.quote_plus(payload['startDate'])
    endTime = '' #urllib.parse.quote_plus(arrow.utcnow().shift(hours=+1).format('h:MM A'))
    allDayEvent = urllib.parse.quote_plus('True')
    where = urllib.parse.quote_plus('')
    url = urllib.parse.quote_plus('')
    description = urllib.parse.quote_plus(payload['description'])
    customEventTypeId = urllib.parse.quote_plus('')
    person=urllib.parse.quote_plus(payload['person'])
    subCalendarId = urllib.parse.quote_plus(payload['subCalendarId'])

    data = f'confirmRemoveInvalidUsers=false&childSubCalendarId=&customEventTypeId={customEventTypeId}&eventType=custom&isSingleJiraDate=false&originalSubCalendarId=&originalStartDate=&originalEventType=&originalCustomEventTypeId=&recurrenceId=&subCalendarId={subCalendarId}&uid=&what={what}&startDate={startDate}&endDate={endDate}&startTime={startTime}&endtime={endTime}&allDayEvent={allDayEvent}&rruleStr=&until=&editAllInRecurrenceSeries=true&where={where}&url={url}&description={description}&person={person}&userTimeZoneId=America%2FLos_Angeles'

    headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    }
    res = requests.put(url=reqUrl,data=data,headers=headers,auth=(username,password))
    print(res.text)

## End Functions

Next we dive into the main part of the code which defines our variables and prompts the user for input. There is no input validation in this proof of concept code. If you are considering user input as a method for your production code, add validation.

## Main ##

# Variables
confluence_url = "YOUR_CONFLUENCE_URL"
CONFLUENCE_SUBCALENDAR_ID = "YOUR_SUB_CAL_ID"

start_date = input("Please enter event start date (YYYY-MM-DD): ")
event_title = input("Please enter event title: ")
event_description = input("Please enter event description: ")
assigned_user = input("Please enter who the event is assigned to(must be valid concluence user): ")

username = input("Please enter confluence account: ")
password = getpass.getpass()

# Get dates from user, in YYYY-MM-DD format. Will be converted to confluence friendly date later
start_date_obj = (datetime.strptime(start_date, '%Y-%m-%d'))
end_date_obj = (datetime.strptime(start_date, '%Y-%m-%d'))

payload = {
    'what':event_title,
    'startDate':(start_date_obj).strftime('%d-%b-%Y'),
    #'endDate':(end_date_obj).strftime('%d-%b-%Y'),
    'description':event_description,
    'person':get_confluence_user_id(assigned_user),
    'subCalendarId':CONFLUENCE_SUBCALENDAR_ID
}
print(f"Scheduling event for {assigned_user}")
#Add event to calendar
add_oncall_event_to_calender(payload)

And that’s it! When ran, this will add a simple all day event to the confluence calendar of your choosing. The output is shown below.

The full code can be found on my github located here: https://github.com/craigsorensen/confluence

Sharing is caring!

Leave a Reply

Your email address will not be published. Required fields are marked *

+ five = thirteen