Subscribe to Visual Studio Online events from another service

The service hooks feature is in preview. Learn more

Use the REST APIs to programmatically create subscriptions that notify your service when a specific event occurs in a team project. For example, create a subscription to notify your service when a build fails. When a user signs up for your service, you can let them choose what notifications they want and then create the subscriptions for them so that they don't have to set them up manually.

These are the events that you can subscribe to for a team project in a Visual Studio Online account:

  • build completed
  • code pushed (Git team projects)
  • code checked in (TFVC team projects)
  • work item created
  • work item updated
  • comments added to work item

You can filter these events. For example, you can filter the build completed event based on the build status.

Service hook publishers provide these events. Service hook consumers provide the actions that you can choose to take when events occur. You create a subscription that specifies the event, the consumer and the action.

Create a subscription for a team project

To create a subscription for an event, you choose which consumer to use and the action you want to take. You send an HTTP POST request to the subscriptions URL for the Visual Studio Online account with the event, consumer and action to take for the subscription.

Before you begin

You will need this data:

  • team project ID (Use this REST API to get the project id)
  • event settings (find these here including the filters for events)
  • IDs and settings for for the consumers and actions (find these here)

Authorize access

Use OAuth 2.0 to authorize access for your service to use the REST APIs for a user. Use the authorization token to get the team project id and set up the subscriptions for the team project. You will use this access token in the authorization header for your HTTP POST request.

Include this in the header for your request to use the token for authorization:

Authorization: Bearer <access_token>

Create the request

Construct the body of the HTTP POST request to create the subscription based on the team project id, event, consumer and action.

Here's an example of the JSON string for a subscription request to subscribe to an event that sends notification when the Continuous Integration build fails. It uses the Web hooks consumer to send an HTTP request containing a JSON object that represents the event to the URL in setting1 (https://myservice/event).

{
    "publisherId": "tfs",
    "eventType": "build.complete",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "publisherInputs": {
        "buildStatus": "failed",
        "definitionName": "Continuous Integration",
        "projectId": "56479caf-1eeb-4bca-86ab-aaa6f29399d9",
    },
    "consumerInputs": {
        "setting1": " https://myservice/event"
    }
}

Secure HTTPS URLs are recommended for the security of the private data in the JSON object.

This is the response:

{
    "id": "74aeeed0-bf5d-48dc-893f-f862b80987e9",
    "url": "https://{account}/DefaultCollection/_apis/hooks/subscriptions/74aeeed0-bf5d-48dc-893f-f862b80987e9",
    "status": "success",
    "publisherId": "tfs",
    "eventType": "build.complete",
    "consumerId": "webHooks",
    "consumerActionId": "httpRequest",
    "probationRetries": 2,
    "createdBy": {
        "id": "00ca946b-2fe9-4f2a-ae2f-40d5c48001bc"
    },
    "createdDate": "2014-03-28T16:10:06.523Z",
    "modifiedBy": {
        "id": "1c4978ae-7cc9-4efa-8649-5547304a8438"
    },
    "modifiedDate": "2014-04-25T18:15:26.053Z",
    "publisherInputs": {
        "buildStatus": "",
        "definitionName": "",
        "hostId": "17f27955-99bb-4861-9550-f2c669d64fc9",
        "projectId": "56479caf-1eeb-4bca-86ab-aaa6f29399d9",
        "tfsSubscriptionId": "29cde8b4-f37e-4ef9-a6d4-d57d526d82cc"
    },
    "consumerInputs": {
        "url": "http://myservice/event"
    }
}

If the subscription request fails, an HTTP response code of 400 will be returned with a message that has further details.

What happens when the event occurs?

When the event occurs in Visual Studio Online that has a subscription, the consumer action in the subscription will be performed. View the data that will be returned as a JSON string for each event here.

Your service needs to handle the action and performs any necessary tasks based on the data sent.

Q&A

Q: Are there services that I can subscribe to manually?

A: Yes. Here are the services that you can subscribe to from the administration page for a team project.

Q: Are there C# libraries that I can use to create subscriptions?

A: No, but here's a sample to help you get started.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Mvc;

namespace Microsoft.Samples.VisualStudioOnline
{
    public class ServiceHookEventController : Controller
    {

        // POST: /ServiceHookEvent/workitemcreated
        [HttpPost]
        public HttpResponseMessage WorkItemCreated(Content workItemEvent)
        {
            //Grabbing the title for the new workitem
            var value = RetrieveFieldValue("System.field", workItemEvent.Resource.Fields);

            //Acknowledge event receipt
            return new HttpResponseMessage(HttpStatusCode.OK);
        }

        /// <summary>
        /// Gets the value for a specified work item field.
        /// </summary>
        /// <param name="key">Key used to retrieve matching value</param>
        /// <param name="fields">List of fields for a work item</param>
        /// <returns></returns>
        public String RetrieveFieldValue(String key, IList<FieldInfo> fields)
        {
            if (String.IsNullOrEmpty(key))
                return String.Empty;

            var result = fields.Single(s => s.Field.RefName == key);

            if (result == null)
                return String.Empty;

            return result.Value;
        }

    }

    public class Content
    {
        public String SubscriptionId { get; set; }

        public int NotificationId { get; set; }

        public String EventType { get; set; }

        public WorkItemResource Resource { get; set; }

    }

    public class WorkItemResource
    {
        public String UpdatesUrl { get; set; }

        public IList<FieldInfo> Fields { get; set;}

        public int Id { get; set; }

        public int Rev { get; set; }

        public String Url { get; set; }

        public String WebUrl { get; set; }
    }

    public class FieldInfo
    {
        public FieldDetailedInfo Field { get; set; }

        public String Value { get; set; }

    }

    public class FieldDetailedInfo
    {
        public int Id { get; set; }

        public String Name { get; set; }

        public String RefName { get; set; }
    }
}