Rally Software

Creating a Webhook in Agile Central

By David LeDeaux posted 01-25-2019 03:00 AM


Last week, I put together an article introducing webhooks.  This week we'll be covering creating your first webhook.  Creating a webhook is going to require working with our REST API.  It's a good idea to skim through our webhooks documentation page to get an idea of the topics discussed there as it will go into much more detail than this post will.



You'll need to identify a few things prior to generating our webhook:

  1. Tools
  2. Match Expression
  3. Target URL



We'll be interacting with a REST API, so it's helpful to have a client that can craft these HTTP requests with the various methods needed to handle our CRUD operations.  Some people really like , however my "go to" REST client lately has been a little Chrome extension called RESTlet Client so my examples will be using that tool.  Regardless of which tool you use, the concepts are generally the same.


We'll also need a target URL to deliver a webhook to.  Now, we're not going to be turning around and doing anything with this payload, so a simple visual indicator of delivery is all the proof we need that the webhook is firing successfully and when we expect it to.  For that, I like to use Webhook Inbox.  Webhook Inbox is a free and simple tool to use.  You simply click one button and it gives you a unique URL to point your webhook to and it shows you the incoming webhooks in real time.  The catch with this is that is only stays active for about a day so it's only useful for debugging purposes.  You'll need to request a new URL and update your webhook if you come back to this a few days later.


Match Expression

Expressions will be the fine grained rules that we use to match on.  They'll usually use some form of "key", operator and value.  For example, you might choose to specify a project in your expression so that if a work item is modified in that project, we'll trigger a webhook.  I like to keep things simple, so I usually create a webhook that fires when one particular work item is modified.  That's not useful in a production scenario, but for this example we'll keep it simple and we'll fire whenever US58 is updated.


Target URL

This is the destination for the payload to be delivered.  This payload will always come from our datacenters, but the destination is up to you.  It could be a server listening for requests behind your firewall, it could be a serverless function call in AWS, or it could be a third party service like Zapier or Flowdock.  This target URL will typically be a unique destination designed to accept calls for a specific webhook.  I like to use a webhook test site like Webhook Inbox to test the validity of my expressions prior to moving the webhook target into its production URL and in this case, you probably already have a Webhook Inbox set up.



Before jumping into the nuts and bolts, it's important to explain the relationship between HTTP methods and CRUD operations in a RESTful interface.  In general, there are four HTTP methods that get used to indicate different actions to perform with a target; GET, POST, PATCH/PUT, DELETE.  Not all targets will support all operations because it's not always relevant and in some RESTful implementations, POST and PATCH or POST and PUT are used interchangeably.


Our WSAPI interface is an example where the calls can use POST or PUT interchangeably to modify an artifact, however with our Pigeon API, PATCH is required to modify.

HTTP MethodCRUD Action


Creating a Webhook

In order to create a webhook, we're going to use the POST method and we'll be calling the Pigeon API endpoint directly at https://rally1.rallydev.com/apps/pigeon/api/v2/webhook 


In the next section down we have two areas that we want to populate; headers and body. 

Headers are going to contain information about what we're sending to the server to create the webhook.  In this case we want to tell it that'we sending a Content-Type of application/json.  If you're not already logged into Agile Central, then you'll need to click "Add Authorization" to add your username and password to the request.


Body, is going to be the message that we send to the API.   For our basic example, our body will consist of the following JSON payload:

"AppName": "DavidL WebhookInbox Integrations",
"AppUrl": "http://api.webhookinbox.com/i/EF1aKWbX/in/",
"Name": "DavidL WebhookInbox Integration",
"TargetUrl": "http://api.webhookinbox.com/i/EF1aKWbX/in/",
"ObjectTypes": ["HierarchicalRequirement"],
"Expressions": [{
"AttributeName": "FormattedID",
"Operator": "=",


Then we click the "Send" button and we should get back a response from the server with a 200.


The response body is going to contain a lot of valuable information and it's a good idea to keep this around while you're working on getting the webhook set up.

"LastUpdateDate": "2019-01-21T22:37:10.360Z",
"Expressions": [
"AttributeID": null,
"AttributeName": "FormattedID",
"Operator": "=",
"Value": "US58"
"SubscriptionID": 209,
"LastWebhookResponseTime": null,
"_ref": "https://rally1.rallydev.com/apps/pigeon/api/v2/webhook/65016026-b215-4611-b802-c1acd7b37640",
"ObjectTypes": [
"LastSuccess": null,
"LastStatus": null,
"_type": "webhook",
"OwnerID": "2d8dc501-829f-4564-bfd9-REDACTED",
"FireCount": null,
"TargetUrl": "http://api.webhookinbox.com/i/EF1aKWbX/in/",
"CreatedBy": null,
"_objectVersion": 1,
"Disabled": false,
"Security": null,
"ErrorCount": null,
"Name": "DavidL WebhookInbox Integration",
"LastFailure": null,
"AppName": "DavidL WebhookInbox Integrations",
"ObjectUUID": "65016026-b215-4611-b802-c1acd7b37640",
"CreationDate": "2019-01-21T22:37:10.360Z",
"AppUrl": "http://api.webhookinbox.com/i/EF1aKWbX/in/"


The _ref line is very valuable for coming back to this webhook for checking on the status or for making modifications later on so copy that out to a file.


Now, we simply go back to US58 and make a small change while watching our Webhook Inbox.  If everything was set up correctly, you'll see the webhook appear within a few seconds in your inbox:


Modifying a Webhook

Let's say you made a mistake and instead of firing on US58, you actually wanted it to fire on US59.  This is where that _ref URL comes in handy.  Take that URL and paste it into the address bar of the query, and change your METHOD to PATCH.


Then, down to the body of the request and simply change the value down there


Click Send, and you'll see the Expressions section has been updated to US59:


This method of updating works for updating any part of the payload, including target URLs, object types, expressions, etc.


What's Next

In the next installment, I'll be going over how to tie a webhook into a serverless technology for further processing and data manipulation.