Cookies

We use analytics to see how the site is used so we can improve it.

Skip to content
Renada

Building a Salesforce style ticket swarm inside HaloPSA with custom runbooks

A walkthrough for HaloPSA admins who want to pull engineers into a Microsoft Teams chat straight from a ticket, using custom runbooks and the Graph API

17 December 2024 25 min watch Connor Fagan

The short version

Renada's Robbie Emerson walks through a custom HaloPSA runbook that recreates Salesforce style ticket swarming, pulling engineers into a Microsoft Teams group chat with one action. It covers the Graph API calls, the new array iteration feature in v2.132, and the limitations you'll hit around external users and message posting.

What you'll take away

  • A create swarm action on the ticket

    One button lets an agent multi select engineers and optionally add the end user, then triggers the whole runbook on save.

  • Array iteration is new in v2.132

    HaloPSA's new iteration function loops through every selected agent and adds each one to the Teams chat individually, so it scales to any number of engineers.

  • Adding the end user kills the dashboard tab

    Teams won't allow tabs on chats that contain external users, so ticking add user to swarm removes the public dashboard link from the chat.

  • A public dashboard stands in for a proper chat link

    Because Graph won't let application permissions post messages into the chat, the runbook adds a website tab pointing at a public HaloPSA report instead.

  • Tenant IDs have to come from somewhere

    Adding a customer contact as a guest requires their Azure tenant ID, which Renada already store against the customer record from their CSP integration.

  • The status field doubles as the queue

    Setting the ticket status to swarm when the action runs is what feeds the my hive dashboard, showing only tickets currently being actively swarmed.

Key insights from the episode

  1. Build the swarm agents field as a multiple select custom field with a dynamic SQL lookup returning the agent's UserID and email address.

  2. Capture the ticket's current agent email separately so the runbook can add them to the chat without listing them in the swarm selector.

  3. Avoid using the ticket summary in the Graph API chat topic, since characters like speech marks or colons can break the JSON payload.

  4. Application permissions on the Graph API chats endpoint block posting messages into the chat, which is why the tab based dashboard exists instead.

  5. Store each customer's Azure tenant ID under Settings, Microsoft details if you want to add external users as guests via the CSP integration.

  6. Set the action's system use to send a webhook or queue an integration runbook, and set the resulting ticket status to swarm so reporting can filter on it.

  7. Keep the public dashboard link limited to non identifiable fields such as customer name and ticket ID, since the generated URL is public facing.

Questions people actually ask

How do I create a ticket swarm in HaloPSA?

Add a custom action to the ticket screen, such as create swarm, with a multi select custom field for agents and a checkbox to include the end user. Set the action to queue an integration runbook that creates a Microsoft Teams chat via the Graph API and adds each selected agent to it.

Why does the Teams dashboard tab disappear when I add a customer to a HaloPSA swarm chat?

Microsoft Teams does not allow tabs on chats or channels that contain external users, so ticking add user to swarm removes the public dashboard tab from that chat. The chat itself still works and the external user is still added as a member.

Can a HaloPSA runbook post messages directly into a Microsoft Teams chat?

Not if you are using application permissions on the Graph API, which is what most custom integrations rely on. Posting into an existing chat body needs delegated permissions acting on behalf of a user, so Renada's runbook uses a website tab linking to a dashboard instead of posting a message.

How do I add an external customer contact to a Microsoft Teams chat from HaloPSA?

You need that contact's Azure tenant ID alongside their email address when calling the Graph API chats endpoint. Renada store the tenant ID against the customer record in HaloPSA, populated from their CSP integration, and pull it in as a variable before adding the guest member.

What HaloPSA version introduced array iterations in custom runbooks?

Array iteration in custom runbooks is new in HaloPSA version 2.132. It lets a runbook loop through an array, such as a list of agent emails, and repeat a set of steps once per item without building out each step manually.

How does the my hive swarm dashboard work in HaloPSA?

