Advanced Zendesk notifications in Slack using Incoming Webhooks

I recently implemented customer satisfaction surveys to my department’s Zendesk instance. The feedback we’re getting out of it is really cool, but I was surprised that the vanilla Zendesk integration for Slack doesn’t have any way to post that feedback. Really the only things you can do out of the box are notifications for ticket creation, closure and other updates.

I started reading about my options and found out about Incoming Webhooks, a feature that Slack makes available that allows you to easily submit messages using HTTP requests. If you’re willing to write a little bit of JSON you can post pretty much anything you want from Zendesk to Slack.

The Incoming Webhooks setup is really a three part process. First thing you need is a place to send these messages to, the Incoming Webhooks integration in Slack will give you a private URL to receive your messages. On the Zendesk side, you create an external target with the Webhook URL. Last, you add this target to a trigger or automation in Zendesk to post what you’re looking for.

Here’s what you will need to get started:

  • A Zendesk account with the Teams plan or higher
  • Administrative access to Zendesk
  • Administrative access to Slack or approval for the Incoming Webhooks integration.

That’s it! Next, I’ll walk you through all of this step by step with examples of what I’m doing in my environment.

1. Set up Incoming Webhooks in Slack

Incoming Webhooks on Slack is just an integration, so jump over to the app directory and search for “Incoming Webhooks”. Go ahead and pull it up and click Add Configuration like this.


It will ask you which channel you want to post to, keep in mind this is only a default. Same with the next page when it asks you to select a name, emoji/icon, etc. All of this can be overridden when you submit a post, but if you sent text only, the defaults will be used. I recommend you set it to direct message your account as a default for testing purposes.


Take note of that Webhook URL, this is what we will need in the next step.

2. Set up your External Target in Zendesk

Now jump over to Zendesk, we’re going to add the Slack Webhook URL as a target to post JSON messages to. From Zendesk, choose Settings > Extensions > Add Target > HTTP target. You should test your target before saving, this is actually the default option from here. Use the code below to send a super simple test message to your default channel.


 "text": "This is a line of text.\nAnd this is another one."




Zendesk should return an HTTP/1.1 200 OK message and you should see that test message appear in Slack. If you get an error instead, jump back to step one and verify your Webhooks URL. Once you have this set, change the drop down to “Create target” and click Submit.

3. Create a Zendesk Automation to post your message to Slack

Zendesk Triggers and Automations are powerful ways to add rules to how your tickets are processed. Now that we have set up the Slack Webhook integration and it’s configured as target in Zendesk, you can add it to any rule.

There are a lot of really good resources to show you how to build Triggers and Automations so I won’t dig into them too much here, I’ll just provide a brief example of what I’ve done for my use case. Instead, I’ll focus more on how to form the JSON messages that Slack can interpret.

If you recall from the beginning, I want to send a Slack notification whenever we receive positive feedback from a customer. The way my Zendesk Triggers are set up, is that when a ticket is solved it sends a closure email that includes link to rate satisfaction. When a user clicks the satisfaction link they are taken to a web page where they can also record a comment.

In my use case I used an automation, here are the settings I used.

Meet all the following conditions:
Ticket: Status > Is > Solved
Ticket: Satisfaction > Greater than > Bad with comment
Ticket: Hours since requester update > (calendar) Is > 0

Meet any of the following conditions:
Ticket: Group > Is > IT Group 1
Ticket: Group > Is > IT Group 2
Ticket: Group > Is > IT Group 3

Perform these actions:
Notifications: Notify target > TheReallyCoolWay Slack Notifications


The first section ensures that we are matching solved tickets updated in the last hour with a positive satisfaction rating (with or without comment). The second section just makes sure the ticket is assigned to any one of my specific IT Groups. If you only have one group, you can ignore that part. The last section, “Perform these actions”, tells Zendesk to send a notification to our Slack target. This opens up a text box for you to enter the JSON message which will appear in Slack. Here’s a really simple example, just fill in the blanks.

    "username": "BotName",
    "channel": "#your-channel",
    "icon_emoji": ":your_emoji:",
    "text": "Nice job {{}}, you got some positive feedback from {{}}!",



Here’s what this notification would look like.


