Working With Monday.com Via VBA Automation

I’ve been having some fun recently automating a database with Monday.com for a client. I had never used Monday.com, but they were using it and wanted to integrate information from my system into it. So I needed to develop a synchronization mechanism to for the standard CRUD operations (Create, Read, Update, Delete).

Now, the work I’ve been doing is actually part of a Web Application, so programmed in PHP, but I thought to myself that given the work I did on using the Outlook Graph REST API as well as the Google REST API, that what I had achieve in PHP I could translate over to VBA for use in any application of my choosing.

A couple hours later, I had a fully functional Access database capable of querying Monday.com, looking up information, creating entries, updating entries & deleting entries.
 

oAuth and Tokens

Now, I not going to over all the REST API stuff here.  For that I’d refer you to my previous articles/videos:

So, in this article, I’m assuming you have authenticated properly and have a token to work with.

Monday.com oAuth Endpoints
To save you some digging, here are Monday.com endpoints for authentication:

To get your authorization code

https://auth.monday.com/oauth2/authorize

To get your token

https://auth.monday.com/oauth2/token

You can consult the official oAuth documentation for all the details at:

Also note the oAuth implementation of Monday.com appears to be very basic, no means to check a token (besides just using it), no means to renew or invalidate a token. So basically, it implies that once you generate a token it is valid indefinitely. Thus, performing this task manually once or using the token provided in the Easy way (see below) may be the best option and offer you the possibility to completely bypass the need for any oAuth integration whatsoever.

Monday.com Makes Tokens Even Easier!
I should mention that Monday.com makes getting up and running super easy and you can even bypass the whole concept of oAuth if you want. They provide you with a ready made token (Developers->My Access Token) for use in any project you want. Simply copy it and use it in PHP/VBA/… This way you’re up and running immediately and you can revoke the access at any time by simply going back to that same page and Regenerating the token to invalidating the current one.
 

VBA Integration of Monday.com

Querying Monday.com

The first thing to understand with interacting with Monday.com is that everything is done via a query. So you need to create a query, send it to Monday.com and then check the response that is sent back to you.

Luckily for use, once again Monday.com has somewhat helped us with our task of developing our query(ies) by providing us an interface for creating/testing them. They call it the ‘API Playground’ (Developers->API Playground). There you have a query editor to try variations, run, adjust, … Once you have it functional you can then bring it into VBA!

The API Playground permits multiple queries to be created and stored in separate tabs which is really convenient!

The VBA Procedure

Here is a simple procedure framework for working with the Monday.com REST API via VBA.

