Using the Discourse API from Python

Tags: #<Tag:0x00007fb7ce60dc08> #<Tag:0x00007fb7ce60da78>

Using the Discourse API from Python

Posting via GitLab

Post via the API

Credential management

A simple Unix-like way to keep the credentials: Generate a dotfile and put user:apikey in the first line. Getting an API key for your discourse user is a straight forward procedure via the settings.

def get_credentitals():
    :return: tupel
    with open(os.path.expanduser('~/.disco.auth')) as f:
        return [x.strip().split(':') for x in f.readlines()]
def main():

    for user, key in get_credentitals():
        disco_user = user
        disco_key = key

Read files that aren't posted

This is obviously the dumbest possible way. Keep the markup (mdfile) in a sub-directory called posts. If it’s not in the status.csv list, it’s not posted… ideally.

def load_and_track_md_post(pfile="", dir="posts"):

    with open(dir + '/' + pfile) as postfile:
        mdpost = ''.join(postfile.readlines())

    with open(dir + '/' + "status.csv") as statusfile:
        posted_list = statusfile.readlines()

    if pfile not in posted_list:
        with open(dir + '/' + 'status.csv', 'a') as status:

    return mdpost

Are there better way to do this… yes.

Posting to Discourse

And this is super simple of course. Use the read credentials from the paragraph above, pass them into the HTTP request using Python 3’s requests, and use the correct meta-data.

  • The category ID is propagated via a URL: https:// + TLD + /c/category_name/show.json - the field is id
  • mdpost is read from the file.
apicreds = {"api_key": disco_key, "api_username": disco_user}
discourl = "" # with the slash on the end

# Now, send a post
post_details = {
    "title": "Title of the new topic",
    "raw": mdpost,
    "category": 9, # get the category ID from the admin
    "archetype": "regular",
    "reply_to_post_number": 0
r = + "posts", params=apicreds, data=post_details)

Using GitLab to post