It's a report filtered to tickets where the status equals swarm, showing ticket ID, customer, site and other basic metrics at a glance. The action sets the ticket status to swarm when a swarm is created, and agents set it back to in progress once the chat has served its purpose.

Where do I configure the create swarm action in HaloPSA?

Go to Configuration, Tickets, Actions and create a new action with the fields you want, such as a swarm agents multi select and an add user checkbox. On the details tab set the system use to send a webhook or queue an integration runbook, choose your swarm runbook, and set the resulting ticket status.

Full transcript

4,814 words

Read full transcript

Hello, we're back again. It has been almost a month since our last video and for that I must apologise. We've been quite busy and, um, I'm not going to say lacking imagination but I don't just want to throw videos out for the sake of it. Um, so today I am joined by a guest and that guest is the one and only Robbie Emerson. He is the man behind the curtain these days for us at Renada. Um, I'll be honest, I spend majority of my time now on calls day to day, so it is left down to Robbie to essentially have fun and design and create all of our cool workflows and runbooks. And most of the things I now demonstrate, to be fair, are done by Robbie. So it was about time that I got Robby on a call to demonstrate and explain what he's done.

So, um, Robbie, hello. Good day.

Robbie: Hello, yeah. Um, so yeah, today we're going to be looking at swarming. Uh, there was a post on the HaloPSA subreddit on Friday night, um, that explained the concept. And this is something that Salesforce is doing at the moment, that they've just released as a function. And so we wanted to see if we could replicate at least some of that functionality inside of Halo. The ability in Salesforce is a little bit larger. There's a little bit more that they can do, um, but what we've achieved is the ability to create a group and swarm all of the engineers that we need into that ticket and get the ball rolling on the solution.

And as always, Robbie does some really cool work, and I go, well, what we should probably do, and then scope creep basically and make a small 20-minute job a full day thing. But what we've achieved now is really cute, and I really genuinely do like it and can see the use case in it. Now, with Renada, there's me and Robbie, so it's kind of pointless for us, to be honest with you, but someone posted it on Reddit. We like a challenge, and we've—well, I say we've, I've done very little. Robbie has now created this swarm function, which is really cool.

So, um, I'm going to share my screen in a minute. We're going to show you what happens from my perspective if I'm just sat working in Teams. What happens? And then we're going to jump into Halo, show you how it's configured. And as always, there's going to be some documentation attached underneath this video, which we'll put in later on today, um, and also hopefully, fingers crossed, this will soon be in the Halo online repository. And I am doing some testing today with Halo, and if you're watching this on day of release, then it might already be there. But we check the comments below. We'll put in there what's happening. So I'm going to jump in straight away. I'm going to share my screen, um, and I'm going to show you what happens. So let me just share my entire screen over here. Give me a second. Over here, and what you're now seeing is Teams. Okay, so, um, let's assume that my Teams is always this quiet and empty, um, and I'm just sat working away. So what Robby will do on his side is he will initiate a swarm. And we'll show you what this looks like in Halo in a minute. Yeah, so I'm going to hit that now, and it should be coming through any second. And there we go. I have a notification for a new chat. And if I click it, it will have Swarm for Ticket 502. That is the header we've put on this, um, for this. So that is ticket ID number 502, um, and if I click on the participants, you will see it is me, Robbie, and our break glass account, who is an agent inside of Halo. And what we've also done—this is kind of the nice part about this—is we've added a website URL, which basically takes us to a public-facing dashboard if I could speak, which looks like this. It says My Hive. These are all the swarmed tickets in our instance. And you'll see here the function is we can open the ticket. And we've put some basic metrics: so ticket ID, customer, site, et cetera, et cetera, um. We've put this in to demonstrate the fact we could have, oh sorry, more ticket data. So depending on what you want your dashboard to be like for this, you can add stuff in. This is just an example, probably not overly useful, but the idea is you can at a glance from a swarm get insights of that ticket, or what it is. I can then simply click Open Ticket, and that will then take me over to Halo. Now, you won't see this at the minute. It's on another tab, but essentially that is what happens. And with that being said, um, I really like it. The ability that we can then quickly go in chat about the problem, jump in and out of the chat as we need to, and hopefully get a resolution as quick as possible.

