Citrix Virtual Apps and Desktops REST APIs

Learning journey

Go through the learning journey section to get started with tasks that you can perform using the Citrix Virtual Apps and Desktops REST APIs.

This guide walks you through steps to generate your first bearer token, make your first API request, and perform some common administrative tasks. By the end of this learning journey, you will be comfortable parsing the documentation and get familiar with functionalities available to you.

This guide lists a few examples of what you can do with these APIs. We release new runbooks often. You can provide feedback on this guide and any of our APIs in our discussion forums.

Prerequisites

Before you make your first call to the service, let’s make sure that you have everything that is required.

Step 1: Create a bearer token

Tokens are passed into the authorization header of APIs. Create a bearer token for API authentication and authorization. To generate a token, use the admin credential to exchange a token.

POST https://[DdcServerAddress]/cvad/manage/Tokens HTTP/1.1
Accept: application/json
Authorization: Basic [AdminCredenticalEncodedByBase64]
<!--NeedCopy-->

The following parameters are required to create bearer token:

  • a DdcServerAddress which is one of your on-premises DDC server address.
  • a AdminCredenticalEncodedByBase64 which is your admin credentical encoded by base64. The username and password separated by a colon, UTF8-encoded, then base64-encoded.

The admin credentical can be encoded by the following powershell script:

$adminCredentical = :
$Bytes = [System.Text.Encoding]::UTF8.GetBytes($adminCredentical)
$EncodedAdminCredentical =[Convert]::ToBase64String($Bytes)
$EncodedText
<!--NeedCopy-->

After successfully calling the Token API, you receive a response and a payload with a bearer token in the field token. Save this token for later use, to pass the `` in authorization header as Authorization: CWSAuth bearer=.

Note:

Bearer tokens are typically valid for an hour, after which they expires (refer to the response field expires_in). In that case, follow the same steps to generate a new token.

Step 2: Get the site ID

Know your siteId to specify to the API service which Citrix Virtual Apps and Desktops site you want to call. Use the Me API route to get the ``, which is used in other API calls. The Me route is used to return information about the sites for a given customer. For on-premises Citrix Virtual Apps and Desktops, the customerId is always CitrixOnPremises.

Use the bearerToken that was generated in Step 1 as header values in the request as per the following format:

GET https://[DdcServerAddress]/cvad/manage/Me HTTP/1.1
Citrix-CustomerId: 
Authorization: CWSAuth Bearer=
<!--NeedCopy-->

The following is a sample response:

{
    "UserId": "Test\\Administrator",
    "DisplayName": "Administrator",
    "ExpiryTime": "11:27:31 AM",
    "RefreshExpirationTime": "10:27:31 AM",
    "VerifiedEmail": null,
    "IsCspCustomer": false,
    "Customers": [
        {
            "Id": "CitrixOnPremises",
            "Name": null,
            "Sites": [
                {
                    "Id": "41701c13-d857-449b-bed8-bc843e7ee9a9",
                    "Name": "samplecloudsite"
                }
            ]
        }
    ]
}
<!--NeedCopy-->

Under the Sites array within the first element of the Customers array, put the first element’s Id as the siteId. The siteId can be saved, it will not change as long as the DaaS account remains active.

For more information, see the Me API Specification.

Step 3: Identify route structure for functional routes

The URI pattern for Citrix Virtual Apps and Desktops functional routes is as follows:

https://[DdcServerAddress]/cvad/manage/

You can make a note of the URI pattern for future use.

Hello notepad

When setting up a Citrix Virtual Apps and Desktops site, it is common that many admins use Notepad as a simple test application for any Delivery Group. Let’s use this application to show that routes are working in our site.

Note:

In this example, let’s assume that you have a machine that is already provisioned, and a delivery group created.

Example 1: Publishing an app via API (Notepad)

If you want to publish an application in Citrix Studio, go to your Delivery Group and then modify the delivery to include the application in the object. The same logic applies here. Use the /DeliveryGroups/ route collection to implement this functionality.

Step 1: Get the delivery group ID

Since we assume you already have a Delivery Group created, let’s first get the Delivery Group Id so that you can store this information. Most API route collections have standard GET methods implemented so getting all Delivery Groups is easy.

