Skip to content

Instantly share code, notes, and snippets.

@adamsbytes
Created December 28, 2021 22:44
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamsbytes/8445e2f9a97ae98052297a4415b5356f to your computer and use it in GitHub Desktop.
Save adamsbytes/8445e2f9a97ae98052297a4415b5356f to your computer and use it in GitHub Desktop.
Retrieving and creating Discord events with Python

Interacting with the Discord Events API using Python

As of writing this, documentation for the Discord events API is a little lacking and the feature is not yet integrated into Discord.py.

The Basics

This gist presents a basic class that performs a couple event actions against the Discord API.

To interact with the Discord API you need an async http client, for this gist it'll be aiohttp. You'll need a Discord bot created, and to have a token generated for that bot. Your bot will also need event permissions in the guilds/servers you are trying to create events in.

For information on the return content of the list_guild_events() function, see this section of Discord's API docs.

Remember, these functions are asynchronous! They'll need to be awaited, not just called like normal functions. If you're new to that sort of thing, see this guide for details.

The Code

import json

import aiohttp

class DiscordEvents:
    '''Class to create and list Discord events utilizing their API'''
    def __init__(self, discord_token: str) -> None:
        self.base_api_url = 'https://discord.com/api/v8'
        self.auth_headers = {
            'Authorization':f'Bot {discord_token}',
            'User-Agent':'DiscordBot (https://your.bot/url) Python/3.9 aiohttp/3.8.1',
            'Content-Type':'application/json'
        }

    async def list_guild_events(self, guild_id: str) -> list:
        '''Returns a list of upcoming events for the supplied guild ID
        Format of return is a list of one dictionary per event containing information.'''
        event_retrieve_url = f'{self.base_api_url}/guilds/{guild_id}/scheduled-events'
        async with aiohttp.ClientSession(headers=self.auth_headers) as session:
            try:
                async with session.get(event_retrieve_url) as response:
                    response.raise_for_status()
                    assert response.status == 200
                    response_list = json.loads(await response.read())
            except Exception as e:
                print(f'EXCEPTION: {e}')
            finally:
                await session.close()
        return response_list

    async def create_guild_event(
        self,
        guild_id: str,
        event_name: str,
        event_description: str,
        event_start_time: str,
        event_end_time: str,
        event_metadata: dict,
        event_privacy_level=2,
        channel_id=None
    ) -> None:
        '''Creates a guild event using the supplied arguments
        The expected event_metadata format is event_metadata={'location': 'YOUR_LOCATION_NAME'}
        The required time format is %Y-%m-%dT%H:%M:%S'''
        event_create_url = f'{self.base_api_url}/guilds/{guild_id}/scheduled-events'
        event_data = json.dumps({
            'name': event_name,
            'privacy_level': event_privacy_level,
            'scheduled_start_time': event_start_time,
            'scheduled_end_time': event_end_time,
            'description': event_description,
            'channel_id': channel_id,
            'entity_metadata': event_metadata,
            'entity_type': 3
        })

        async with aiohttp.ClientSession(headers=self.auth_headers) as session:
            try:
                async with session.post(event_create_url, data=event_data) as response:
                    response.raise_for_status()
                    assert response.status == 200
            except Exception as e:
                print(f'EXCEPTION: {e}')
            finally:
                await session.close()
@CodingBarber
Copy link

Hi, Thanks for this!

If I wanted the location to be a voice channel, is there a particular way I need to format the event meta data?

@adamsbytes
Copy link
Author

Hi, Thanks for this!

If I wanted the location to be a voice channel, is there a particular way I need to format the event meta data?

Yes! You'll want to do the following if you want a voice channel:
'channel_id': DISCORD_CHANNEL_ID, 'entity_metadata': None

If you want a location, like "The Bar Down the Road":
'channel_id': None, 'entity_metadata': {'location': 'The Bar Down the Road'},

@jvanlint
Copy link

I'm trying to figure out how to send image data to the event from a URL.
Any thoughts?

@Glassmade
Copy link

@adamsbytes First of all thank you for the code implementation the get all events works like a charm.
However, every time I try to send a post to create a scheduled guild event I get "Bad Request".

Here's what I am trying to connect with:

The URL: https://discord.com/api/v10/guilds/GUILD ID/scheduled-events

The headers: {'Authorization': 'BOT TOKEN', 'User-Agent': 'DiscordBot (https://discord.com/api/oauth2/authorize?client_id=CLIENT ID&permissions=8&scope=bot) Python/3.10 aiohttp/3.8.1', 'Content-Type': 'application/json'}

The body: {"channel_id": CHANNEL ID, "entity_metadata": null, "name": "Test", "privacy_level": 2, "scheduled_start_time": "2022-06-01T12:42:12.494638", "scheduled_end_time": "2022-06-02 15:42:12.494638", "description": "Test", "entity_Type": 3, "image": null}

I already changed the version of the endpoint to v10 since I was worried about v08 deprecation, both of them fail tho on the same error.
I know that is not an authorisation problem otherwise the get all events wouldn't work.

I get errors about the body
{"code": 50109, "message": "The request body contains invalid JSON."}

But no clue where my body is breaking, any insights?

@Fortex365
Copy link

Fortex365 commented Aug 26, 2022

@Glassmade

The body: {"channel_id": CHANNEL ID, "entity_metadata": null, "name": "Test", "privacy_level": 2, "scheduled_start_time": "2022-06-01T12:42:12.494638", "scheduled_end_time": "2022-06-02 15:42:12.494638", "description": "Test", "entity_Type": 3, "image": null}

Hello, I do see a problem with your body content. The problem is with "scheduled_start_time": "2022-06-01T12:42:12.494638" same for "scheduled_end_time": "2022-06-02 15:42:12.494638", its bad time format. The time format is Y-%m-%dT%H:%M:%S and it should look like 2022-06-01T12:42:12 without the float in seconds.

Please note, that you need to have valid time to post that request. The time must be ahead of the time what is now. You cannot create event in the past date(time).

import datetime

date = "2022-8-26 17:45:00"
format_from = "%Y-%m-%d %H:%M:%S"
format_to = "%Y-%m-%dT%H:%M:%S"

converted = datetime.datetime.strptime(date, format_from).strftime(format_to)

@yaschk
Copy link

yaschk commented Aug 30, 2022

Could someone help what is the issue?

The URL: https://discord.com/api/v10/guilds/[GUILD ID]/scheduled-events

Headers: {'Authorization': 'Bot [TOKEN]', 'User-Agent': 'DiscordBot (https://discord.com/api/oauth2/authorize?client_id=[CLIENT ID]&permissions=8&scope=bot) Python/3.8 aiohttp/3.7.4', 'Content-Type': 'application/json'}

The body:
{"channel_id": [CHANNEL ID], "entity_metadata": null, "name": "Test", "privacy_level": 2, "scheduled_start_time": "2022-09-10T12:42:12", "scheduled_end_time": null, "description": null, "entity_Type": 2, "image": null}

The error: EXCEPTION: 400, message='Bad Request

@Fortex365
Copy link

Fortex365 commented Oct 1, 2022

@yaschk

https://github.com/Fortex365/Barmaid/blob/main/barmaid/events/scheduled_events.py
You can check this, its rewritten from this thread and it works.

@bufordtaylor
Copy link

I'm trying to figure out how to send image data to the event from a URL. Any thoughts?

https://gist.github.com/adamsbytes/8445e2f9a97ae98052297a4415b5356f?permalink_comment_id=4167514#gistcomment-4167514

I am also having issues getting images to work. Anyone have any lucik?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment