Receive AVEVA PI Event Frames by Webhook
Your PI integration can push each event frame to the Innovapptive webhook instead of being polled.
Endpoint
Your PI integration (PI Notifications, a custom service, or another connector in front of PI) calls Innovapptive. Innovapptive gives you the full URL for your tenant:
POST https://{innovapptive-host}/esis/webhook/{yourTenantId}/pi_af
Content-Type: application/json
Sign in with one of the methods in Authentication. These credentials are only for calling Innovapptive; they are not the account Innovapptive uses to call your PI Web API.
Responses
| Response | Meaning |
|---|---|
| HTTP 401 | The credential is missing or invalid. The event is not accepted. |
HTTP 200 with { "success": true } | Innovapptive has stored the event frame. |
HTTP 200 does not change anything in PI, and it does not prove that the later acknowledgement write succeeded. After storing the event, Innovapptive writes the acknowledgement attribute as a separate call. See Write Acknowledgements and Round Readings to AVEVA PI.
Payload
Tag readings come from values only. values can be { "Items": [ ... ] } or a plain array. The reading must be nested at Value.Value; a single flat value in Value is not read. The timestamp used is values.Items[].Timestamp, not Value.Timestamp.
| Field | Required | Purpose |
|---|---|---|
eventType | Yes | Send event_frame |
externalId | Yes | Event-frame WebId. Same value as item.WebId. A retry with the same ID does not create a second event. |
emittedAt | Yes | ISO-8601 time of the event |
item.WebId | Yes | Same event-frame ID as externalId |
item.Name | Yes | Event title |
item.Path | Yes | AF path of the event frame. A tag path is {item.Path}|{Name} when the value has no path of its own. |
item.StartTime | Yes | When the event started |
item.EndTime | No | Omit it while the frame is open. If sent, the event is treated as closed. |
item.Severity | Yes | For example Critical |
item.RefElementWebIds | Yes | Only the first entry is used. It must equal externalIds.id on the TaxonomyNode (system pi_af). |
item.TemplateName, item.CategoryNames, item.referencedAsset | No | Not used. Do not send. |
attributes | No | Not used. Do not send. |
values.Items[].Name | Yes | Tag name. This is how the reading is identified. |
values.Items[].WebId | No | Not used during ingestion |
values.Items[].Timestamp | Yes | Time of the reading |
values.Items[].Value.Value | Yes | The reading: number, string or boolean |
values.Items[].Value.UnitsAbbreviation | Yes | Units of the reading |
values.Items[].Value.Good | Yes | Quality. true means a good value. |
values.Items[].Value.Timestamp | No | Not read |
Sample payload. Replace {{eventId}} with the event-frame WebId, in both externalId and item.WebId.
{
"eventType": "event_frame",
"externalId": "{{eventId}}",
"emittedAt": "2026-10-06T23:15:00Z",
"item": {
"WebId": "{{eventId}}",
"Name": "Test",
"Path": "\\\\PISRV01\\Innovapptive\\Plant1\\PUMP-101\\EventFrames[High Vibration]",
"StartTime": "2026-10-06T23:15:00Z",
"Severity": "Critical",
"RefElementWebIds": [
"10143959"
]
},
"values": {
"Items": [
{
"WebId": "F1AbEAI8QAAAAAAAAAAAAAAAAAAAAAAATTRVIB01",
"Name": "Discharge Pressure",
"Timestamp": "2026-09-10T06:15:00Z",
"Value": {
"Timestamp": "2026-09-10T06:15:00Z",
"Value": 1100,
"UnitsAbbreviation": "psi",
"Good": true
}
},
{
"WebId": "F1AbEAI8QAAAAAAAAAAAAAAAAAAAAAAATTRTMP01",
"Name": "BearingTemp",
"Timestamp": "2026-09-10T06:15:00Z",
"Value": {
"Timestamp": "2026-09-10T06:15:00Z",
"Value": 87.2,
"UnitsAbbreviation": "degC",
"Good": true
}
},
{
"WebId": "F1AbEAI8QAAAAAAAAAAAAAAAAAAAAAAATTRTMP01",
"Name": "Alarm",
"Timestamp": "2026-09-10T06:15:00Z",
"Value": {
"Timestamp": "2026-09-10T06:15:00Z",
"Value": true,
"UnitsAbbreviation": "degC",
"Good": true
}
}
]
}
}
In this sample, 10143959 is the value looked up as externalIds.id on the TaxonomyNode. The Alarm entry repeats the BearingTemp WebId and shows the unit degC for a boolean; these are sample artifacts, and values.Items[].WebId is not used during ingestion.
