PIWebAPI 1.0.0
dotnet add package PIWebAPI --version 1.0.0
NuGet\Install-Package PIWebAPI -Version 1.0.0
<PackageReference Include="PIWebAPI" Version="1.0.0" />
<PackageVersion Include="PIWebAPI" Version="1.0.0" />
<PackageReference Include="PIWebAPI" />
paket add PIWebAPI --version 1.0.0
#r "nuget: PIWebAPI, 1.0.0"
#:package PIWebAPI@1.0.0
#addin nuget:?package=PIWebAPI&version=1.0.0
#tool nuget:?package=PIWebAPI&version=1.0.0
PIWebAPI - REST API Documentation
A .NET Framework 4.8 REST API for accessing OSIsoft PI System data via the AF SDK.
Base URL: http://{host}:{port}/api
Table of Contents
- Authentication
- Common Concepts
- Points API
- Streams API
- StreamSets API
- AF Hierarchy API
- Event Frames API
- Health API
- Data Models
- Error Handling
Authentication
The API uses Windows Integrated Authentication (NTLM/Kerberos). Clients must provide valid Windows credentials that have appropriate permissions on the PI Data Archive and AF Server.
Common Concepts
WebId
All resources are identified by a WebId - a Base64-encoded identifier with a type prefix:
| Prefix | Type |
|---|---|
P |
PI Point |
E |
AF Element |
A |
AF Attribute |
D |
AF Database |
F |
Event Frame |
Time Syntax
The API supports both ISO 8601 and PI time syntax:
| Syntax | Description | Example |
|---|---|---|
* or now |
Current time | * |
*-{n}{unit} |
Relative past | *-1h, *-7d |
*+{n}{unit} |
Relative future | *+30m |
t or today |
Start of today (midnight) | t |
y or yesterday |
Start of yesterday | y |
| ISO 8601 | Absolute timestamp | 2024-01-15T10:00:00Z |
Interval Syntax
Time intervals use the format {n}{unit}:
| Unit | Description |
|---|---|
ms |
Milliseconds |
s |
Seconds |
m |
Minutes |
h |
Hours |
d |
Days |
w |
Weeks |
Examples: 500ms, 30s, 5m, 1h, 1d, 1w
Summary Types
Available summary/aggregate types:
Average- Time-weighted averageTotal- Sum of valuesMinimum- Minimum valueMaximum- Maximum valueCount- Number of valuesRange- Max minus MinStdDev- Standard deviationPopulationStdDev- Population standard deviationPercentGood- Percentage of good quality values
Points API
Endpoints for PI Points (tags) in the PI Data Archive.
Search Points
GET /api/points?nameFilter={pattern}&maxResults={n}
| Parameter | Type | Default | Description |
|---|---|---|---|
nameFilter |
string | * |
Name pattern with wildcards |
maxResults |
int | 100 |
Maximum results (1-10000) |
Response: PointDto[]
Get Point
GET /api/points/{webId}
Response: PointDto
Get Current Value
GET /api/points/{webId}/value
Response: TimeSeriesValueDto
Update Current Value
PUT /api/points/{webId}/value
Content-Type: application/json
{
"timestamp": "2024-01-15T10:00:00Z",
"value": 42.5,
"good": true
}
Get Recorded Values
GET /api/points/{webId}/recorded?startTime={start}&endTime={end}&maxCount={n}
| Parameter | Type | Default | Description |
|---|---|---|---|
startTime |
string | *-1h |
Start time |
endTime |
string | * |
End time |
maxCount |
int | 10000 |
Maximum values (1-1000000) |
Response: TimeSeriesValueDto[]
Get Recorded Values with Filter
GET /api/points/{webId}/recordedfiltered?startTime={start}&endTime={end}&filterExpression={expr}
| Parameter | Type | Default | Description |
|---|---|---|---|
startTime |
string | *-1h |
Start time |
endTime |
string | * |
End time |
boundaryType |
string | Inside |
Inside, Outside, Interpolated |
filterExpression |
string | - | PI expression filter |
includeFilteredValues |
bool | false |
Include filtered values |
maxCount |
int | 10000 |
Maximum values |
Response: TimeSeriesValueDto[]
Get Recorded Values by Count
GET /api/points/{webId}/recordedbycount?time={time}&count={n}&direction={dir}
| Parameter | Type | Default | Description |
|---|---|---|---|
time |
string | * |
Reference time |
count |
int | 100 |
Number of values (1-100000) |
direction |
string | Backward |
Forward or Backward |
Response: TimeSeriesValueDto[]
Get Recorded Values at Times
GET /api/points/{webId}/recordedattimes?times={timestamps}&retrievalMode={mode}
| Parameter | Type | Default | Description |
|---|---|---|---|
times |
string | - | Comma-separated timestamps |
retrievalMode |
string | Auto |
Auto, AtOrBefore, AtOrAfter, Exact |
Response: TimeSeriesValueDto[]
Get Interpolated Values
GET /api/points/{webId}/interpolated?startTime={start}&endTime={end}&interval={interval}
| Parameter | Type | Default | Description |
|---|---|---|---|
startTime |
string | *-1h |
Start time |
endTime |
string | * |
End time |
interval |
string | 1h |
Interpolation interval |
Response: TimeSeriesValueDto[]
Get Interpolated Values at Times
GET /api/points/{webId}/interpolatedattimes?times={timestamps}
| Parameter | Type | Description |
|---|---|---|
times |
string | Comma-separated timestamps |
Response: TimeSeriesValueDto[]
Get Plot Values
Optimized for visualization - returns significant values that capture data shape.
GET /api/points/{webId}/plot?startTime={start}&endTime={end}&intervals={n}
| Parameter | Type | Default | Description |
|---|---|---|---|
startTime |
string | *-8h |
Start time |
endTime |
string | * |
End time |
intervals |
int | 640 |
Number of intervals (1-10000) |
Response: TimeSeriesValueDto[]
Get Summary
GET /api/points/{webId}/summary?startTime={start}&endTime={end}&summaryType={type}
| Parameter | Type | Default | Description |
|---|---|---|---|
startTime |
string | *-1d |
Start time |
endTime |
string | * |
End time |
summaryType |
string | Average |
Summary type |
summaryDuration |
string | - | Duration per summary period |
Response: SummaryDto[]
Get Multiple Summaries
GET /api/points/{webId}/summaries?startTime={start}&endTime={end}&summaryTypes={types}
| Parameter | Type | Default | Description |
|---|---|---|---|
startTime |
string | *-1d |
Start time |
endTime |
string | * |
End time |
summaryTypes |
string | Average,Minimum,Maximum,Total |
Comma-separated types |
summaryDuration |
string | - | Duration per period |
calculationBasis |
string | TimeWeighted |
TimeWeighted or EventWeighted |
Response: Dictionary<string, SummaryDto[]>
Get Percent Good
GET /api/points/{webId}/percentgood?startTime={start}&endTime={end}
Response: PercentGoodDto
Get Time-Weighted Value
GET /api/points/{webId}/timeweightedvalue?startTime={start}&endTime={end}
Response: TimeSeriesValueDto
Get End of Stream
GET /api/points/{webId}/end
Response: TimeSeriesValueDto
Write Values
POST /api/points/{webId}/recorded?updateOption={option}&bufferOption={buffer}
Content-Type: application/json
[
{ "timestamp": "2024-01-15T10:00:00Z", "value": 42.5, "good": true },
{ "timestamp": "2024-01-15T10:01:00Z", "value": 43.2, "good": true }
]
| Parameter | Type | Default | Description |
|---|---|---|---|
updateOption |
string | Replace |
Replace, Insert, NoReplace, ReplaceOnly, InsertNoCompression, Remove |
bufferOption |
string | BufferIfPossible |
BufferIfPossible, DoNotBuffer, Buffer |
Response: WriteResultDto
Replace Values in Range
PUT /api/points/{webId}/recorded?startTime={start}&endTime={end}
Content-Type: application/json
[
{ "timestamp": "2024-01-15T10:00:00Z", "value": 42.5, "good": true }
]
Response: WriteResultDto
Delete Values in Range
DELETE /api/points/{webId}/recorded?startTime={start}&endTime={end}
Response: { "deletedCount": 5 }
Get Point Attributes
GET /api/points/{webId}/attributes
Response: Dictionary<string, object>
Update Point Attributes
PUT /api/points/{webId}/attributes
Content-Type: application/json
{
"descriptor": "Updated description",
"engunits": "degC"
}
Get Annotations
GET /api/points/{webId}/annotations?time={timestamp}
Response: AnnotationDto[]
Create Annotation
POST /api/points/{webId}/annotations?time={timestamp}
Content-Type: application/json
{
"name": "Operator Note",
"value": "Sensor calibrated"
}
Streams API
Unified data access for both PI Points and AF Attributes.
Get Value
GET /api/streams/{webId}/value
Works with both PI Point (P prefix) and AF Attribute (A prefix) WebIds.
Response: TimeSeriesValueDto
Update Value
PUT /api/streams/{webId}/value
Content-Type: application/json
{
"timestamp": "2024-01-15T10:00:00Z",
"value": 42.5,
"good": true
}
Get Recorded Values
GET /api/streams/{webId}/recorded?startTime={start}&endTime={end}&maxCount={n}
Response: TimeSeriesValueDto[]
Get Interpolated Values
GET /api/streams/{webId}/interpolated?startTime={start}&endTime={end}&interval={interval}
Response: TimeSeriesValueDto[]
Get Plot Values
GET /api/streams/{webId}/plot?startTime={start}&endTime={end}&intervals={n}
Response: TimeSeriesValueDto[]
Get Summary
GET /api/streams/{webId}/summary?startTime={start}&endTime={end}&summaryType={type}
Response: SummaryDto[]
Get Multiple Summaries
GET /api/streams/{webId}/summaries?startTime={start}&endTime={end}&summaryTypes={types}
Response: Dictionary<string, SummaryDto[]>
Get Multiple Values
GET /api/streams/values?webIds={id1},{id2},{id3}
| Parameter | Type | Description |
|---|---|---|
webIds |
string | Comma-separated WebIds (max 100) |
Response: Dictionary<string, TimeSeriesValueDto>
Write Values
POST /api/streams/{webId}/recorded?updateOption={option}&bufferOption={buffer}
Content-Type: application/json
[
{ "timestamp": "2024-01-15T10:00:00Z", "value": 42.5, "good": true }
]
Response: WriteResultDto
StreamSets API
Bulk operations on multiple streams for efficient data retrieval.
Get Current Values (GET)
GET /api/streamsets/value?webIds={id1},{id2},{id3}
| Parameter | Type | Description |
|---|---|---|
webIds |
string | Comma-separated WebIds (max 1000) |
Response: Dictionary<string, TimeSeriesValueDto>
Get Current Values (POST)
POST /api/streamsets/value
Content-Type: application/json
{
"webIds": ["P...", "P...", "A..."]
}
Response: Dictionary<string, TimeSeriesValueDto>
Get Recorded Values
GET /api/streamsets/recorded?webIds={ids}&startTime={start}&endTime={end}&maxCount={n}
| Parameter | Type | Default | Description |
|---|---|---|---|
webIds |
string | - | Comma-separated WebIds (max 100) |
startTime |
string | *-1h |
Start time |
endTime |
string | * |
End time |
maxCount |
int | 1000 |
Max values per stream |
Response: Dictionary<string, TimeSeriesValueDto[]>
Get Interpolated Values
GET /api/streamsets/interpolated?webIds={ids}&startTime={start}&endTime={end}&interval={interval}
Response: Dictionary<string, TimeSeriesValueDto[]>
Get Plot Values
GET /api/streamsets/plot?webIds={ids}&startTime={start}&endTime={end}&intervals={n}
Response: Dictionary<string, TimeSeriesValueDto[]>
Get Summary Values
GET /api/streamsets/summary?webIds={ids}&startTime={start}&endTime={end}&summaryTypes={types}
Response: Dictionary<string, Dictionary<string, SummaryDto[]>>
Get End of Stream Values
GET /api/streamsets/end?webIds={ids}
Response: Dictionary<string, TimeSeriesValueDto>
Batch Write Values
POST /api/streamsets/recorded/batch
Content-Type: application/json
{
"updateOption": "Replace",
"bufferOption": "BufferIfPossible",
"items": [
{
"webId": "P...",
"values": [
{ "timestamp": "2024-01-15T10:00:00Z", "value": 42.5, "good": true }
]
},
{
"webId": "P...",
"values": [
{ "timestamp": "2024-01-15T10:00:00Z", "value": 100.0, "good": true }
]
}
]
}
Response: Dictionary<string, WriteResultDto>
AF Hierarchy API
Endpoints for navigating the Asset Framework hierarchy.
List Databases
GET /api/af/databases
Response: AFDatabaseDto[]
Get Database
GET /api/af/databases/{webId}
Response: AFDatabaseDto
Get Database Elements
GET /api/af/databases/{webId}/elements?depth={n}
| Parameter | Type | Default | Description |
|---|---|---|---|
depth |
int | 0 |
Hierarchy depth (0-10) |
Response: AFElementDto[]
Get Elements
GET /api/af/elements?path={path}&depth={n}
| Parameter | Type | Default | Description |
|---|---|---|---|
path |
string | - | AF path (e.g., \\Server\Database\Element) |
depth |
int | 0 |
Hierarchy depth (0-10) |
Response: AFElementDto[]
Get Element
GET /api/af/elements/{webId}
Response: AFElementDto
Get Child Elements
GET /api/af/elements/{webId}/children
Response: AFElementDto[]
Get Element Attributes
GET /api/af/elements/{webId}/attributes
Response: AFAttributeDto[]
Get Attribute
GET /api/af/attributes/{webId}
Response: AFAttributeDto
Get Attribute Value
GET /api/af/attributes/{webId}/value
Response: TimeSeriesValueDto
Search AF Hierarchy
GET /api/af/search?query={query}&scope={scope}&maxResults={n}
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
string | - | AF search query |
scope |
string | Elements |
Elements or Attributes |
maxResults |
int | 100 |
Maximum results (1-10000) |
Response: AFElementDto[]
Event Frames API
Endpoints for AF Event Frames.
Search Event Frames
GET /api/eventframes?startTime={start}&endTime={end}&nameFilter={filter}
| Parameter | Type | Default | Description |
|---|---|---|---|
startTime |
string | *-1d |
Start time |
endTime |
string | * |
End time |
nameFilter |
string | * |
Name pattern with wildcards |
templateName |
string | - | Template name filter |
referencedElementWebId |
string | - | Element WebId to search within |
searchMode |
string | Overlapped |
Overlapped, StartInRange, EndInRange, InProgress |
maxCount |
int | 1000 |
Maximum results |
Response: EventFrameDto[]
Get Event Frame
GET /api/eventframes/{webId}
Response: EventFrameDto
Get Event Frames for Element
GET /api/eventframes/element/{elementWebId}?startTime={start}&endTime={end}
Response: EventFrameDto[]
Create Event Frame
POST /api/eventframes
Content-Type: application/json
{
"name": "Equipment Failure",
"description": "Pump P-101 tripped",
"startTime": "2024-01-15T10:00:00Z",
"templateName": "Equipment Alarm",
"refElementWebIds": ["E..."]
}
Response: EventFrameDto
Update Event Frame
PUT /api/eventframes/{webId}
Content-Type: application/json
{
"name": "Updated Name",
"description": "Updated description"
}
End Event Frame
POST /api/eventframes/{webId}/end?endTime={time}
| Parameter | Type | Default | Description |
|---|---|---|---|
endTime |
string | * (now) |
End time |
Delete Event Frame
DELETE /api/eventframes/{webId}
Acknowledge Event Frame
POST /api/eventframes/{webId}/acknowledge
Get Event Frame Attributes
GET /api/eventframes/{webId}/attributes
Response: AFAttributeDto[]
Capture Values
POST /api/eventframes/{webId}/capturevalues
Health API
Endpoints for monitoring API and connection health.
Overall Health
GET /api/health
Response:
{
"status": "Healthy",
"version": "1.0.0",
"components": [
{
"status": "Healthy",
"component": "PI Data Archive",
"details": { ... }
},
{
"status": "Healthy",
"component": "AF Server",
"details": { ... }
}
]
}
PI Data Archive Health
GET /api/health/pi
Response: HealthDto
AF Server Health
GET /api/health/af
Response: HealthDto
Liveness Check
GET /api/health/live
Response:
{
"status": "alive",
"timestamp": "2024-01-15T10:00:00Z"
}
Readiness Check
GET /api/health/ready
Returns 200 OK if ready, 503 Service Unavailable if not.
Response:
{
"status": "ready",
"timestamp": "2024-01-15T10:00:00Z",
"pi": "Healthy",
"af": "Healthy"
}
Data Models
TimeSeriesValueDto
{
"timestamp": "2024-01-15T10:00:00Z",
"value": 42.5,
"good": true,
"questionable": false,
"substituted": false,
"annotated": false
}
| Field | Type | Description |
|---|---|---|
timestamp |
DateTime | UTC timestamp |
value |
object | Value (numeric, string, or digital state) |
good |
bool | Good quality flag |
questionable |
bool | Questionable quality flag |
substituted |
bool | Value was substituted |
annotated |
bool | Has annotations |
PointDto
{
"webId": "P...",
"name": "SINUSOID",
"description": "12 Hour Sine Wave",
"pointType": "Float32",
"engineeringUnits": "degC",
"pointClass": "classic",
"digitalSetName": null,
"future": false,
"step": false,
"zero": 0.0,
"span": 100.0,
"serverName": "PI-SERVER"
}
SummaryDto
{
"type": "Average",
"timestamp": "2024-01-15T10:00:00Z",
"value": 42.5,
"good": true
}
AFElementDto
{
"webId": "E...",
"name": "Pump-101",
"description": "Main cooling pump",
"path": "\\\\Server\\Database\\Plant\\Pump-101",
"templateName": "Pump",
"categoryNames": ["Critical Equipment"],
"hasChildren": true,
"attributes": [ ... ],
"children": [ ... ]
}
AFAttributeDto
{
"webId": "A...",
"name": "Temperature",
"description": "Process temperature",
"path": "\\\\Server\\Database\\Plant\\Pump-101|Temperature",
"type": "Double",
"defaultUOM": "degC",
"dataReferencePlugIn": "PI Point",
"configString": "\\\\PI-SERVER\\PUMP101.TEMP",
"hasChildren": false
}
EventFrameDto
{
"webId": "F...",
"name": "Equipment Failure",
"description": "Pump tripped due to high temperature",
"path": "\\\\Server\\Database\\EventFrames\\Equipment Failure",
"startTime": "2024-01-15T10:00:00Z",
"endTime": "2024-01-15T11:30:00Z",
"duration": "01:30:00",
"templateName": "Equipment Alarm",
"categoryNames": ["Alarms", "Critical"],
"severity": "High",
"isAcknowledged": true,
"acknowledgedBy": "DOMAIN\\operator",
"acknowledgedDate": "2024-01-15T10:05:00Z",
"refElementWebIds": ["E..."],
"attributes": [ ... ]
}
WriteResultDto
{
"success": true,
"affectedCount": 5,
"errors": []
}
HealthDto
{
"status": "Healthy",
"component": "PI Data Archive",
"details": {
"serverName": "PI-SERVER",
"serverVersion": "2018 SP3",
"connected": true,
"pointCount": 50000
}
}
Error Handling
All errors return a consistent JSON structure:
{
"error": {
"code": "NotFound",
"message": "PI Point with WebId 'P...' not found.",
"details": null
}
}
HTTP Status Codes
| Code | Description |
|---|---|
200 |
Success |
201 |
Created (POST) |
400 |
Bad Request - Invalid parameters |
401 |
Unauthorized - Authentication required |
403 |
Forbidden - Insufficient permissions |
404 |
Not Found - Resource doesn't exist |
500 |
Internal Server Error |
503 |
Service Unavailable - PI/AF connection failed |
Examples
Get Last Hour of Data for a Point
curl -X GET "http://localhost/api/points/P.../recorded?startTime=*-1h&endTime=*" \
--ntlm -u :
Get Current Values for Multiple Points
curl -X GET "http://localhost/api/streamsets/value?webIds=P...,P...,P..." \
--ntlm -u :
Write Values to a Point
curl -X POST "http://localhost/api/points/P.../recorded" \
-H "Content-Type: application/json" \
--ntlm -u : \
-d '[
{"timestamp": "2024-01-15T10:00:00Z", "value": 42.5, "good": true},
{"timestamp": "2024-01-15T10:01:00Z", "value": 43.2, "good": true}
]'
Create an Event Frame
curl -X POST "http://localhost/api/eventframes" \
-H "Content-Type: application/json" \
--ntlm -u : \
-d '{
"name": "Maintenance Window",
"description": "Scheduled pump maintenance",
"startTime": "2024-01-15T08:00:00Z",
"refElementWebIds": ["E..."]
}'
Swagger UI
Interactive API documentation is available at:
http://{host}:{port}/swagger
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- Microsoft.AspNet.WebApi.Client (>= 5.2.9)
- Microsoft.AspNet.WebApi.Core (>= 5.2.9)
- Microsoft.AspNet.WebApi.WebHost (>= 5.2.9)
- Microsoft.Web.Infrastructure (>= 1.0.0)
- Newtonsoft.Json (>= 13.0.3)
- Polly (>= 7.2.4)
- Serilog (>= 2.12.0)
- Serilog.Sinks.Console (>= 4.1.0)
- Serilog.Sinks.File (>= 5.0.0)
- Swashbuckle (>= 5.6.0)
- Swashbuckle.Core (>= 5.6.0)
- Unity (>= 5.11.10)
- Unity.Abstractions (>= 5.11.7)
- Unity.Container (>= 5.11.11)
- Unity.WebAPI (>= 5.4.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 136 | 12/22/2025 |
## v1.0.0
- Initial release
- Full PI Points data access (recorded, interpolated, plot, summary)
- AF hierarchy navigation (databases, elements, attributes)
- Streams API for unified PI Point and AF Attribute access
- StreamSets API for bulk operations
- Event Frames CRUD operations
- Calculation/expression evaluation
- Templates and Tables support
- Unit of Measure conversions
- Health check endpoints