Now, there obviously is functionality inside of Halo such as mentions, but then you're relying on a notification or an email trigger. You've then got to go to the ticket chat. Isn't really that possible unless you're using the chat in Halo or adding notes. And again, this is just a nice way to quickly gather colleagues. And again, with remote working, we could be different ends of the country and have a quick conversation about that ticket. So Robbie, over to you, sir.

Robbie: Yeah, cool. So I'm going to take over and share my screen. Cool. So I'll first show you from an engineer's perspective, uh, what they would do in order to trigger a swarm, um, so we've got this ticket here, um, which is currently in progress, and we've got the user that's there for the ticket as well. And I can click on a button at the top here called Create Swarm. And what that button does is gives us the option to select the agents that we want to swarm to the ticket. And this is a multi-select, so we can select whichever agents we want to add to that swarm. And then we do have the option to add the user to the Swarm as well, uh. If you add a user to the Swarm, unfortunately, the ticket dashboard disappears, uh, that's due to a limitation inside of Teams, um, which doesn't allow us to have tabs in Teams which have external users or channels which have external users, um. Once we hit save, it will trigger the automation. It will also change the status to Swarm. And we'll see that the runbook has been queued. And after a few seconds, we'll see that an automation is written back to the ticket that a swarm has been created by me.

And just to jump in there as well, um, the report that we showed a minute ago on the dashboard was basically all tickets where the status is Swarm.

Robbie: Yeah, so the idea is you come in, you swarm, then you put the status back to In Progress. Swarm should be a very—is actively being swarmed—is the idea, um. You could put Swarmed or Swarm, whatever you like, but that is how the report then reflects and only shows you tickets you need to see.

Yeah, yeah, absolutely. So how does this all work? Well, I'll show you the integration runbook first, and then I'll quickly show you the action that we're using to trigger it. So firstly, we've got our integration runbook. And if I go to the flowchart, you'll see it looks a little bit overwhelming at first, but really what we're doing is collecting information about the ticket and then triggering a chat to be created. And then we're using the new iterations function in Halo to iterate through each agent, um, in that multi-select field and add them to the chat as well. So if you had 20 agents, it will add each one individually.

So we start off with getting the ticket details. And almost all of our runbooks, we start off with this phase. We are using an integration method. And what we do is we, um, we have an authentication and we have a, uh, sorry, I'll start again. What we do is we have a custom integration that is linked to our Halo instance. And then we use methods to really, uh, easily define exactly what information we want to pull out there. There are such things as Halo API actions now in integration runbooks. Um, they're a little bit less flexible than building it out yourself, and so we've gone the route of building it out ourselves. It's not too difficult to do that, um. It just takes a little bit of work, which again, we've got some documentation on.

So the first thing we're doing is we're doing this Get Ticket Details, uh, request. And we're outputting the Swarm Agents into an array. And that's really important because we'll use the array later. We're getting the user's email address. And that's the user's email on the ticket. And we're grabbing the summary of the ticket as well.

For the Swarm Agents, I've created a custom field which, uh, is a selector of all those engineers. Again, we'll have documentation on how to do that, but that's a dynamic SQL lookup of all the agents in Halo that have an email address, um, and then we display that.

So next, we're going to get the agent's email. And what we're doing here is we're getting the ticket's agent ID and we're outputting the agent's email address. We have to do that because otherwise, we'd have to select the agent to add themselves into the agents to swarm, which is a little bit silly. Um, so this way we can, uh, grab the agent that is logged to the ticket. So this will always create the chat as the agent that is currently assigned that ticket. And again, this is a get request. So we're simply getting to our Halo instance, and we're looking at the agent and then the ticket's agent ID, grabbing the agent's email address, and then storing that as a string.

