How to call Team Services REST API from PowerShell and Node.js

When I first tried to learn how to use the REST API for Team Services I really struggled so I thought I would give a simple example on how to get started using the REST API with PowerShell and Node.js.

To follow along you will need the following:

Optional items:

The part that was not clear to me is that once you have the Personal Access Token you do not have to worry about a user name. The second thing that was very unclear was that the Personal Access Token had to be 64 bit Encoded to be passed in the header of your request.


Before I jumped into trying to write code I used a tool called Postman to call the APIs and review the responses.

  1. Start Postman
  2. Set the verb to GET
  3. Enter the following URL replacing {Your Team Services Account} with your Team Services account name
    https://{Your Team Services Account}
  4. Select Basic for Authorization type

    Field Name


    Username {Leave Blank}
    Password {Your Personal Access Token}
  5. Click Send

Postman will send the request to Team Services and return a JSON object with a collection of your Team Projects.  One great feature of Postman is the ability for it to generate code in many different languages for you.


Now that we know we have a good Personal Access Token we can move to writing code. Below you will find code in both PowerShell and Node.js with techniques on encoding your Personal Access Token for use in the REST API calls.


This PowerShell script will work on Mac, Linux and PC.

$version = '1.0'
$account = '{Your Team Services Account}'
$resource = '/projects'
$collection = '/DefaultCollection'
$instance = "$"
$pat = '{Your Personal Access Token}'
$encodedPat = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$pat"))

# Build the url to list the projects
$listurl = 'https://' + $instance + $collection + '/_apis' + $resource + '?api-version=' + $version

# Call the REST API
$resp = Invoke-RestMethod -Uri $listurl -Headers @{Authorization = "Basic $encodedPat"}

Write-Output $resp.value


Make sure you use npm to install the request package using the following command before trying to run the code below.

npm install request
var request = require("request");
var encodedPat = encodePat('{Your Personal Access Token}');

var options = {
   method: 'GET',
   headers: { 'cache-control': 'no-cache', 'authorization': `Basic ${encodedPat}` },
   url: 'https://{Your Team Services Account}',
   qs: { 'api-version': '1.0' }

request(options, function (error, response, body) {
  if (error) throw new Error(error);


function encodePat(pat) {
   var b = new Buffer(':' + pat);
   var s = b.toString('base64');

   return s;

Comments (22) -

  • Dave Shaw

    11/21/2016 9:01:00 PM | Reply

    Thanks for writing this, I tried doing this myself the other day to help with some SO questions but gave up in the end thinking it was too hard, this should really be in the docs, it's much clearer than what I could find.

    • Donovan

      11/27/2016 3:00:29 PM | Reply

      I had a hard time at first too but once you figure it out it is cake.  I am glad it helped.  

  • Nilesh Gadhiya

    3/21/2017 4:32:00 PM | Reply

    Is there REST API for VSTS exists that can be used to extract logs and audit information to send to centralized logging solution?

  • Newton Sheikh

    10/27/2017 10:34:22 AM | Reply

    You saved my life. Cheers to you

  • Phil

    11/9/2017 2:14:12 PM | Reply

    I came to this blog post because I was having difficulty getting Postman to access VSTS APIs using my PAT (though it worked fine with an OAuth token). I knew that the PAT had to be encoded in Base64, which, as you say, isn't as clear as it could be in the VSTS documentation. However, your post further confused me because it explicitly says that the PAT must be Base64-encoded but doesn't then mention that Postman seems to handle this automatically! Once I entered the unenconded PAT in the Password box the request worked just fine!

    • Donovan

      12/3/2017 1:59:40 PM | Reply

      Sorry for the confusion and thanks for the comment. This comment might help others.

  • Seb

    12/7/2017 9:58:59 AM | Reply

    Can I somehow get VSTS agent queue (REST API does not mention about agents theirs job queues) number?
    Meaning the nr. of builds in the queue on particular agent hosted on AzureVM on particular  pool.


  • Dave

    1/18/2018 2:57:46 PM | Reply

    Is it possible to modify the authentication to use Windows instead? My TFS server doesn't currently have an SSL connection hence can't use a PAT

  • Arun

    4/12/2018 4:14:35 PM | Reply

    Thanks for sharing this, very useful. It was one of the best blog/walk through as it was very focused on the topic and was very easy to follow.

    If you could do one for the POST as well, that would be great, for creating a new work item as I ran into this issue.

  • Agus

    4/25/2018 11:01:54 AM | Reply

    Thank you for your useful guide!

  • anayisse

    7/30/2018 9:03:35 AM | Reply

    Thanks for writing this.
    i want to ask you what is the utilisty of this line please "  headers: { 'cache-control': 'no-cache', 'authorization': `Basic ${encodedPat}` }"
    Thanks for helping,
    have a nice day

    • Donovan

      8/7/2018 8:50:32 PM | Reply

      The header section is how you auth. Without it, you will get a 401 because it will not know who you are. You have to create a PAT in VSTS/TFS and 64 bit encode it and set it in your header. Then you can call the APIs

      • anayisse

        8/8/2018 9:12:42 AM | Reply

        J'ai essayé d'écrire ce code pour pouvoir acceder à mon url avec les identifiants que j'ai fixé avant.
        mais j'ai toujours une erreur qui dit "(node:2572) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: task is not defined"  

        /*My code*/

        var auth = 'Basic ' + new Buffer(username + ':' + password).toString('base64');
                    var options = {
                        method: 'GET', headers: { 'Accept': 'application/json',
                        'Accept-Charset': 'utf-8', 'cache-control': 'no-cache', 'authorization': auth},
                        url: complete_link,
                     request.get(options, function (error, response, body) {
                        if (error)
                        {    throw new Error(error)

        /*Thank you for helping me*/

  • ANNA

    7/31/2018 7:57:00 AM | Reply

    thank you for you helps,
    who can help me please i have problems with this code!!
    thank youu

    • Donovan

      8/7/2018 8:50:50 PM | Reply

      You can ask your questions here in the comments.

  • Tomas

    8/26/2018 6:41:08 PM | Reply

    Hi, does VSTS rest api implement any kind of caching? I've made an extension/report that queries all releases and it is very slow. It would be nice to skip releases that did not change over time. Thanks!

  • Sinclair

    1/4/2019 4:17:19 AM | Reply

    Oh my god thank you for writing this.

  • sudalai muthukumar

    1/31/2020 2:08:05 PM | Reply

    in RestAPI, how to create a workspace and check-in the files into TFVC rep branch nay idea

  • Mallesh

    8/29/2020 10:38:00 AM | Reply

    How to access on-premises tfs server, using rest apis. Such as run a test suite in a test plan through postman.

  • Henry

    1/5/2022 10:07:51 PM | Reply

    Hi Donovan.
    Im using REST Api for VSTS and want to set required reviewers branch policy, which in turn, needs the reviewer id. Im thinking this would be the Active Directory account SID. I´ve also tried with domain\user format but none of this work. Could you please assist with this problem ?

Add comment