PI Vision API Reference
- Last UpdatedDec 12, 2025
- 11 minute read
- PI System
- PI Vision API Reference
- Developer
With the release of PI Vision 2021, PI Vision introduces new capabilities that allow PI Vision displays to be imported or exported using the PI Vision API. It is an alternative to using PI Vision Display Utility offline display files (PDIX).
This documentation covers the supported usage and functionality of the PI Vision API for display import and export.
Guidelines for Usage
The guidelines below cover the supported import and export functionality of the PI Vision API. Any modifications of code outside of these guidelines is not permitted.
The PI Vision API enables the export and import of PI Vision displays. The modification of JSON content permitted is limited to display metadata covered in this documentation. This API does not permit the modification of any display definition content such as symbol definition.
Security
Most PI Vision Display API endpoints require authentication with the request. The authenticated user must be authorized as a Utility User or as an Administrator in PI Vision. The exception to this is the Version endpoint, which does not require authentication, and is used primarily to verify that the API service is responsive. In addition to authentication, any request that is not a GET request must include a non-empty value in the X-Requested-With header.
Check server configuration
The method of authentication varies based on the PI Vision configuration. To determine the authentication configuration, use the AuthenticationInfo endpoint. Similar to the Version endpoint, the AuthenticationInfo endpoint does not require authentication.
Invoke-WebRequest -Uri 'https://myServer/PIVision/Utility/api/v1/AuthenticationInfo'
Windows authentication
Using PowerShell, specify -UseDefaultCredentials to authenticate as the current signed-on Windows user.
Invoke-WebRequest -UseDefaultCredentials -Uri 'https://myServer/PIVision/Utility/api/v1/folders'
Using cURL, specify --negotiate to authenticate as the current signed-on Windows user. To authenticate as a different user (or if not on Windows), pass the username and password using -u USERNAME:PASSWORD.
curl --negotiate https://myServer/PIVision/Utility/api/v1/folders
curl --negotiate -u domain\user:mypassword https://myServer/PIVision/Utility/api/v1/folders
OpenID Connect
When PI Vision is configured to authenticate users with OpenID Connect only, you must acquire an access token from the active Identity Server to call the PI Vision API. The token must be provided as a Bearer token in the Authorization header.
The active AIM server is returned from the AuthenticationInfo endpoint and should be used when acquiring new access tokens.
Using PowerShell:
$token = .\GetToken.ps1 -PIVisionServer 'https://myServer/PIVision' # see GetToken.ps1 in "Examples" section
Invoke-WebRequest -Headers @{ Authorization = "Bearer $token" } -Uri 'https://myServer/PIVision/Utility/api/v1/folders'
Using cURL:
curl -H "Authorization: Bearer myAccessTokenHere" https://myServer/PIVision/Utility/api/v1/folders
OpenID Connect and Windows
When PI Vision is configured for "OpenID Connect and prompt for Windows credentials when required", callers must authenticate with an access token and with a Windows identity. In this mode, the access token must be sent in a custom header named PVBearerToken. Note that the Bearer prefix is not used in this header.
Using PowerShell:
$token = .\GetToken.ps1 -PIVisionServer 'https://myServer/PIVision' # see GetToken.ps1 in "Examples" section
Invoke-WebRequest -UseDefaultCredentials -Headers @{ PVBearerToken = $token } -Uri 'https://myServer/PIVision/Utility/api/v1/folders'
Using cURL:
curl --negotiate -H "PVBearerToken: myAccessTokenHere" https://myServer/PIVision/Utility/api/v1/folders
Pagination
Some GET operations utilize pagination to specify or limit the number of results returned in the response. This provides support for low-speed networks and limits memory consumption on the client side.
One of example of this is the GET /Folders endpoint. The following parameters can be passed to configure the results returned via pagination:
skip – Allows the user to skip a specific number of records. The default value is
0. If this parameter is omitted, no records are skipped.count – Allows the user to set the specific number of records to be returned. The default value is
100.
In the case where there are more results than what is requested, the response will contain a HasMore field that indicates that there are more records beyond the requested amount.
The following are pagination examples.
Lets assume that the PI Vision server has two folders at the root level.
Request: GET /Folders?count=1
{
"Items": [
{
"Id": 1,
"Name": "Folder1",
"ParentId": null,
"HasChildren": true
}
],
"HasMore": true <-- Indicates that there are more records available on the server side
}
One folder returned, and HasMore returns true since there is one more folder left to request. It can be requested using following example.
Request: GET /Folders?count=2&skip=1
{
"Items": [
{
"Id": 2,
"Name": "Folder2",
"ParentId": null,
"HasChildren": false
}
],
"HasMore": false
}
The first folder was skipped, and the remaining folder was returned.
Operations
The primary operations provided by the PI Vision Display API are exporting and importing displays. Displays can be exported by calling the GET /Displays/Export endpoint and imported by calling the PUT /Displays endpoint. It is recommended that the request body for PUT /Displays be taken from the content of the GET /Displays/Export response with minimal changes.
You can modify the following fields between the export response and input request body:
ParentId – ID of the parent PI Vision folder. It can be null to indicate that display resides in the root directory. The folder structure should be recreated before the PUT /Displays call.
Owner – Provides the target display owner for the imported display. The format is
DOMAIN\\username.Name – Sets the PI Vision display name. The maximum length is 1024 characters.
Identities – Specifies the list of AF identity groups that have access to the imported display. To get the list of available AF identities, use the
OSIsoft.AF.AFSecurityIdentity.FindSecurityIdentitiesmethod from OSIsoft.AFSDK. To get the list of current identities for a specific display, use the GET /Displays/{id}/AccessControl endpoint.Labels – Labels associated with the PI Vision display. The maximum label name length is 100 characters.
It is also possible to get and set identities by using the GET /Displays/{id}/AccessControl and PUT /Displays/{id}/AccessControl endpoints.
Folders structure can be managed by using the GET /Folders and PUT /Folder endpoints. Folder name has a maximum length of 1024 characters.
In general, the typical workflow for using the PI Vision Display API should be:
Use GET /Folders and GET /Displays to select displays.
Export displays into temporary storage (memory, file on disk, etc.) using the GET /Displays/{id}/Export endpoint.
Adjust the folder structure on the target PI Vision server by using the GET /Folders and PUT /Folders endpoints.
Update the supported fields for every imported display. For example: updating the target Folder Id in ParentId field or replacing the owner in Owner field.
Import displays into designated location using the PUT /Displays endpoint.
Handling duplicate display names
In cases where displays are imported using the API to a location already containing one or more displays of the same name, use the DuplicateDisplayWriteBehavior field within the display definition to indicate the desired behavior. The same field is returned in the response when the import is completed.
Within the display definition, the DuplicateDisplayWriteBehavior property is added to the top level, and contains one of the following values:
"DuplicateDisplayWriteBehavior": "Append"
"DuplicateDisplayWriteBehavior": "Overwrite"
"DuplicateDisplayWriteBehavior": "Skip"
Append
A value of Append creates a new PI Vision display in the target folder with a numeral in parentheses appended to the display name.
The response from the import call reflects this new name and the result of the import operation:
{
"Id": 17,
"Name": "Sample Display (1)",
"PatchErrors": [
],
"DuplicateDisplayWriteBehavior": "Append"
}
Append is the default value for DuplicateDisplayWriteBehavior. If the display definition for the PI Vision display to be imported does not contain DuplicateDisplayWriteBehavior, the default behavior is to create a new display in the target folder with a modified display name.
Overwrite
A value of Overwrite overwrites a PI Vision display with the same name as the imported display definition if it already exists.
The response from the import call reflects this new name and the result of the import operation:
{
"Id": 18,
"PatchErrors": null,
"DuplicateDisplayWriteBehavior": "Overwrite"
}
Skip
A value of Skip does not replace a PI Vision display in the target location if a display with the same name as the imported display definition already exists.
The response from the import call reflects this and the result of the import operation:
{
"Name": "Sample Display",
"PatchErrors": [
],
"DuplicateDisplayWriteBehavior": "Skip"
}
Examples
To illustrate possible uses of the API, the following example PowerShell scripts show how the API can perform common operations, such as exporting and importing displays. These scripts are meant to be a guide to illustrate the various features of the PI Vision display API. The scripts include:
Export.ps1exports PI Vision displays and saves them as .json files on diskImport.ps1reads PI Vision displays from .json files on disk and imports them into PI VisionFunctions.ps1contains shared functions used by the above two scriptsGetToken.ps1retreives an access token from the Identity Server (usable if PI Vision is configured for OpenID Connect)
To experiment with these scripts, copy them to your local environment and save them as .ps1 files, then invoke the scripts with the required parameters. For example:
# Export all displays from PI Vision folder 'Example\Folder' to files stored in .\displays
.\Export.ps1 -SourceServer 'https://SourceServer/pivision' -SourceFolderPath 'Example', 'Folder'
# Read the display files from .\displays and write them to a different PI Vision server under the 'Imported' folder
.\Import.ps1 -DestinationServer 'https://DestServer/pivision' -DestinationFolderPath 'Imported'
Or if your PI Vision server is configured to use OpenID Connect, get an access token first and pass it as a parameter to the other scripts:
# Get an access token and store it so we can pass it to PI Vision
$token = .\GetToken.ps1 -PIVisionServer 'https://SourceServer/PIVision'
# Export all displays from the Home folder of PI Vision and write them to 'C:\temp\exports'
.\Export.ps1 -SourceServer 'https://SourceServer/pivision' -DestinationDirectory 'C:\temp\exports' -Token $token
Export displays to disk
The following script, Export.ps1, exports all PI Vision displays from a PI Vision folder and stores them as files in a local directory (defaults to .\displays).
#requires -version 4
<#
.SYNOPSIS
An example script capable of exporting PI Vision displays to disk.
.DESCRIPTION
Read displays from the PI Vision server and write them as .json files into the
provided destination folder.
This script does not have comprehensive error handling (no retries, no skips).
#>
param(
# The source PI Vision server (without trailing slash)
[Parameter(Mandatory)]
[string]$SourceServer,
# The source PI Vision folder path, as a list of folder names.
# If your folder is "Demo\Test1", you would pass "-SourceFolderPath 'Demo', 'Test1'"
# To read displays from the Home folder, do not pass a value to this parameter.
[string[]]$SourceFolderPath,
# Destination directory to write displays into. Default is '.\displays'
[string]$DestinationDirectory = '.\displays',
# Bearer token to use when connecting to PI Vision. Not required if connecting
# to PI Vision using Windows authentication.
[string]$Token = $null
)
# Stop if any errors occur
$ErrorActionPreference = 'Stop'
# Import functions
Import-module "$PSScriptRoot\functions.ps1" -Force
# Create destination directory if missing
if (-not (Test-Path $DestinationDirectory)) {
New-Item -Path $DestinationDirectory -ItemType Directory
}
# Ensure we can connect to the PI Vision server
Test-PIVisionApiConnection -ServerUrl $sourceServer -Token $Token
# If folder path was requested, find the Folder ID for the given folder path
if ($SourceFolderPath.Count) {
$sourceFolderId = Get-FolderId -ServerUrl $SourceServer -FolderPath $SourceFolderPath -Token $Token
Write-Host "Found source folder ID: $sourceFolderId"
}
# Read displayIds from server
$displayIds = Get-DisplayIds -ServerUrl $sourceServer -FolderId $sourceFolderId -Token $Token
Write-Host "Found $($displayIds.Count) displays"
# Read the displays and save them as .json files to the destination directory
$current = 0
foreach ($displayId in $displayIds) {
# Report progress
Write-Progress -Activity "Copying $($displayIds.Count) displays" -Status "Display ID $displayId" -PercentComplete ($current/$displayIds.Count*100)
$displayInfo = Read-Display -ServerUrl $sourceServer -DisplayId $displayId -Token $Token
Write-DisplayToDirectory -Directory $DestinationDirectory -DisplayId $displayId -DisplayInfo $displayInfo
$current += 1
}
Write-Host "`r`nDone."
Import displays from disk
The following script, Import.ps1, imports display files from a local directory into the destination PI Vision folder.
#requires -version 4
<#
.SYNOPSIS
An example script capable of importing PI Vision displays from disk.
.DESCRIPTION
Read displays from .json files in the provided source folder and write them to the
target PI Vision server under the specified folder.
This script does not have comprehensive error handling (no retries, no skips).
#>
param(
# The destination PI Vision server (without trailing slash)
[string]$DestinationServer,
# The destination PI Vision folder path, as a list of folder names.
# If your folder is "Demo\Test1", you would pass "-DestinationFolderPath 'Demo', 'Test1'"
# To write to the Home folder, do not pass a value to this parameter.
[string[]]$DestinationFolderPath,
# Source directory to read displays from. Default is '.\displays'
[string]$SourceDirectory = '.\displays',
# Bearer token to use when connecting to PI Vision. Not required if connecting
# to PI Vision using Windows authentication.
[string]$Token = $null
)
# Stop if any errors occur
$ErrorActionPreference = 'Stop'
# Import functions
Import-module "$PSScriptRoot\functions.ps1" -Force
# Ensure we can connect to the PI Vision server
Test-PIVisionApiConnection -ServerUrl $DestinationServer -Token $Token
# If folder path was requested, find the Folder ID for the given folder path
if ($DestinationFolderPath.Count) {
$destinationFolderId = Get-FolderId -ServerUrl $DestinationServer -FolderPath $DestinationFolderPath -Token $Token
Write-Host "Found destination folder ID: $destinationFolderId"
}
else {
Write-Host 'No destination folder specified, using Home folder as destination'
# Displays in the Home folder have "ParentId":null
$destinationFolderId = 'null'
}
# Read the displays from the source directory
$displays = Read-DisplaysFromDirectory -Directory $SourceDirectory
# Write each display to the destination PI Vision folder
$current = 0
foreach ($displayInfo in $displays) {
$parsed = $displayInfo | ConvertFrom-Json
$displayName = $parsed.Display.Name
# Report progress
Write-Progress -Activity "Writing $($displays.Count) displays" -Status "Display '$displayName'" -PercentComplete ($current/$displays.Count*100)
# Update parent ID to reflect the folder we will write the display into
$displayInfo = $displayInfo -creplace '"ParentId":(null|\d+)', "`"ParentId`":$destinationFolderId"
# Write the display and print its new ID
$newId = Write-Display -ServerUrl $DestinationServer -DisplayInfo $displayInfo -Token $Token
Write-Host "Copied '$displayName': new ID $newId"
}
Write-Host "`r`nDone."
Shared functionality
This script, Functions.ps1, contains functions utilized by both the export and import scripts above.
Note: You may need to add character encoding if your file names contain special characters.
function Read-DisplaysFromDirectory {
param(
[string]$Directory
)
$files = Get-ChildItem -Path $Directory -File -Filter "*.json"
$displays = $files | Get-Content
return [array]$displays
}
function Write-DisplayToDirectory {
param(
[string]$Directory,
[int]$DisplayId,
[string]$DisplayInfo
)
$fileName = "display-$DisplayId.json"
$filePath = Join-Path $Directory $fileName
Set-Content -Path $filePath -Value $displayInfo
}
function Read-Display {
param(
[string]$ServerUrl,
[int]$DisplayId,
[string]$Token = $null
)
$url = "$ServerUrl/utility/api/v1/displays/$DisplayId/export"
$response = Invoke-PIVisionApiRequest -Url $Url -Token $Token
return $response.Content
}
function Write-Display {
param(
[string]$ServerUrl,
[string]$DisplayInfo,
[string]$Token = $null
)
$url = "$ServerUrl/utility/api/v1/displays"
$response = Invoke-PIVisionApiRequest -Url $url -Method 'Put' -Body $DisplayInfo -Token $Token
$parsed = $response | ConvertFrom-Json
return $parsed.Id
}
function Test-PIVisionApiConnection {
param(
[string]$ServerUrl,
[string]$Token = $null
)
Write-Host "Testing connection to '$ServerUrl'..."
$url = $ServerUrl + '/utility/api/v1/version'
$response = Invoke-PIVisionApiRequest -Url $url -Token $Token
Write-Host 'Connected.' -ForegroundColor Green
}
function Get-FolderId {
param(
[string]$ServerUrl,
[string[]]$FolderPath,
[string]$Token = $null
)
$folderPathToReport = $folderPath -join "/"
foreach ($folderName in $FolderPath) {
$url = "$ServerUrl/utility/api/v1/folders?count=10000"
if ($null -ne $folderId) {
$url += "&folderId=$folderId"
}
# Server request
$response = Invoke-PIVisionApiRequest -Url $url -Token $Token
$parsed = $response.Content | ConvertFrom-Json
# update $folderId
$matchingFolder = $parsed.Items | Where-Object Name -eq $folderName
if ($null -eq $matchingFolder) {
throw "Folder with path [$folderPathToReport] not found"
}
$folderId = $matchingFolder.Id
}
return $folderId
}
function Get-DisplayIds {
param(
[string]$ServerUrl,
[Nullable[int]]$FolderId,
[string]$Token = $null
)
$url = "$ServerUrl/utility/api/v1/displays?count=10000"
if ($null -ne $FolderId) {
$url += "&folderId=$FolderId"
}
$response = Invoke-PIVisionApiRequest $url -Token $Token
$parsed = $response.Content | ConvertFrom-Json
return $parsed.Items.Id
}
function Invoke-PIVisionApiRequest {
param(
[string]$Url,
[string]$Token,
[string]$Method = 'Get',
[object]$Body = $null
)
$Headers = @{ 'Content-Type' = 'application/json; charset=utf-8' }
# Add the X-Requested-With header if making any request type other than GET.
if ($Method -INE 'Get') {
$Headers['X-Requested-With'] = 'PowerShell'
}
# If a token is provided, include it in the headers of the request. Only one of these
# headers will actually be used by PI Vision, the other will be ignored. Feel free
# to remove the line for the header you are not using.
if ($Token) {
# If PI Vision is using "OpenID Connect only", it will read the token from this header.
$Headers['Authorization'] = "Bearer $Token"
# If PI Vision is using "OpenID Connect and prompt for Windows credentials when required",
# it will read the token from this header.
$Headers['PVBearerToken'] = $Token
}
return Invoke-WebRequest -Uri $Url -Method $Method -Headers $Headers -Body $Body -UseBasicParsing -UseDefaultCredentials
}
Retrieve an access token (for OpenID Connect)
The following script, GetToken.ps1, requests an access token from the current Identity Server using Windows authentication as the current signed-on Windows user. It first requests the current AIM Identity Server from PI Vision using the AuthenticationInfo endpoint.
#requires -version 4
<#
.SYNOPSIS
Retrieve an access token for the current user from the current Identity Server.
.DESCRIPTION
Authenticate to the current Identity Server using the current Windows identity to retrieve
an access token that is usable with the PI Vision API.
#>
param(
# Address of the PI Vision server
[string]$PIVisionServer
)
$ErrorActionPreference = 'Stop'
Write-Host 'Getting current Identity Server from PI Vision server ...' -ForegroundColor DarkGray
$authenticationInfoResponse = Invoke-WebRequest -Uri "$PIVisionServer/utility/api/v1/authenticationinfo"
$authenticationInfo = $authenticationInfoResponse.Content | ConvertFrom-Json
if (!($authenticationInfo.AuthenticationMode -in @('Oidc', 'OidcAndWindows')))
{
Write-Error "PIVision is not configured to use OIDC authentication. Current mode: $($authenticationInfo.AuthenticationMode)"
exit 1
}
$IdentityServer = $authenticationInfo.Authority
Write-Host "Current Identity Server: $($IdentityServer)" -ForegroundColor DarkGray
Write-Host "Authenticating with Identity Server $($IdentityServer) using current Windows identity..." -ForegroundColor DarkGray
$tokenResponse = Invoke-WebRequest -Uri "$IdentityServer/account/windowslogin" `
-UseBasicParsing `
-UseDefaultCredentials `
-Method Post `
-ContentType 'application/x-www-form-urlencoded' `
-Body @{
'client_id' = 'AIM_DefaultManagementClient'
'grant_type' = 'windows'
}
$parsed = $tokenResponse.Content | ConvertFrom-Json
Write-Host "Success! Token expires in $($parsed.expires_in) seconds" -ForegroundColor DarkGray
return $parsed.access_token