Next, we're going to create the chat. So this is where we need to create an authentication and a custom integration method to our Office 365 instance. Again, we've created some documentation around this, um, because you need to, uh, we've got the specific permissions that are required here as well, um. But we need to connect to our Office 365 tenant and then we're going to query the Graph API, and specifically the chats API, to send a post with a body that contains the following information.

So we're creating a group chat. The topic is Swarm for Ticket, and then the ticket ID. We're not using the summary in here because you can use certain characters which will break the JSON, um, so you, if, uh, for example, the ticket had a speech mark in it, it can cause some problems with the JSON there. And then for the members, we're starting by just adding the agent in, and then as I mentioned, we're going to use an iteration to add all the other users. So here we're just adding the agent's email address. And this agent email variable is one which we captured earlier.

And finally, we're outputting the Chat ID to a string. And that, again, is the response ID. And the Chat ID is really important for adding all the users in afterwards.

So if we close that, finally, before we add all the rest of the agents, we're adding a tab to that chat. And that was that dashboard you saw earlier. So if we edit this step, we can see we're doing another post request. And we're doing this to the Graph API again. And we're using that Chat ID that we captured earlier. And we're sending it to the tabs endpoint.

The body of this request is a display name, so we use Ticket and Ticket ID. So you saw Ticket 502 earlier. The Teams app ID is a, uh, is specifically the Microsoft Teams Space tab dot web, which is a website. And the website URL and content URL are the same. And for this, we're using that dashboard that we created earlier, uh. You can link directly to the ticket ID here, um, but it doesn't always display properly in Teams, which is why we went down the route of a dashboard. And we found that we can again potentially provide some much more useful information by providing a dashboard there.

What I will do in the documentation is provide you the SQL for the report that we used on that table in the middle showing you the information. Unfortunately, I can't provide you all the JSON for the dashboard because they rely on reports which then they have IDs linked, so it would be an absolute nightmare to try and get across to you in a workable fashion. So I'll just give you the SQL for that, um. Just note though, and just be conscious of this when you're doing this: the URL we're generating there is a public link. So you'll notice on the dashboard that I made there was no information there that was identifiable other than the customer name and a ticket ID, um. So again, just be conscious. If somehow this URL gets out there, maybe don't show the full message trail because there could be anything in there—confidential or even GDPR-related. We've just gone with the customer name and the ticket ID. And that, for me, was fine because when you open it, you have to be authenticated to view the ticket details. Again, it's very, very unlikely anyone's ever going to find this URL, but on the side of caution is my advice on that one.

Yeah, absolutely. Um, so once we've, uh, captured—or created the tab, sorry—the next thing that we're going to do is a new function which only exists in version 1.2132 in Halo. And that is the ability to create iterations in our custom runbooks.

So an array iteration takes an array which we created earlier. So when we captured the ticket details, we created an array of all of the agents that we're going to bring into the Swarm. And so what we do is we start an array. And the array that we're, uh, iterating through is the Swarm Agents array. We're going to start the array, and we're going to capture the response name. And that gives us the email address of each agent.

The next step is to add the agent to the chat. So if we edit this method, we can see in the body that we're adding the agent email in here. And again, we're just adding a new member to that chat. The role here is, uh, as far as I know, is only owner, um, in a group chat. Um, with channel messages or channels, you can have different types of members, but with group chats, you can only have owner. Um, so we're adding in each agent. And then you can see the final step is to start the next iteration. So you'll see here we're starting with the iteration of the Swarm Agents, adding each one in, and then moving around and iterating to the next one.

So once we've finished iterating through the Swarm Agents array, we then run a check. And that check is going to check to see if we've ticked the box that says Add User to Swarm. As you saw earlier on our action, we had a little checkbox that said Add User to Swarm. And if that is equal to yes—so if the checkbox has been checked—we're going to go and do some extra steps. And those extra steps involve getting the user's tenant ID and then adding the user to the Swarm.

