Using Azure DevOps REST API to start multiple releases

Azure DevOps CI / CD (i.e. Build / Release) mechanism is very valuable to me. It makes things reproduceable & robust. It allows me to change whatever I want since I have this constant safety net underneath.

For simple projects, having a build and release is fine. With micro-services I adopt the pattern of one service / one repo / one CI/CD.

That is great until we consider shared infrastructure. If many services share an infrastructure (e.g. AKS Cluster, App Service Plan, etc.), which one’s release should deploy the shared service? I considered having each of them doing so but finally adopted the pattern of having a separate repo / CI/CD for the shared infrastructure. I now need to cascade releases: shared infrastructure first, then the “real” services.

That’s not too bad to sequence it since it’s all automated. But… I’m cheap and I delete my “dev” environment all the time. So, when I need to reconstruct it, I need to release the shared infrastructure then each services. This is when it gets ugly to do it with Azure DevOps UI.

In this article I’m going to show how to use Azure DevOps REST API to do this. This is going to be solution-agnostic. You could implement it with a console-app running on your laptop, a container in Azure, etc. .

In the next article, I’m going to show how to implement it using Azure Logic Apps.

We are going to stay simple. I’m going to target the scenario of doing a release on a project, waiting for it to succeed and then releasing another project. There are many more scenarios with approvals and conditions, etc. , but here we’re going to look at the basics. You can use your imagination to land your own scenario.

Fundamental of APIs

Azure DevOps has a collection of REST APIs. There is an API per entity, e.g. Build, Release, Git, Work Item, etc. .

As the online documentation states, APIs requires use to know:

We also need to authenticate. But that’s important, so let’s do an entire sub section about that.


There are many ways to authenticate against Azure DevOps.

Typically, a user authenticates through an Azure AD application. The application then performs actions on behalf of the user.

In our case, it makes more sense to have actions performed by the system. Azure AD Service Principal aren’t supported in Azure DevOps. Instead, there is a concept of Personal Access Tokens (PAT).

PAT fundamentals

A PAT is a token we can directly pass to requests. We do not need to authenticate using that token to receive a bearer token.

PAT can be given Full access (useful to start) or custom scope. We recommend using a custom scope here. As always, we apply the Principle of least privilege to limit the attack surface and the magnitude of the risk should the secret be leaked.

For our scenario, a token giving access to read / write / execute of releases is enough:

Release scope

Unfortunately, at the time of this writing (end of November 2018), there isn’t a way to limit the scope per project.

We can set expiration dates to PATs and revoke them shall they be compromised.

It is important to note that a token can be readily used without any user authenticating. It is therefore important to handle the token with care. Ideally, Azure Key Vault should be used so the secret isn’t expose to users.

Unfortunately, at the time of this writing (end of November 2018), there is an API for revoking tokens but none to create one (to automatically rotate PATs).

Using a PAT to authenticate

Although using PATs is simple, there are caveats that can easily incur some wasted time.

PAT are using for basic HTTPS authentication. So, they are passed clear text over HTTPS connection.

Well… their base-64 representation is passed clear text.

Actually… An important detail is that a colon (i.e. :) needs to be prepended to the PAT before its base-64 representation be calculated.

This is because typically we use the pair USER:SECRET. Here USER is empty, hence :SECRET.

To be clear, if the PAT value is XYZ, we need to take the base-64 value of :XYZ.

We can then use the following HTTP host header:

Authorization: Basic BASE64PATSTRING

A C# example is given at the bottom of this article.

Creating a release

Now we can look at specific API.

First we’ll need to create a release:


The request body can contain a few specifics, such as an artefact list.

The real key value to pass in the body is the release definition ID. This can be found by looking at the URL when looking at a release definition. It is present in the URL query string under definitionId.

It typically is a small integer (e.g. 1, 2, 3, etc.).

This API returns a payload of information. The key value to keep is the id. This is the release-id. We’ll need it to inquire about the release status.

Getting a release status

In order to wait for the release to be over, we’ll need to probe the get-release API:


This is where the releaseId we got from the previous API comes handy.

It is pretty straightforward to use.

The returned payload contains information about the release and each of its stage. The stages information can be found under the environments JSON property. Each of those stage have a status. This is the value we need to monitor.


We hope this quick look at Azure DevOps API gives enough pointer to start using them.

In the next article, we’ll look at an example implemented using Azure Logic Apps.

One response

  1. satheesh 2021-03-15 at 21:23

    How to provide artifacts details while creating new release ?

Leave a comment