Public Sub HTTP_SendRequest_Monday()
    On Error GoTo Error_Handler
    Dim oHTTP                 As MSXML2.XMLHTTP60
    Dim sHTTPRequest          As String
    Dim sMondayQuery          As String
    Const sToken = "PutYourMonday.comTokenHere"
    
    'Initialize our variables
    lHTTP_Status = 0
    sHTTP_StatusText = ""
    sHTTP_ResponseText = ""

    'Define the Monday.com REST API query
    sMondayQuery = "query { me { name } }"

    'Finalize the actual REST API request string
    sHTTPRequest = "{""query"": """
    sHTTPRequest = sHTTPRequest & sMondayQuery
    sHTTPRequest = sHTTPRequest & """}"

    'Make the request and get a response back
    Set oHTTP = New MSXML2.XMLHTTP60
    With oHTTP
        Call .Open("POST", "https://api.monday.com/v2")
        Call .setRequestHeader("Content-Type", "application/json")
        Call .setRequestHeader("Authorization", sToken)
        Call .send(sHTTPRequest)

        lHTTP_Status = .Status
        sHTTP_StatusText = .StatusText
        sHTTP_ResponseText = .responseText

        Debug.Print "URL: " & "https://api.monday.com/v2"
        Debug.Print "Request: " & sHTTPRequest
        Debug.Print "Status: " & lHTTP_Status & " | " & sHTTP_StatusText
        Debug.Print "Response: " & sHTTP_ResponseText
    End With

Error_Handler_Exit:
    On Error Resume Next
    Set oHTTP = Nothing
    Exit Sub

Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Source: HTTP_SendRequest_Monday" & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Description: " & Err.Description & _
           Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
           , vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Sub

Running this will then output something like:

URL: https://api.monday.com/v2
Request: {"query": "query { me { name } }"}
Status: 200 | OK
Response: {"data":{"me":{"name":"Daniel"}}}

Normally you are only truly after the sHTTP_ResponseText values, but for illustrative and learning purposes I made the procedure return other information as well.

More Queries You Say

As I mentioned above, everything is query based, so once you have the basic procedure, the only thing you really need to do is switch the query being sent to Monday.com, the rest of the procedure stays unchanged! With that in mind, here are some examples of queries to help you understand and get going.

Identify the Current User

As shown above, we can easily identify the current user with a query like:

sMondayQuery = "query { me { name } }"

but, if you wish, you can also retrieve other information about the current user by simply adding the column(s) of data you wish to retrieve, such as:

sMondayQuery = "{ me { id name birthday } }"

List the Boards

To list all the boards, we could do something like:

sMondayQuery = "query ListAllBoard { boards { id name board_kind } }"

Get a Boards Details

Another useful thing, to be able to work with a board (perform CRUD operations on the items within a board) is to analyze a board and its columns. To do this, we can use a query like:

sMondayQuery = "query ListContactBoardColumns{ boards(ids: [YourBoardId]) { name columns { title id type } } }"

This will permit you to identify the ids of the various columns which is critical to being able to work with them!

List the Board Groups

On a board, we can make groups to better view groupings of data, so break the information down, if we wish to extract a list of these groups and their id (to be able to interact with them further) we can do something like:

sMondayQuery = "query ListBoardGroups{ boards(ids: [YourBoardId]) { groups { id title } } }"

Retrieving an Entry’s Details

So say you have a Contacts board with a listing of contacts. Say you wanted to get a listing of the entries, you could do:

sMondayQuery = "query ListContactsDetailed { boards(ids: [YourBoardId]) { items_page { items { id name } } } }"

or to get more details on each entry, you could do (adjusting for your column names of course):

sMondayQuery = "query ListContactsDetailed { boards(ids: [YourBoardId]) { items_page { items { id name column_values { id column { title } type value text } } } } }"

This will provide you a breakdown of current contacts on the specified board

If, instead of wanting to get a listing of all the entries you wanted to look up a specific entry, say search by First and Last name, you could do something like:

sMondayQuery = "query GetSpecificContactDetailsByName{ items_page_by_column_values( board_id: YourBoardId columns: [{column_id: \""text_mkpeqqsr\"", column_values: [\""Erik\""]}, {column_id: \""text_mkperft3\"", column_values: [\""Higgins\""]}] ) { cursor items { id name } } }"

Where text_mkpeqqsr is the id of my First Name column and text_mkperft3 is the id of my Last Name column.

Enumerate the Entries by Board Group

If instead of just getting a breakdown of the entries of a board, as shown above, we wanted to get a breakdown by group(ing), then we could do something like:

sMondayQuery = "query ListClientsByBoardGroup{ boards(ids: YourBoardId ) { groups{ id title items_page{ items{ id name } } } } }"

Or if you want to only get the breakdown of a specific board then you’d do:

sMondayQuery = "query ListClientsByBoardForASpecificGroup{ boards(ids: YourBoardId ) { groups(ids: \""YourGroupId\""){ \tid title position items_page{ items{ id name } } } } }"

and you could get a breakdown for multiple specific group by simply modifying the above slightly to:

sMondayQuery = "query ListClientsByBoardForASpecificGroups{ boards(ids: YourBoardId ) { groups(ids: [\""YourGroupId1\"", \""YourGroupId2\""]){ \tid title position items_page{ items{ id name } } } } }"

and adding as many Group Ids as you need to the ‘groups(ids:’ section.

Creating a New Entry In a Board

Creating an entry is relatively simple as well, once you know the query syntax.

 sMondayQuery = "mutation { create_item(board_id: YourBoardId, item_name: \""John Doe\"", column_values: \""{\\\""text\\\"": \\\""AYZ Inc\\\"", \\\""text_mkpeqqsr\\\"": \\\""John\\\"", \\\""text_mkperft3\\\"": \\\""Doe\\\""}\"" ) { id } }" 

This will create an entry labeled ‘John Doe’ with a First Name of ‘John’ and a Last Name of ‘Doe’.

Modifying an Existing Entry

To modify an entry we would look up the record to determine the id and then bind to that id to perform the update by doing:

sMondayQuery = "mutation UpdateContactEmail { change_simple_column_value( board_id: YourBoardId item_id: YourContactId column_id: \""email\"" value: \""j.doe@somewhere.com j.doe@somehwere.com\"" ) { id } }"

Deleting an Entry on a Board

Deletion is very straightforward and you only need the id of the entry to delete. The basic syntax would be:

sMondayQuery = "mutation DeleteContact{ delete_item(item_id: YourContactId) { id } }"

Some Final Thoughts

I must say that Monday.com seems to have made initial access to automate things as simple as possible by providing a token directly via your account, bypassing the need of coding any oAuth processes into your project. That said, be very careful how you code/store such a confidential piece of information!

I must also applaud them for the API Playground. This is where I spent the bulk of my time learning things! Once I got thing functional there, migrating to PHP, or VBA, was relatively simple.

Syntax. Well this is one thing that sometimes took a bit to figure out, or look up online. I had issues with their documentation (but that could be just me as it was new to me) and often found it easier to perform and online search to locate a discussion … from which I could learn things, or through trial and error in the API Playground.

PHP/VBA Syntax. Well, if you reviewed the VBA procedure you probably noticed that we set a header to “application/json” indicating that our request must be a JSON string. This is why we have to send strings like \\\”” … I will hopefully do another post on this in the coming days and show you what I did to convert the API Playground query into the required JSON formatted string (as always we have a couple options on this front).

I also found the fact that I could create a free developer’s account which took me 30 seconds to get up and running a huge bonus!

I should also mention, one thing I’d recommend is that whenever you create an entry in Monday.com capture its id in your application as this will avoid any need to look it up again to be able to work with it (update/delete). You’ll simply use the stored id and run your command!

All and all, this was a fun couple of hours and I already have a VBA and a PHP version up and running.

I hope this enables a few of you to have fun working with Monday.com!
 

Page History

Date Summary of Changes
2025-03-31 Initial Release