GET https://[DdcServerAddress]/cvad/manage/DeliveryGroups HTTP/1.1
Citrix-CustomerId: 
Citrix-InstanceId: 
Authorization: CWSAuth Bearer=
<!--NeedCopy-->

We expect an array of Delivery Group objects: let’s take one of the Delivery Groups and inspect the object.

{
    "Id": "5245ff16-515b-47ee-a0f3-7324cfe8a99e",
    "Uid": 49,
    "UserManagement": "Studio",
    "Delivering": "DesktopsAndApps",
    "DeliveryType": "DesktopsAndApps",
    "Description": null,
    "DesktopsAvailable": 0,
    "DesktopsDisconnected": 21,
    "DesktopsFaulted": 0,
    "DesktopsUnregistered": 1,
    "Enabled": true,
    "HasBeenPromoted": false,
    "HasBeenPromotedFrom": "Unknown",
    "InMaintenanceMode": false,
    "IsBroken": false,
    "IsRemotePC": false,
    "MinimumFunctionalLevel": "L7_6",
    "Name": "Students",
    "RequireUserHomeZone": false,
    ... // Rest of object too large to show for the example. 
}
<!--NeedCopy-->

As you can see, many of the properties represented in the Students Delivery Group are in this object. Now, you will need the Id to pass it to the next route that you will call.

Step 2: Call a route on the particular delivery group

After you have an Id, you are ready to call a route on the particular Delivery Group. In this case, you can POST a NewApplication object while using POST /Applications.

A sample object is used below. Check the documentation to see how to call the route with a custom object.

POST https://[DdcServerAddress]/cvad/manage/DeliveryGroups//Applications HTTP/1.1
Citrix-CustomerId: 
Citrix-InstanceId: 
Authorization: CWSAuth Bearer=

{
    "NewApplications": [
        {
            "ApplicationFolder": "",
            "ApplicationType": "HostedOnDesktop",
            "IncludedUsers": [],
            "InstalledAppProperties": {
                "CommandLineExecutable": "",
                "CommandLineArguments": "",
                "WorkingDirectory": "C:\\"
            },
            "Name": "",
            "PublishedName": ""
        }
    ]
}
<!--NeedCopy-->

For more information, see the API Specification.

Admins must know the application name, the published name, and where the app is installed. Assuming one prepared an image and we are publishing an app off a Golden Image. Run where {executableName.exe} in the Windows command prompt to get a valid path. In our case: notepad is located in Windows\System32\notepad.exe for most images.

You should see Notepad added to the applications.

Example 2: Enumerating sessions and send message to a session console

Step 1: Pull all of the active sessions running within your site

Now, it’s common that you would want to pull all of the active sessions running within your site. That is pretty simple! We have a dedicated route that can return all of the sessions along with the requisite session information.

GET https://[DdcServerAddress]/cvad/manage/Sessions HTTP/1.1
Citrix-CustomerId: 
Citrix-InstanceId: 
Authorization: CWSAuth Bearer=
<!--NeedCopy-->

For more information, see the API specification.

An array full of Session objects is returned, as follows:

{
 "Items": [
    {
      "Id": "b108af54-cdaa-463e-b791-0b07a624e2b2",
      "Uid": 1002,
      "ApplicationsInUse": [
        {
          "Id": "00000000-0000-0000-0000-000000000000",
          "Uid": null,
          "Name": "Faculty Club"
        }
      ],
      "AppState": "Active",
      "AppStateLastChangeTime": "5/8/2021 5:38:58 PM",
      "Brokering": {
        "AutonomouslyBrokered": false,
        "DurationMilliseconds": null,
        "Time": null,
        "UserName": null,
        "UserSid": null
      },
      "Client": {
        "DeviceId": "WR_kcAvFgC7qh03R7jrt",
        "HardwareId": "00000000",
        "IPAddress": "127.0.0.1",
        "Name": "HTML-1063-0750",
        "Platform": "Unknown",
        "ProductId": 0,
        "ReceiverIPAddress": "66.165.176.60",
        "ReceiverName": "WR_kcAvFgC7qh03R7jrt",
        "Version": ""
      },
      "Connection": {
        "ConnectedViaHostName": null,
        "ConnectedViaIP": "10.0.0.5",
        "ConnectionMode": "Brokered",
        "LaunchedViaHostName": "hynth658.eastus.cloudapp.azure.com",
        "LaunchedViaIP": "13.92.114.133",
        "Protocol": "Hdx",
        "SecureIcaActive": false,
        "SmartAccessTags": []
      },
       ... // More information omitted.
    },
     ... // More sessions omitted.
 ],
 "ContinuationToken": "T7UhcehawR8PBTpc-tszgA=="
}       
<!--NeedCopy-->

