Loving the new (beta) API!!

spackows ✭✭✭
edited October 2022 in Mural API

I'm having a great time experimenting with the new API that's in beta. (https://developers.mural.co/public/reference/intro) What's everybody else building with it? Here are a few use cases I've been working through:

  • Cluster stickies using NLP, then group them in the mural, and produce a report
  • Read stickies and then summarize/consolidate into a document using NLP
  • Pull status updates from a Slack channel into a mural for review/reflection
  • Automatically save data from team murals into a database every week

Here's a GitHub repo where I started collecting samples:


I'm starting with small pieces and adding more over time.

Does anybody else have examples you've already been experimenting with that you'd share? I know it's still early days for the API, but I'm pretty excited about its potential. 😁



  • Hello Sarah!

    We love that you are loving experimenting with MURAL API and building such cool stuff with it! Thank you for sharing your MURAL API creativity with us - keep them coming!! 😍


  • Hi @spackows

    I am curious how you did authentication to get the auth token in your python scripting.

    I wanted to create stickies in a new mural based on reading github issues through python scripting.

    The api setup guide talks about registering an app, auth through browser and callback urls which I don't know how that works in when using a python script.

  • spackows
    spackows ✭✭✭

    Hi, @CharekC

    Yes, that detail is vague in those notebooks. Sorry! I'll add some comments to the notebooks explaining.

    They way I do it is like this: I deployed a Node.js web app to go through that OAuth 2.0 web app/callback flow to get a token (and/or refresh it.) Then I copy the token into the notebook.

    I happened to have set up the same OAuth flow for other projects before. So I was able to refactor my previous work to authenticate with the MURAL API too. Because of that, it wasn't a lot of work for me. But if you're starting from scratch and just want to kick the tires on the new MURAL API, I recognize that feels like a lot of work.

    On this page, they describe the OAuth flow pretty nicely and there's a link to download a sample app:

    *For anybody who hasn't set up OAuth 2.0 before, knowing how to set that up is a pretty handy thing. Maybe this is a good time to dig into it? If it helps anybody, I'll copy my Node.js authentication app into GitHub too. I'll post a comment here when that's done.

  • Anuj
    Anuj admin

    This is awesome - thanks @spackows!

  • Hi @spackows thank you for the hard work and creating some workflow examples! I'm attempting to run through the OAuth2 workflow purely in python using the Requests-OAuthlib lib: https://requests-oauthlib.readthedocs.io/en/latest/

    I'm following the Web Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#web-application-flow

    I have a dummy redirect URL in the Mural App I created. When I manually call the generated Auth URL I'd expect to go to the Mural Auth page first, but I'm just getting sent straight to my redirect URL. Any thoughts? I realize I may not be able to automate everything in Python but still trying to understand the flow components.

    This is the returned redirect URL (I added the space to stop auto formatting):

    https:// my.dummy.app /?error=invalid_request&state=agGwNyVnZMfMmOOpGbXbbdS3hcKfu1

    So I assume I'm still not doing something correctly to generate the Auth URL since it's adding an error to the redirect URL.

    Here's my basic Python code:


    from requests_oauthlib import OAuth2Session

    import requests

    clientID = "--------" # Get from Mural app creation

    clientSecret = "-----------" # Get from Mural app creation

    baseURL = "https://app.mural.co"

    authBaseURL = baseURL + "/api/public/v1/authorization/oauth2"

    tokenURL = baseURL + "/api/public/v1/authorization/oauth2/token"

    def login():

        mural = OAuth2Session(clientID)

        authURL, state = mural.authorization_url(authBaseURL)

        print(authURL) # I then copy-paste this into the browser



    Any hints to get me started?


  • spackows
    spackows ✭✭✭


    A working Python MURAL OAuth sample would be nice to have... so let's make one. 😁

    Flashback: I remember really struggling to get SAML redirects working with my Python (Flask) apps at first.

    Anyway, I'll read through the docs you link to above and see what I can get working. Then I'll post an update here.

  • Hah just added the scope param and started working :)

    scope= "murals:read murals:write"

    def login():

        mural = OAuth2Session(clientID, scope=scope)

        authURL, state = mural.authorization_url(authBaseURL)

        print(authURL) # Loading this URL in the browser showed the Mural permission page then redirected to my dummy URL with code, scopes and state params

  • rambutan2000
    edited July 2022

    Here's a min/janky example of getting the auth code and token in Python. I set my redirect URL in the Mural app config to http://localhost:8088:


    from http.server import BaseHTTPRequestHandler, HTTPServer

    from urllib.parse import urlparse, parse_qs

    import webbrowser

    import json

    import os

    from oauthlib.oauth2 import BackendApplicationClient

    from requests_oauthlib import OAuth2Session

    clientID = "------------" # Get from Mural app creation

    clientSecret = "------------" # Get from Mural app creation

    baseURL = "https://app.mural.co"

    authBaseURL = baseURL + "/api/public/v1/authorization/oauth2"

    tokenURL = baseURL + "/api/public/v1/authorization/oauth2/token"

    scopes= "murals:read murals:write"

    localHostName = "localhost"

    localServerPort = 8088

    redirectURL = "http://" + localHostName + ":" + str(localServerPort)

    class LocalServer(BaseHTTPRequestHandler):

        keepRunning = True    

        authResponse = ""

        def do_GET(self):

            queryDict = parse_qs(urlparse(self.path).query)


            self.send_header("Content-type", "text/html")


            self.wfile.write(bytes("<html><head><title>Mural Auth Local Redirect</title></head><body>", "utf-8"))

            if "code" in queryDict.keys():

                self.wfile.write(bytes("<p>Mural Authentication Successfull! The script should continue to run automatically.  You may close this window/tab</p>", "utf-8"))

                LocalServer.authResponse = self.path          


                self.wfile.write(bytes("<p>Mural Authentication Error!</p>", "utf-8"))


            self.wfile.write(bytes("<p>" + (json.dumps(queryDict)) + "</p>", "utf-8"))

            self.wfile.write(bytes("</body></html>", "utf-8"))

            LocalServer.keepRunning = False

    def login():

        # Get Auth URL

        os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # Required since our local server is HTTP.  Should implement local HTTPS

        mural = OAuth2Session(clientID, redirect_uri=redirectURL, scope=scopes)

        authURL, state = mural.authorization_url(authBaseURL)


        # Open URL in default browser

        webbrowser.open(authURL, new=1)

        # Start local HTTP server to handle redirect

        webServer = HTTPServer((localHostName, localServerPort), LocalServer)


            print("Starting server")



        except KeyboardInterrupt:


        print("Closing server")


        # We now have the Auth code, now need to get token    

        token = mural.fetch_token(tokenURL, client_secret=clientSecret, authorization_response=LocalServer.authResponse)


        # We now have the token




  • I'm having a go with something - using the API to generate ~200 stickynotes that represent github issues. I'm doing the digital equivalent of getting a machine to auto-cut me a bunch of index cards which i'd throw on a table.

    Basically, I'd like a better organisational view of my repo issues, so I'm trying to use mural as that org tool - there's So.Many.Assumptions I'm making (so the prototype is as brittle as all heck) but as a base thing, I'm doing a 1-way sync of all github issues to a mural. Once they're in mural I move/cluster and just get a better visual representation of relationships using arrows/icons/areas/text, etc.

    If this works, then I'll consider a push-back, but the main idea is that I want a representation of issues that i can visually cluster and organise, so first wave of tooling is 1-way. The staging is:

    • (done!) shove down 150 tickets by hand, cluster - is it vaulable? worth moving to code?
    • (done! but hacky and inefficient) pull new issues into mural, each new issue is tagged and linked correctly
    • (next) resync (apply/remove new tags, change bg colour or some attrib of closed issues)
    • (maybe) retag in mural -> pushback to git
    • (maaaybe) bring in JIRA tickets
  • @tanant Sounds really cool! When you are ready, we will love to see a demo of what you have built.