Get started with the REST APIs

Integrate your app with Visual Studio Online using these REST APIs. These APIs follow this pattern.

VERB https://{account}.VisualStudio.com/DefaultCollection/_apis[/{area}]/{resource}?api-version=1.0-preview

Notice that the version of the API is specified.

For example, here's how to get a list of team projects in a Visual Studio Online account.

curl -u {username}[:{password}] https://{account}.VisualStudio.com/DefaultCollection/_apis/projects?api-version=1.0-preview

If you don't have a Visual Studio Online account, you can set one up for free.

We're using basic authentication for now, which requires that you enable alternate credentials. We'll look at how to use OAuth later.

Responses

You should get a response like this.

{
    "value": [
        {
            "id": "eb6e4656-77fc-42a1-9181-4c6d8e9da5d1",
            "name": "Fabrikam-Fiber-TFVC",
            "url": "https: //fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/projects/eb6e4656-77fc-42a1-9181-4c6d8e9da5d1",
            "description": "TeamFoundationVersionControlprojects",
            "collection": {
                "id": "d81542e4-cdfa-4333-b082-1ae2d6c3ad16",
                "name": "DefaultCollection",
                "url": "https: //fabrikam-fiber-inc.visualstudio.com/_apis/projectCollections/d81542e4-cdfa-4333-b082-1ae2d6c3ad16",
                "collectionUrl": "https: //fabrikam-fiber-inc.visualstudio.com/DefaultCollection"
            },
            "defaultTeam": {
                "id": "66df9be7-3586-467b-9c5f-425b29afedfd",
                "name": "Fabrikam-Fiber-TFVCTeam",
                "url": "https: //fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/projects/eb6e4656-77fc-42a1-9181-4c6d8e9da5d1/teams/66df9be7-3586-467b-9c5f-425b29afedfd"
            }
        },
        {
            "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c",
            "name": "Fabrikam-Fiber-Git",
            "url": "https: //fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c",
            "description": "Gitprojects",
            "collection": {
                "id": "d81542e4-cdfa-4333-b082-1ae2d6c3ad16",
                "name": "DefaultCollection",
                "url": "https: //fabrikam-fiber-inc.visualstudio.com/_apis/projectCollections/d81542e4-cdfa-4333-b082-1ae2d6c3ad16",
                "collectionUrl": "https: //fabrikam-fiber-inc.visualstudio.com/DefaultCollection"
            },
            "defaultTeam": {
                "id": "8bd35c5e-30bb-4834-a0c4-d576ce1b8df7",
                "name": "Fabrikam-Fiber-GitTeam",
                "url": "https: //fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c/teams/8bd35c5e-30bb-4834-a0c4-d576ce1b8df7"
            }
        }
    ],
    "count": 2
}

The response is JSON. That's generally what you'll get back from the Visual Studio REST APIs, although there are a few exceptions, like Git blobs.

Now you should be able to look around the specific API areas like work item tracking or Git and get to the resources that you need. Keep reading to learn more about the general patterns that are used in these APIs.

HTTP verbs

VerbUsed for...
GETGet a resource or list of resources
POSTCreate a resource
Get a list of resources using a more advanced query
PUTCreate a resource if it doesn't exist or, if it does, update it
PATCHUpdate a resource
DELETEDelete a resource

Request headers and request content

When you provide request body (usually with the POST, PUT and PATCH verbs), include request headers that describe the body. For example,

POST https://fabrikam-fiber-inc.VisualStudio.com/DefaultCollection/_apis/build/requests
Content-Type: application/json
{
   "definition": {
      "id": 3
   },
   "reason": "Manual",
   "priority": "Normal"
}

HTTP method override

Some web proxies may only support the HTTP verbs GET and POST, but not more modern HTTP verbs like PATCH and DELETE. If your calls may pass through one of these proxies, you can send the actual verb using a POST method, with a header to override the method. For example, you may want to update a work item (PATCH _apis/wit/workitems/3), but you may have to go through a proxy that only allows GET or POST. You can pass the proper verb (PATCH in this case) as an HTTP request header parameter and use POST as the actual HTTP method.

POST _apis/wit/workitems/3
X-HTTP-Method-Override: PATCH
{
   (PATCH request body)
}

Response codes

ResponseNotes
200Success, and there is a response body.
201Success, when creating resources. Some APIs return 200 when successfully creating a resource. Look at the docs for the API you're using to be sure.
204Success, and there is no response body. For example, you'll get this when you delete a resource.
400The parameters in the URL or in the request body aren't valid.
403The authenticated user doesn't have permission to perform the operation.
404The resource doesn't exist, or the authenticated user doesn't have permission to see that it exists.
409There's a conflict between the request and the state of the data on the server. For example, if you attempt to submit a pull request and there is already a pull request for the commits, the response code is 409.

Authorization

You can use basic authentication with your app while you're just getting the integration to work. To avoid your users having to sign in to yet another service, implement OAuth integration.

Help and feedback

Get your technical questions answerd, request a feature, or reporting a bug on the support page.

Q&A

