Alarm and Event Monitoring with Webhooks

Use the ACS webhook interface to set up webhooks to receive alarms and events from the Avigilon Cloud Services. 

This document includes:

  • Creating Central Station and Site Monitoring

  • Retry Logic

  • Verifying Event Messages

  • Event Message Format

  • Cloud API Endpoints

Unless otherwise specified, all examples are in JSON. For more information about Central Station Monitoring, see Avigilon Online Product Documentation here.

Creating Central Station and Site Monitoring using Webhooks

Central Station is the way that the ACS platform provides for Remote Monitoring Providers to gain access to Customer Sites for purposes of monitoring. An Agent user account is defined for each Central Station.

Note: In order to create a Central Station follow the manual Create a Central Station

Retry Logic

The ACS service acknowledges successful HTTP responses:

  • 200 OK

  • 201 Created

  • 202 Accepted

For connection errors or HTTP request timeouts, the ACS service resend the event with an increasing wait time, up to a maximum of 24 hours after the event has occurred.

After 24 hours, the ACS service will stop sending the event.

Verifying Event Messages

With the Shared Secret Phrase field, you can verify that event messages came from the Avigilon Cloud Services and not a third party.

For security, each Shared Secret Phrase must be unique for each central station configuration. If you support multiple central station configurations or multiple Avigilon dealers, each should have a different Shared Secret Phrase.

For webhooks directed to HTTPS endpoints, each event message contains the Shared Secret Phrase as an authenticationToken.

For webhooks directed to HTTP endpoints, each event message contains a hash-based message authentication code (HMAC)-encrypted authorization header. The entire message payload plus the Shared Secret Phrase are encrypted. Your endpoint can use the authorization header value to verify the authenticity of the message content by recalculating the hash using the Shared Secret Phrase. In this case, the authenticationToken value will be null in the message to avoid man-in-the-middle attacks.

Verifying event messages sent over HTTP

For HTTP endpoints, the HMAC-encrypted authorization header is calculated using a SHA-256 cryptographic hash function, and a secret cryptographic key which is the Shared Secret Phrase.

The HTTP request authorization header is formatted as follows:

Authorization: HMAC-SHA256 t/LN4FhGBhqIRt6dpD6BufeTMKSSjVMRkuLEl6BF6w4=

To verify the message content:

  1. Convert the message payload to UTF8-encoded byte array.

  2. Convert the Shared Secret Phrase to UTF8-encoded byte array.

  3. Compute the SHA-256 hash of the encoded message using the encoded Shared Secret Phrase.

  4. Convert the hash value to a Base-64 string.

  5. Compare the computed Base-64 string with the authorization header value.

The following code demonstrates how to implement message validation:

using Nito.AsyncEx;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading.Tasks;

string computeMessageSignature(string messagePayload, string authenticationToken)
{
var content = System.Text.Encoding.UTF8.GetBytes(messagePayload);
var token = System.Text.Encoding.UTF8.GetBytes(authenticationToken);
using (HMACSHA256 hmacSha256 = new HMACSHA256(token))
{
return Convert.ToBase64String(hmacSha256.ComputeHash(content));
}
}

async Task<bool> validateMessageRequest(HttpRequestMessage request, string authenticationToken)
{
var authHeader = request.Headers.GetValues("Authorization").First();
if (authHeader != null && authHeader.StartsWith("HMAC-SHA256"))
{
var headerHmac = authHeader.Substring("HMAC-SHA256 ".Length).Trim();
var rawMessage = await request.Content.ReadAsStringAsync();
var computedHmac = computeMessageSignature(rawMessage, authenticationToken);
return headerHmac.Equals(computedHmac);
}
return false;
}

[HttpPost]
[Route("IntegrationEvent/Webhook")]
public IHttpActionResult IntegrationWebhook([FromBody] IntegrationEvent integEvent)
{
var result = AsyncContext.Run(() => validateMessageRequest(Request, "authentication token"));
if (!result)
{
throw new Exception("Corrupt Integration Event Message!!!");
}
}

Event Message Format

An Avigilon event message consists of an Envelope and a Payload.

The event message format is as follows:

{ 
"payloadType":"BlueEvent",
"version":"1.0.0",
"messageId":"ebb7bd2c-4f2d-4116-8f59-b671110c9ae1",
"transmitTime":"2019-07-17T21:41:27.7959817Z",
"logCorrelationId":"90c3f1972cd44556abd0628c75d25da5",
"authenticationToken":null,
"payload":{
"Version":"1.0.0",
“agentUserId”:"400107a8-193d-4f03-b669-838bd15d31a4",
“agentUserTenantId”:"400107a8-193d-4f03-b669-838bd15d31a4",
"alarmId":"400107a8-193d-4f03-b669-838bd15d31a4",
"alarmTenantId":"400107a8-193d-4f03-b669-838bd15d31a4",
“eventClass”:”security”,
"eventName":"Person in Area",
"eventType":"TooMany",
"eventRuleName":"Person in Area",
"eventStartTime":"2019-07-17T21:41:20.57",
"eventEndTime":null,
"entityTenantId":"400107a8-193d-4f03-b669-838bd15d31a4",
"locationId":"400107a8-193d-4f03-b669-838bd15d31a4",
"locationName":"Assembly Row",
"serverId":"400107a8-193d-4f03-b669-838bd15d31a4",
"serverName":"VMA-BLU-8P8-211712250387",
"cameraId":"400107a8-193d-4f03-b669-838bd15d31a4",
"cameraName":"3.0C-H3A-BO1-IR (1167038) - Assembly Solid Cam",
"cameraRemoteId": "4321HJghayMNBTE5NStVLTsw1MBASuGH8bWKFnY_VrlmPK2KDWx4AAA",
"clipId":"400107a8-193d-4f03-b669-838bd15d31a4",
"clipUri": "https://blue.avigilon.com/some/path",
"gatewayId":"400107a8-193d-4f03-b669-838bd15d31a4"
}
}