So firstly, when adding a guest, we have to also provide the tenant ID of the user that's being added. So what we'll do here is we're going to query the Halo API again, and we're going to get the ticket's client ID, include all of the details in the request, and then output the user's tenant ID. So if we go to Output Variables, we're capturing Azure Tenant ID as a string. And we're capturing the response's Azure Tenant's Azure Tenant ID, uh. This is capturing the first of those tenant IDs. If you do have customers with multiple Azure tenant IDs, you might need to add some additional logic in here, but for most people, they've only got one.

The next step is we're going to add the user to the Swarm. And so we've created a new method for that, which again queries the—or posts to the—Graph API chats endpoint. We're using that Chat ID that we had earlier. And we're adding another member.

And if we go to the body, you'll see there's a couple of differences here. Main one being the tenant ID is added using that variable that we created a moment ago—the Azure Tenant ID. So we're also grabbing the user's email address, um, which we do at the very start when we capture the ticket details, and adding in their tenant ID.

Once that's been done, or if that condition is not met—so if you're not adding the user—um, the next stage is it will move to update the ticket. And we're using a Halo API action just because this is typically the easiest way to do it. And we are posting the JSON body to the ticket ID with the outcome of Team Swarm done by the automation user. Again, this can be anyone here, but done—I like to show that it was an automation that did that. It's hidden from the user, so the user doesn't see this on the ticket. Again, that's optional, but that was what we decided was best. And then the note HTML just shows that the Swarm was created by my email address or me.

And again, just to add to that as well, so if you wanted to demonstrate to your customers that you were creating swarms, you could have it shown on the portal. You could have even send out an email if you wanted to, saying, ah, we have swarmed the team around this, you know, we are addressing this as a high priority. And again, depending on your desk and your service levels, swarms may only be able to be invoked by certain people. So you can hide the actions. I won't get into the weeds of that today, but I don't imagine creating a swarm in this fashion will be available to everyone all the time. That could be a nightmare. But again, training and stuff. So yeah, just that comes down to you. We've just said for this use case, don't show it, um, yeah, but again, that's up to you.

And just to clarify, with us, for my sake, are we saying then that if we want to add in users, we have to have a mechanism to gather all their tenant IDs? Like the CSP integration?

Robbie: Yeah, we do, unfortunately, um. Obviously, in this instance, we've already got it because it's stored in the CSP integration, um. But in order to use this with a user, we do have to add their tenant ID, which means we have to be storing it, um. Where we are storing it is specifically, again, because this has come from the CSP integration, we're storing it at the customer level. And if we go over to settings and scroll all the way down, we have Microsoft Details. And we have that Azure Tenant ID for that test demo Azure Tenant, um. So the only way to do this properly is if we can capture that tenant ID in there.

So finally, the last thing to show you is how to create this action and trigger this action. Um, or have this action trigger the runbook that we want to run. So if we head over to Configuration and go to Tickets and Actions, what we've done is created an action called Create Swarm.

If we open that up and go to the Field List first, we've got two fields on there. We've got Agents to Swarm to the ticket with our CF Swarm Agents field. And our Add User to Swarm field, with CF Add User to Swarm. These have been created via custom objects. And if we go to Custom Objects, Custom Fields, I'll just show you this one because this one is the most important one.

If we look at our custom field Swarm Agents, this is a dynamic lookup. Super easy to create. But what we need to do is create a new multiple select custom field with the lookup type of Dynamic SQL. And the stored script is simply the UN Num as the ID—so the agent's ID is the ID—and their email address, which is their U Active D, um, as their display. So that is what's going to show to you when you select them. We're using the email address directly here just to make it a lot easier to, um, to run through this. You could show names here, but we'd have to have an extra couple of steps to take each agent and go and get their email address, um, instead of just displaying it as an email address. So we decided to do that.