Q: Is there a .NET library that I can use to access the web APIs?

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

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Samples.VisualStudioOnline
{
    class Program
    {
        static String _baseUrl = "https://{0}.visualstudio.com/DefaultCollection/_apis/";

        // Get the alternate credentials that you'll use to access the Visual Studio Online account.
        static String _altUsername = PromptForUsername();
        static String _altPassword = PromptForPassword();

        //Your visual studio account name
        static String _account = "{account}";

        //Api version query parameter
        static String _apiVersion = "?api-version=1.0-preview.1";

        static void Main(string[] args)
        {
            RunSample();
        }

        static async void RunSample()
        {
            var responseBody = String.Empty;

            ApiCollection<BuildDefinition> buildDefinitions;
            BuildRequest queueResult;
            Build buildResult;

            _baseUrl = String.Format(_baseUrl, _account);

            using (HttpClient client = new HttpClient())
            {
                client.DefaultRequestHeaders.Accept.Add(
                new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

                //Set alternate credentials
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
                    Convert.ToBase64String(
                        System.Text.ASCIIEncoding.ASCII.GetBytes(
                            string.Format("{0}:{1}", _altUsername, _altPassword))));

                Console.WriteLine("==============Getting a list Build Definitions=================");

                //Get a list of build definitions
                responseBody = await GetAsync(client, _baseUrl + "build/definitions");

                buildDefinitions = JsonConvert.DeserializeObject<ApiCollection<BuildDefinition>>(responseBody);

                if (buildDefinitions.Value.Count() > 0)
                {
                    foreach (var buildDefinition in buildDefinitions.Value)
                    {
                        Console.WriteLine(String.Format(
                            "{0} - {1}",
                            buildDefinition.Id,
                            buildDefinition.Name
                            ));
                    }

                    Console.WriteLine("==============Queueing a Build=================");

                    //Use the first build definition to queue a build
                    var firstBuildDefinition = buildDefinitions.Value.First<BuildDefinition>();

                    Console.WriteLine(String.Format(
                        "Queuing a build using build definition {0}...",
                        firstBuildDefinition.Id
                        ));

                    //Queue a build
                    var buildRequestPOSTData =
                        new BuildRequest()
                        {
                            Definition = new Definition()
                            {
                                Id = firstBuildDefinition.Id
                            },
                            Priority = Priority.Normal,
                            Reason = Reason.Manual

                        };

                    responseBody = await QueueBuildAsync(client, buildRequestPOSTData, _baseUrl + "build/requests");

                    queueResult = JsonConvert.DeserializeObject<BuildRequest>(responseBody);

                    Console.WriteLine(String.Format(
                        "Build request submitted successfully - ID: {0}",
                        queueResult.Id
                        ));

                    Console.WriteLine("==============Waiting for Build to Start Running=================");

                    //poll the server till the build is out of the queue
                    while (!String.IsNullOrEmpty(queueResult.Status) &&
                          queueResult.Status == "queued")
                    {
                        //Wait a while before polling the server
                        Thread.Sleep(8000);

                        Console.WriteLine("Polling the server...");

                        responseBody = await GetAsync(client,
                            String.Format(queueResult.Url,
                            queueResult.Id
                            ));

                        queueResult = JsonConvert.DeserializeObject<BuildRequest>(responseBody);

                        Console.WriteLine(String.Format("Build queue status: {0}", queueResult.Status));
                    }

                    Console.WriteLine("==============Waiting for Build to Complete=================");

                    //Get the status of the build we queued
                    responseBody = await GetAsync(client,
                            String.Format(queueResult.Builds.First<Build>().Url,
                            queueResult.Builds.First<Build>().Id
                            ));

                    buildResult = JsonConvert.DeserializeObject<Build>(responseBody);

                    //Poll until the build either fails or succeeds
                    while (buildResult.Status == BuildStatus.NotStarted
                           || buildResult.Status == BuildStatus.InProgress) 
                    {
                        //Wait a while before polling the server
                        Thread.Sleep(8000);

                        //Get a Build 
                        responseBody = await GetAsync(client,
                                String.Format(buildResult.Url,
                                queueResult.Builds.First<Build>().Id
                                ));

                        buildResult = JsonConvert.DeserializeObject<Build>(responseBody);

                        Console.WriteLine(String.Format(
                            "Build {0}: {1}",
                            buildResult.Id,
                            buildResult.Status
                            ));
                    }

                    if (buildResult.Status == BuildStatus.Succeeded)
                    {
                        Console.WriteLine(String.Format(
                                "Build {0} drop: {1}  ",
                                buildResult.Id,
                                buildResult.BuildDrop.Url
                                ));
                    }
                }
                else
                {
                    Console.WriteLine("No build definitions found....");
                }

            }

                Console.WriteLine("Done...");

                Console.ReadLine();

        }

        static async Task<String> GetAsync(HttpClient client, String apiUrl)
        {
            var responseBody = String.Empty;

            try
            {
                using (HttpResponseMessage response = client.GetAsync(apiUrl + _apiVersion).Result)
                {
                    response.EnsureSuccessStatusCode();
                    responseBody = await response.Content.ReadAsStringAsync();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            return responseBody;
        }

        static async Task<String> QueueBuildAsync(HttpClient client, 
                                          BuildRequest data, 
                                          String apiUrl)
        {
            var responseBody = String.Empty;

            var temp = JsonConvert.SerializeObject(data);

            var content = new StringContent(
                JsonConvert.SerializeObject(data),
                Encoding.UTF8,
                "application/json");

            try
            {
                using (HttpResponseMessage response = client.PostAsync(apiUrl + _apiVersion, content).Result)
                {
                    response.EnsureSuccessStatusCode();
                    responseBody = await response.Content.ReadAsStringAsync();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            return responseBody;
        }

    }

    public class Build
    {
        [JsonProperty(PropertyName = "id")]
        public int Id { get; set; }

        [JsonProperty(PropertyName = "status")]
        public String Status { get; set; }

        [JsonProperty(PropertyName = "name")]
        public String Name { get; set; }

        [JsonProperty(PropertyName = "drop")]
        public Drop BuildDrop { get; set; }

        [JsonProperty(PropertyName = "url")]
        public String Url { get; set; }
    }

    public class Drop
    {
        [JsonProperty(PropertyName = "location")]
        public String Location { get; set; }

        [JsonProperty(PropertyName = "type")]
        public String type { get; set; }

        [JsonProperty(PropertyName = "url")]
        public String Url { get; set; }
    }

    public class BuildDefinition
    {

        [JsonProperty(PropertyName = "uri")]
        public String Uri { get; set; }

        [JsonProperty(PropertyName = "queue")]
        public Queue Queue { get; set; }

        [JsonProperty(PropertyName = "triggerType")]
        public String TriggerType { get; set; }

        [JsonProperty(PropertyName = "defaultDropLocation")]
        public String DefaultDropLocation { get; set; }

        [JsonProperty(PropertyName = "dateCreated")]
        public DateTime DateCreated { get; set; }

        [JsonProperty(PropertyName = "definitionType")]
        public String DefinitionType { get; set; }

        [JsonProperty(PropertyName = "id")]
        public int Id { get; set; }

        [JsonProperty(PropertyName = "name")]
        public String Name { get; set; }

        [JsonProperty(PropertyName = "url")]
        public String Url { get; set; }
    }

    public class BuildRequest
    {
        [JsonProperty(PropertyName = "definition")]
        public Definition Definition { get; set; }

        [JsonProperty(PropertyName = "reason")]
        public String Reason { get; set; }

        [JsonProperty(PropertyName = "priority")]
        public String Priority { get; set; }

        [JsonProperty(PropertyName = "queuePosition")]
        public int QueuePosition { get; set; }

        [JsonProperty(PropertyName = "queueTime")]
        public DateTime QueueTime { get; set; }

        [JsonProperty(PropertyName = "requestedBy")]
        public RequestedBy RequestedBy { get; set; }

        [JsonProperty(PropertyName = "id")]
        public int Id { get; set; }

        [JsonProperty(PropertyName = "status")]
        public String Status { get; set; }

        [JsonProperty(PropertyName = "url")]
        public String Url { get; set; }

        [JsonProperty(PropertyName = "builds")]
        public IEnumerable<Build> Builds { get; set; }

    }

    public class RequestedBy
    {
        [JsonProperty(PropertyName = "displayName")]
        public String DisplayName { get; set; }

        [JsonProperty(PropertyName = "uniqueName")]
        public String UniqueName { get; set; }

    }

    public class Definition
    {
        [JsonProperty(PropertyName = "id")]
        public int Id { get; set; }
    }

    public class ApiCollection<T>
    {
        [JsonProperty(PropertyName = "value")]
        public IEnumerable<T> Value { get; set; }

        [JsonProperty(PropertyName = "count")]
        public int Count { get; set; }
    }

    public class Queue
    {
        [JsonProperty(PropertyName = "queueType")]
        public String QueueType { get; set; }

        [JsonProperty(PropertyName = "id")]
        public int id { get; set; }

        [JsonProperty(PropertyName = "name")]
        public String Name { get; set; }

        [JsonProperty(PropertyName = "url")]
        public String Url;

    }

    public static class Priority
    {
        public const String Normal = "Normal";
        public const String AboveNormal = "AboveNormal";
        public const String BelowNormal = "BelowNormal";
        public const String High = "High";
        public const String Low = "Low";
    }

    public static class Reason
    {
        public const String BatchedCI = "BatchedCI";
        public const String CheckInShelveset = "CheckInShelveset";
        public const String IndividualCI = "IndividualCI";
        public const String Manual = "Manual";
        public const String None = "None";
        public const String Schedule = "Schedule";
        public const String ScheduleForced = "ScheduleForced";
        public const String Triggered = "Triggered";
        public const String UserCreated = "UserCreated";
        public const String ValidateShelveset = "ValidateShelveset";
        public const String HasFlag = "HasFlag";
    }

    public static class BuildStatus
    {
        public const String NotStarted = "notStarted";
        public const String InProgress = "inProgress";
        public const String Succeeded = "succeeded";
    }
}