Envelope Object

The message envelope identifies the payload type, the version number, and additional information about the signaling system.


Parameter


Type


Required


Description


payloadType


string


required

The payload type. For central station webhooks, the value is always “BlueEvent”.
Informs the client how to decode the Payload which can then be specified as a polymorphic Object.


version


string


required


The version number of the envelope.


messageId


string


required


The message ID.


transmitTime


string


required


The time the message was sent in ISO 8601 format in UTC.


logCorrelationId


string


required


A correlation ID that can be used to track the message in the Avigilon Cloud Services.


authenticationToken


object


required


If HTTPS is used, the value is the Shared Secret Phrase.
If HTTP is used, the value is “null”.


payload


object


required


The message payload. See Payload Object below.

Payload Object

The payload object contains the event details.


Parameter


Type


Required


Description


version


string


required


The message envelope version number.


agentUserId


string


required


The user ID based on the username and password created to configure the webhook central station.


agentUserTenantId


string


required


The tenant ID based on the username and password created to configure the webhook central station.


alarmId


string


required


The Avigilon Cloud Services alarm ID.


alarmTenantId


string


required


The tenant ID of the organization in which the alarm occurred.


eventClass


string


required


The type of event. Values can be “health” or “security”. Health events refer to device events. Security events refer to video analytics events.


eventName


string


required


The name of the event. This is the same name as the analytic rule that triggered the event.


eventType


string


required


The analytic rule activity that signalled the event.


eventRuleName


string


optional


The name of the analytic rule that triggered the event. This is typically the same value as the eventName.


eventStartTime


string


required


The time the event started in ISO 8601 format in UTC.


eventEndTime


string


optional


The time the event ended in ISO 8601 format in UTC. If the event is ongoing, the value is “null”.


entityTenantId


string


required


The tenant ID of the organization in which the event occurred.


locationId


string


required


The site ID of the server associated with the event.


locationName


string


required


The name of the site associated with the event.


serverId


string


required


The ID of the server associated with the event.


serverName


string


optional


The name of the server associated with the event.


cameraId


string


optional


The ID of the camera associated with the event.


cameraName


string


optional


The name of the camera associated with the event.


cameraRemoteId


string


optional


The ID of a camera from a connected ACC site.


clipId


string


optional


The ID of the event video clip.


clipUri


string


optional


The URI of the event video clip.


gatewayId


string


optional


The Gateway servicing the associated Event Entities.

Cloud API Endpoints

An integrator can respond to an event using the Cloud API. An integration solution can automatically play video related to an alarm.

Using the Cloud API Gateway to Show Alarm-related Video

Note: The procedure below refers to a body of an ACS event received through a webhook connection, using {{Event}} notation.

  • GET /system - to get ACS system capabilities - see API details

    Note: Subsequent requests refer to the response of the previous request using {{response}} notation.
    For example, if the request response is:

    { 
    "id": "00000000-0000-0000-0000-000000000000",
    "name": "SystemName",
    "_links": {
    "rel/self": "SystemUrl",
    "rel/login": "LoginUrl",
    "rel/devices": "DevicesUrl"
    },
    "_system_id": "00000000-0000-0000-0000-000000000000",
    "_type": "System"
    }

    Then the value of {{response._links.”rel/devices”}} is "DevicesUrl".

  • GET {{response._links.”rel/devices”}}

    Note: If {{response._links.”rel/devices”}} doesn’t exist, perform the login operation using the POST method to {{response._links.”rel/login”}}
    and issue GET /system again. See Overview - Authentication for details.

  • In the returned collection of devices, identify the following camera Device where:

    Device.id == Event.payload.cameraId
    Device.status == "online"

    Note: The next request refers to the identified device using the Device variable.

  • GET {{Device._links."rel/data_sources"}}

  • POST {{response._links."rel/rtsp"}}

    request body:

    {
    "cameraId": "{{Event.payload.cameraRemoteId}}",
    "quality":"high",
    "t":"{{Event.payload.eventStartTime}}",,
    "search":"true"
    }
  • Use {{response.rtspRelayURL}} to get the recorded RTSP video stream associated with the event using the RTSP video player of your choice.

Optimization Hints

  • An integration should perform login and get system capabilities only once - during initialization

  • A list of camera devices and {{Device._links."rel/data_sources"}} can be cached and/or refreshed in the background.