Step 2: Set a limit on the maximum records

For performance consideration, you can set a limit on the maximum records that return when you query and search site objects using APIs. Use the limit query parameter to specify the limit. An extra limit might also be applied at the API server side depending on the Cloud settings.

If the number of objects matching your query or search exceeds the limit, they cannot be returned using one call. Use paging to obtain all the objects through multiple API calls.

In the preceding sample response, we can see a ContinuationToken string at the end of the response JSON object. We can pass this string value as the continuationToken query parameter values to the same query to get the next batch of results. Repeat this step until the ContinuationToken value in response is null, indicating there’re no more unreturned results.

GET https://[DdcServerAddress]/cvad/manage/Sessions?continuationtoken= HTTP/1.1
Citrix-CustomerId: 
Citrix-InstanceId: 
Authorization: CWSAuth Bearer=
<!--NeedCopy-->

Another array of Session objects is returned, as follows:

{
 "Items": [
    {
      "Id": "cf314e6e-0ec6-47ba-aa77-88b63d4827bb",
      "Uid": 1252,
      "ApplicationsInUse": [
        {
          "Id": "00000000-0000-0000-0000-000000000000",
          "Uid": null,
          "Name": "Published Web Browser"
        }
      ],
      "AppState": "Active",
      "AppStateLastChangeTime": "5/8/2021 15:31:07 PM",
      "Brokering": {
        "AutonomouslyBrokered": false,
        "DurationMilliseconds": null,
        "Time": null,
        "UserName": null,
        "UserSid": null
      },
      "Client": {
        "DeviceId": "WR_kcAvFgC7qh03R7jrt",
        "HardwareId": "00000000",
        "IPAddress": "127.0.0.1",
        "Name": "HTML-1063-0750",
        "Platform": "Unknown",
        "ProductId": 0,
        "ReceiverIPAddress": "66.165.176.60",
        "ReceiverName": "WR_kcAvFgC7qh03R7jrt",
        "Version": ""
      },
      "Connection": {
        "ConnectedViaHostName": null,
        "ConnectedViaIP": "10.0.0.5",
        "ConnectionMode": "Brokered",
        "LaunchedViaHostName": "hynth655.eastus.cloudapp.azure.com",
        "LaunchedViaIP": "13.92.114.135",
        "Protocol": "Hdx",
        "SecureIcaActive": false,
        "SmartAccessTags": []
      },
       ... // More information omitted.
    },
     ... // More sessions omitted.
 ],
 "ContinuationToken": "3EOYomxNlavb8GhMCzr7wg=="
}       
<!--NeedCopy-->

Repeat this step until a null ContinuationToken is received.

For more information, see How to use paging.

Step 3: Explore actions with the sessions

Now, that seemed pretty simple. Let us take a step further by exploring what we can do with the sessions.

In the documentation link provided, you can see that $logoff or $sendMessage are some of the actions we can perform. Logging off someone is a common administration task but let’s do something that is less consequential such as sending a message.

You can POST a Message object to a Session by ID and have the message show up to a logged-in user in real time. You can let them know that you added Notepad as an available application.

We can use this mechanism to warn our users about any other announcements to the site that might be applicable.

POST https://[DdcServerAddress]/cvad/manage/Sessions//$sendMessage HTTP/1.1
Citrix-CustomerId: 
Citrix-InstanceId: 
Authorization: CWSAuth Bearer=

{
  "Style": "Unknown",
  "Title": "Hey There!",
  "Text": "We just added Notepad to your machine. Happy Typing!"
}
<!--NeedCopy-->

Ensure you pass the payload.

Remember, this is a small subset of what you can do with the API. With your HTTP client of choice, you can iterate through the sessions object to log anyone off or get robust information about who is connected.

Neat tricks

