Work with URLs in extensions and integrations
Azure DevOps Services
With the introduction of Azure DevOps, organizational resources and APIs are now accessible via either of the following URLs:
https://dev.azure.com/{organization}
(new)https://{organization}.visualstudio.com
(legacy)
Regardless of when the organization was created, users, tools, and integrations can interact with organization-level REST APIs using either URL. As the developer of an extension, integration, or tool that interacts with Azure DevOps, learn how to best work with URLs made available to your code and form URLs when you call REST APIs.
For more information, see the REST API Reference.
Organization primary URL
Each organization has a designated primary URL that is either the new form or the legacy form. The primary URL is used by Azure DevOps for constructing URLs in certain scenarios (more details follow). The default primary URL for an organization is determined by when the organization was created, but can be changed by an administrator:
When the organization was created | Default primary URL |
---|---|
On or after 9/10/2018 | New |
Before 9/10/2018 | Legacy |
How the primary URL is used
The primary URL is the base URL for all URLs constructed by Azure DevOps in background jobs and other automated scenarios. See the following examples.
- URLs provided to Azure Pipelines tasks via environment variables (like
SYSTEM_TEAMFOUNDATIONCOLLECTIONURI
) - URLs included in service hooks event payloads (like URLs in
resourceContainers
) - URLs in email, Slack, Microsoft Teams, and similar notifications
For example, the following task snippet displays the organization URL provided to the task:
$orgUrl = $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI
Write-Host $orgUrl
If this task is executed on an organization where the primary URL is the new URL form, the output is https://dev.azure.com/{organization}
. The same task executed on an organization where the primary URL is the legacy URL form outputs https://{organization}.visualstudio.com
.
It's therefore important that Azure Pipelines tasks and services that receive events from service hooks handle both URL forms.
URLs returned in REST APIs
Regardless of an organization's primary URL, URLs returned in the response to a REST API call use the same base URL as the requesting URL. This function ensures clients calling a REST API using a legacy URL continues to get back URLs in the same (legacy) form. For example, when the Projects REST API is called using a legacy URL, URLs in the response use the legacy form:
Request
GET https://Fabrikam.visualstudio.com/_apis/projects/MyProject
Response
{
"id": "ef4de40d-3d96-4b80-a320-cfafe038ae57",
"name": "MyProject",
"url": "https://Fabrikam.visualstudio.com/_apis/projects/MyProject"
}
Calling the same API using the new URL (https://dev.azure.com/Fabrikam/_apis/projects/MyProject
) results in URLs returned in the new URL form.
Best practices
To ensure your extension, tool, or integration is resilient to changing organization URL forms and to possible future changes to the location (domain) of a REST API:
- Assume the form of the organization URL can change over time.
- Avoid parsing a URL to construct another URL.
- Don't assume a particular REST API always resides on the same domain.
- Avoid storing URLs in your service.
- When possible, use Microsoft-provided .NET, TypeScript (web), Node.js, and Python client libraries with Azure DevOps.
How to get an organization's URL
With just the organization's name or ID, you can get its base URL using the global Resource Areas REST API (https://dev.azure.com/_apis/resourceAreas
). This API doesn't require authentication. It also provides information about the location (URL) of the organization and the base URL for REST APIs, which can live on different domains.
A resource area is a group of related REST API resources and endpoints. Each resource area has a well-known identifier (see the following table). Each resource area has an organization-specific base URL that can be used to form URLs for APIs in that resource area. For example, the base URL for "build" REST APIs for the Fabrikam might be https://dev.azure.com/Fabrikam
, but the base URL for "release management" REST APIs might be https://vsrm.dev.azure.com/Fabrikam
.
Note
The Resource Areas REST API returns URLs for the organization based on that organization's designated primary URL.
With the organization's name
There are a few ways to get the base URL for an organization using its name.
Request
Replace {organizationName}
with organization's name, for example "Fabrikam". 79134C72-4A58-4B42-976C-04E7115F32BF
is the ID for the "core" resource area, which is where important resources like "projects" are.
GET https://dev.azure.com/_apis/resourceAreas/79134C72-4A58-4B42-976C-04E7115F32BF
?accountName={organizationName}&api-version=5.0-preview.1
Response
{
"id": "79134C72-4A58-4B42-976C-04E7115F32BF",
"name": "Core",
"locationUrl": "https://dev.azure.com/Fabrikam"
}
The locationUrl
reflects the organization's base URL.
With the organization's ID
To get the URL for an organization using its GUID identifier, use the hostId
query parameter in the previous examples (instead of accountName
). For example:
GET https://dev.azure.com/_apis/resourceAreas/79134C72-4A58-4B42-976C-04E7115F32BF?hostId={organizationId}&api-version=5.0-preview.1
How to get the base URL for a REST API
Starting from an organization's URL, you can use the Resource Areas REST API to look up the correct base URL for any REST API you need to call. This process ensures your code is resilient to the location (domain) of a REST API changing in the future and avoids potentially brittle logic.
Note
If you are using the Microsoft-provided .NET, TypeScript (web), Node.js, or Python client library, URL lookup is handled for you. For example, in .NET when you construct a VssConnection
and call GetClient<T>
, the returned client is properly bound to the correct base URL for the REST APIs called by this client.
If you aren't using a Microsoft-provided client library:
Use the following table to find the resource area ID for the REST API you need to call. The resource area name usually appears after
/_apis/
in the REST API route. For example, the/_apis/release/definitions
REST API belongs to therelease
resource area, which has an ID ofefc2f575-36ef-48e9-b672-0c6fb4a48ac5
.Call the organization-level Resource Areas REST API (
{organizationUrl}/_apis/resourceAreas/{resourceAreaId}?api-version=5.0-preview.1
) and pass the resource area ID. For example:GET https://dev.azure.com/Fabrikam/_apis/resourceAreas/efc2f575-36ef-48e9-b672-0c6fb4a48ac5?api-version=5.0-preview.1
Use the
locationUrl
field from the JSON response as the base URL for calling other REST APIs for this area. In this example, the base URL for Release Management REST APIs ishttps://vsrm.dev.azure.com/Fabrikam
.
Like the global Resource Areas REST API described earlier, no credentials are required to call the organization-level Resource Areas REST API.
Example: Pipelines task calling an Azure Pipelines releases REST API
In this example, a build task needs to call the Azure Pipelines releases REST API. It forms the correct base URL for this REST API call by using the organization URL (provided in an environment variable) and the Resource Areas REST API.
Note
Resource area IDs are fixed and can be safely embedded in tasks and other logic.
$orgUrl = $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI
$releaseManagementAreaId = "efc2f575-36ef-48e9-b672-0c6fb4a48ac5"
# Build the URL for calling the org-level Resource Areas REST API for the RM APIs
$orgResourceAreasUrl = [string]::Format("{0}/_apis/resourceAreas/{1}?api-preview=5.0-preview.1", $orgUrl, $releaseManagementAreaId)
# Do a GET on this URL (this returns an object with a "locationUrl" field)
$results = Invoke-RestMethod -Uri $orgResourceAreasUrl
# The "locationUrl" field reflects the correct base URL for RM REST API calls
$rmUrl = $results.locationUrl
# Construct the URL to the release definitions REST API
$releaseDefinitionsUrl = [string]::Format("{0}/_apis/release/definitions?api-preview=5.0-preview.1", $rmUrl)
Resource area IDs (reference)
This table shows the IDs for common resource areas. See the previous section for details on how to use this table.
Note
Resource area IDs are fixed and are consistent across all organizations in Azure DevOps Services.
Resource Area ID | Name |
---|---|
0d55247a-1c47-4462-9b1f-5e2125590ee6 | account |
5d6898bb-45ec-463f-95f9-54d49c71752e | build |
79bea8f8-c898-4965-8c51-8bbc3966faa8 | collection |
79134c72-4a58-4b42-976c-04e7115f32bf | core |
31c84e0a-3ece-48fd-a29d-100849af99ba | dashboard |
a0848fa1-3593-4aec-949c-694c73f4c4ce | delegatedAuth |
6823169a-2419-4015-b2fd-6fd6f026ca00 | discussion |
a85b8835-c1a1-4aac-ae97-1c3d0ba72dbd | distributedtask |
7bf94c77-0ce1-44e5-a0f3-263e4ebbf327 | drop |
6c2b0933-3600-42ae-bf8b-93d4f7e83594 | extensionManagement |
67349c8b-6425-42f2-97b6-0843cb037473 | favorite |
4e080c62-fa21-4fbc-8fef-2a10a2b38049 | git |
4e40f190-2e3f-4d9f-8331-c7788e833080 | graph |
68ddce18-2501-45f1-a17b-7931a9922690 | memberEntitlementManagement |
b3be7473-68ea-4a81-bfc7-9530baaa19ad | NuGet |
4c83cfc1-f33a-477e-a789-29d38ffca52e | npm |
45fb9450-a28d-476d-9b0f-fb4aedddff73 | package |
7ab4e64e-c4d8-4f50-ae73-5ef2e21642a5 | packaging |
2e0bf237-8973-4ec9-a581-9c3d679d1776 | pipelines |
fb13a388-40dd-4a04-b530-013a739c72ef | policy |
8ccfef3d-2b87-4e99-8ccb-66e343d2daa8 | profile |
efc2f575-36ef-48e9-b672-0c6fb4a48ac5 | release |
57731fdf-7d72-4678-83de-f8b31266e429 | reporting |
ea48a0a1-269c-42d8-b8ad-ddc8fcdcf578 | search |
3b95fb80-fdda-4218-b60e-1052d070ae6b | test |
c83eaf52-edf3-4034-ae11-17d38f25404c | testresults |
8aa40520-446d-40e6-89f6-9c9f9ce44c48 | tfvc |
970aa69f-e316-4d78-b7b0-b7137e47a22c | user |
5264459e-e5e0-4bd8-b118-0985e68a4ec5 | wit |
1d4f49f9-02b9-4e26-b826-2cdb6195f2a9 | work |
85f8c7b6-92fe-4ba6-8b6d-fbb67c809341 | worktracking |
Next steps
Feedback
https://aka.ms/ContentUserFeedback.
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:Submit and view feedback for