Once we've added those fields to the action, we then also want to go to the Details Tab. And we're doing two things here. We're setting the system use as Send a Webhook or Queue an Integration Runbook. And the runbook that we're running is our Create Swarm runbook. And then finally, we're setting the status as Swarm or Swarmed, um, once the action has been completed, um. And that is really it in terms of configuration. Obviously, we need to add this into any workflows that you want to use it at the right stage that you want to show it on, um, but we won't cover that here for now.

We can just see that on our ticket, we've got the option to Create a Swarm. We can add the agents in. And if we wanted to, we can add the user in. If I hit Save on that, we should see that another one gets created. I'll just demonstrate as well. If we do that, we also get the external user added to the chat. But we do lose that option of having, um, the link to the chat, or the, uh, the link to that dashboard, um, on the chat, again because of limitations in Microsoft Teams.

And if you're nice to your staff when you're building this, don't do it on a weekend and test this about 30 times, because your Teams will slowly blow up and it will drive you slightly insane, um. But jokes aside, um, thank you, Robbie, for obviously doing this at the weekend. There's obviously no expectation on my side, just to be clear, that this is something that we have to do on the weekend. But again, we really like seeing these challenges or even solutions that the community has and see if we can come around it and work something into it, um. Again, this is a little bit rough on the edges. I appreciate that, um, but this is kind of the best we can do with the limitations really on the Teams API side.

Connor: To be honest, we've tried all sorts of, you know, embedding the URL in the summary, but then realised that like colon breaks it, so that doesn't work. We've tried, you know, embedding the ticket URL straight in there, but you can't get past the authentication screen. So we tried a few different things already, and again it increases our understanding. But yeah, we're going to end the video there today. Um, thank you very much, Robbie, once again.

In the description of the video below will be links to a few documentation pages. We'll give you the SQL of the report I use. We'll give you the JSON of Robbie's amazing runbook. Um, we'll link you to our guide on how we would rebuild this. Um, again, as I mentioned in a few videos ago, we're trying to document now all the stuff we do, not just for you, but for ourselves as well, right?

And that's it from me. Anything else, Robbie, before we depart for the day?

Robbie: No, that is everything. Um, the only other thing which I'll just mention quickly is the way in which we're adding the reason we're adding the tab in the first place is because there's a limitation in the Microsoft Graph API that doesn't actually allow us to post messages into that chat. Um, because we're using application permissions, so because this isn't working on behalf of a user, um, we can't post messages into that chat. Um, again, that's just a limitation on Microsoft side. If Halo build this natively, they can get around that because they could use delegated permissions, um, I believe. Um, and then post to the chat body, I think they could probably do that. Um, you'll know a lot better than me. So yeah, cool, I will uh end it there.

Connor: Thanks very much, everyone. Hope you've enjoyed the video. Um, any feedback please put it below. Um, have a beautiful day. I've been Connor. Take care. Bye-bye.

I first found Connor whilst browsing YouTube. The team have been fantastic.
Kero Google Logo

Our Core Services

Offering support to enable sustainable success for your organisation.

Consultation Harness the transformative potential of an agnostic advice tailored to your unique business needs. From PSA implementation to ongoing support, our exceptional consultation services pave the way for extraordinary success. Find out more
Virtual Admin Let us handle the technical heavy lifting. Our expert team builds solutions, creates powerful reports and dashboards, and develops automated integrations - giving you more time to focus on what matters most: your clients. Find out more
Product Onboarding We understand that the first steps in adopting a new product can be daunting, we are here to guide you through every stage of the process with precision and clarity. From initial setup to advanced features, maximise the value of your product from day one. Find out more
Virtual Chief Technology Officer (vCTO) Benefit from a remote and adaptable technology expert to seamlessly combine strategic guidance and effective leadership to propel your business to new heights and empower your organisation’s technology ability. Find out more
Where to next? Get the cutting-edge tools to support your MSP business. Contact us today to receive a bespoke quote tailored to your specific needs.