So far, we have learned about the basics of the API and introductory routes that can be used. Now let’s a take a moment to explore the additional functionality and advanced scenarios that can be performed. We will get into searching, modifying existing objects and VMs, and image management.

In this section, we assume you have provisioned VMs and prepared Golden Images.

Example 3: Tagging VMs by criteria

Many admins wish to tag provisioned VMs on certain information for organization. In this example, we will go through performing a search via an API and then performing a tag.

In this example, two APIs are used, they are:

  • search the machines
  • associate a tag with those machines

Step 1: Get machine ID

First, search for a machine to get its Id to be able to perform an action on it. You can refer to examples given in this guide earlier.

These routes concern actions related to specific VMs. The $ delimiter denotes actions within the API. In this case, you can apply $search to perform a Search. However, since we need to post an object with filters and parameters of what we are looking for, we perform a POST not a GET.

POST https://[DdcServerAddress]/cvad/manage/Machines/$search?limit=100 HTTP/1.1
Citrix-CustomerId: 
Citrix-InstanceId: 
Authorization: CWSAuth Bearer=

{
    "SearchFilters": [
        {
            "Property": "SessionSupport",
            "Value": "SingleSession",
            "Operator": "Equals"
        }
    ]
}
<!--NeedCopy-->

For more information, see the API specification.

The Payload with the SearchFilters object is the standard model we use across all search operations in Citrix Virtual Apps and Desktops. The above object lists all Single Session machines. In your payload, you can have multiple filters and up to one search string. Note, how the standard search query string property commented out in the preceding example. We left this in place to show you that this is optional.

We expect to get the following back:

{
  "Items": [
    {
      "Id": "string",
      "Uid": 0,
      "name": "string",
      "AgentVersion": "string",
      "ApplicationsInUse": [
        {
          "Id": "string",
          "Uid": 0,
          "Name": "string"
        }
      ],
      ...
    }
  ]
}
<!--NeedCopy-->

You might notice a pattern how arrays of objects return under Items. You can expect that Items of any Object type will return for any call where you expect a list of results.

Take the Id and pass it to the next API call we will perform.

Step 2: Explore expected action in next API

Now, you have the Id of the VM you wish to tag, let’s explore what is expected in the next API.

As expected, the functionality pertaining to the same type of object is within the route collection. In this case, the Id of the object is encoded in the route, pass the machineId in the route as well. Assuming that the tag is ready to use in this example, if not you can check out /cvad/manage/Tags to see how you can create one.

POST https://[DdcServerAddress]/manage/Machines//Tags/ HTTP/1.1
Citrix-CustomerId: 
Citrix-InstanceId: 
Authorization: CWSAuth Bearer=
<!--NeedCopy-->

For more information, see the API specification.

Now you can use the tags GET routes to return all Machines with a specific tags simplifying your management experience.

Example 4: Update a catalog image

Admins have image management pipelines in a variety of places. One common admin task after an image is generated in a certain file store is to update the catalog with the new Golden Image. With the $updateProvisioningScheme under the MachineCatalogs collections you can point the Machine Catalog to a newly generated image.

Let’s assume you already have a Machine Catalog you want to update, and let’s assume you have a link to our image in a public infrastructure provider.

With the following route you can post a new ProvisioningScheme object to tell the service that you wish to update with a new image.

POST https://[DdcServerAddress]/cvad/manage/MachineCatalogs//$UpdateProvisioningScheme?async=true HTTP/1.1
Citrix-CustomerId: 
Citrix-InstanceId: 
Authorization: CWSAuth Bearer=

{
    "MasterImagePath": "XDHyp:\\HostingUnits\\Azure001-Resource001\\image.folder\\MachineCatalog.resourcegroup\\MasterVDA001_OsDisk_1_6927d0254c194a01aa3078eec78bdca0.manageddisk",
    "StoreOldImage": true,
    "MinimumFunctionalLevel": "L7_20",
    "RebootOptions": {
        "RebootDuration": -1,
        "SendMessage": false
    }
}
<!--NeedCopy-->

For more information, see the API specification.

Admins can use this mechanism with an IaaS functions service allowing them to include an API call in their Dev Ops pipelines. Remember, the Dev Ops pipeline service must generate a valid token before executing this request.

Resources
Citrix Virtual Apps and Desktops REST APIs OpenAPI Specification
Copy Download
Learning journey