Note, in my example I used some Zendesk Placeholders, this opens up a whole slew of options. This example really just scratches the surface of what you can do. Also take a look at Slack Message Formatting, there’s a lot more you can do with this as well.

4. Making it really cool

So now we have a functioning Zendesk to Slack notification system, but there’s still a lot more we can do with message formatting and Zendesk placeholders. Let’s make it better.

I’d like to add some formatting so that it stands out from a typical Slack message. I’ll also include ticket details like the ticket number and subject, and I’ll also make that whole thing a clickable link to jump straight to it. Last, I definitely want to include the comment if a user provides one.

This is what I ultimately came up with:

    "username": "BotName",
    "channel": "#your-channel",
    "icon_emoji": ":your_emoji:",
    "text": "Nice job {{}}, you got some positive feedback from {{}}!",
    "attachments": [
            "fallback": "<View Ticket - {{}}>",
            "title": "Ticket #{{}}: {{ticket.title}}",
            "title_link": "{{}}",
            "color": "good",
            "text": "{{satisfaction.current_comment}}"



Here’s what the updated notification would look like.


I hope you found this helpful. There’s a ton of power in here to create any kind of notification you can think of, and I’m just getting started with these. I’ve already got similar Slack notifications for vCenter Alarms working, and I plan on doing a follow up blog with details on that. If that’s something that interests you be sure to subscribe. Feel free to comment if you have any questions on setting this up, and thanks for reading!

UPN Suffix Changes – The Cool Way

We’re migrating to Okta in a few weeks and are preparing our domain for the change. Our organization has a legacy “.local” domain and a few different external domains for email. This week we decided to move all of our UPN suffixes from the “.local” domain to our external “.com” domain to prepare. This does a couple things for us – First, we have configured Okta to only recognize that domain for sign in, so it will only import the users we have moved to that domain suffix. Second, it fixes a ton of autodiscover issue we have faced for years as Office 365 users. If you have a “.local” domain, you know what I’m talking about.

So how do we achieve this? You could use the GUI, but the GUI is for chumps, and you don’t want to be a chump do you? The obvious answer is PowerShell, so here’s how you do it the cool way.

Get-ADUser -Filter {userPrincipalName -like '*@OldDomain.local'} -SearchBase "OU=Testing,OU=Users,OU=Company,DC=Domain,DC=local" | ForEach-Object {
    $newUpn = $_.UserPrincipalName.Replace('OldDomain.local','')
    Write-Output "Old UPN is $($_.UserPrincipalName)"
    $_ | Set-ADUser -UserPrincipalName $newUpn
    Write-Output "New UPN is $(Get-ADUser $_ | select -expand UserPrincipalName)`n"

I’ll walk you through this. In the first line we’re getting all AD users within two constraints.

Get-ADUser -Filter {userPrincipalName -like '*@OldDomain.local'} -SearchBase "OU=Testing,OU=Users,OU=Company,DC=Domain,DC=local" | ForEach-Object

The filter looks at all users with the userPrincipalName that includes @OldDomain.local, you would use your old UPN suffix here. The second constraint is the search base, this is saying, “Only look in OU=Testing,OU=Users,OU=Company,DC=Domain,DC=local for users to change”.  From there it uses a ForEach-Object loop to parse through each user meeting these criteria.

$newUpn = $_.UserPrincipalName.Replace('OldDomain.local','')

This first line within the loop defines a variable $newUpn which is equal to $_, ie. that iterations full user principal name, but we’re replacing OldDomain.local with

$_ | Set-ADUser -UserPrincipalName $newUpn

This last line is where the magic happens. You’re piping $_ (The current iteration user) into a Set-ADUser command where we set the UserPrincipalName attribute to that fancy $newUpn variable we saved a step ago.

This iterates for as many users as it finds within that criteria, and I’ve tossed in some output logging just to describe the changes as they are happening. If you’re not into that, just take those lines out.

Now whether you have 10 users or 10,000 users – Powershell is clearly the way to go. It eliminates human error from repetitive steps, and it makes you not a chump. Plus spending time scripting rather than manually changing attributes is just more fun anyway right? Anyway, this is the cool way to achieve this task, but the really really really cool way? That’s making a function. More on that in my next blog post.