This section is made for developers or integrators who would like to integrate with Camlytics Single application.

The REST API allows handling analytical events such as motion detected, camera obstructed, etc. in a custom way. For example, you might want to store events in a remote database, send them to a web service or start an external application.
The API also allows you to receive the list of Camlytics Single channels with complete details - streaming URI, name, etc. This might be helpful if you plan to use your own player to view cameras remotely (via mobile device).


1

How to use REST API

Camlytics Single provides a very simple and universal way to control all camera events and retrieve channels data. In order to integrate with the application via REST API, complete the following steps:

  • Start the application and make sure you have the latest version (min supported version is 1.2.1)
  • Make sure the REST API is enabled in settings (should enabled by default)
  • To verify that the REST API is working, add a channel, generate any event (object appear, etc.) and go to http://localhost:48462/v1/json/events?limit=10&order=DESC&timeout=5. If no events are available, an empty JSON array will be returned.
    In case something went wrong, please refer to logs that are located in %APPDATA%\Camlytics\Logs\.
  • For detailed ducumentation, go through autogenerated REST API reference

The /events endpoint is real time, you will receive new event at the same moment they appear in the video channel.

For additional support contact us at info@camlytics.com


2

REST API example

See the JavaScript implementation example that demonstrates how to integrate with Camlytics Single REST API and receive events in real time.

Note that you can use whatever programming language and framework you prefer. The necessary client code can be generated from Swagger definition file which is compliant with Swagger specifications. Please read more about Swagger here.
Online code generation available at SwaggerHub.


3

Webhooks

If you don't want to write any code to customize events actions locally you can set up the webhook URL for each of the event types. All webhooks are fired via POST request each time the event is created or on hourly/daily basis. Request timeout is 5 seconds.

video camera webhook

There are 3 types of webhooks:

  • Immediate event webhook - fires at the time of the event
  • Hourly aggregate webhook - fires every hour at xx:00
  • Daily aggregate webhook - fires every day at 00:00

Hourly/aggregate webhooks contain sums of the events occurrences grouped by each rule (zone, line) or by each event type (Zone joined, etc.).
See the example of the immediate event webhook request body (JSON):

See the example of the aggregate webhook request body (JSON):

{  
   "channel_id":"ddbbe807-8560-4bc7-b04b-4b3b04c69339",
   "channel_name":"Integrated Camera",
   "event_name":"Line crossed",
   "event_origin":"Pedestrian",
   "event_time":"2019-05-20T18:02:51.2984871+03:00",
   "event_type":"TripwireCrossed",
   "object_id":9,
   "rule_id":"471fa55d-967b-46a7-b77f-5b9ce6af82ee",
   "rule_name":"Line 1"
}
{  
   "channel_id":"ddbbe807-8560-4bc7-b04b-4b3b04c69339",
   "channel_name":"Integrated Camera",
   "event_type_aggregate":[  
      {  
         "event_count":5,
         "event_name":"Line crossed",
         "event_type":"TripwireCrossed"
      },
      {  
         "event_count":0,
         "event_name":"Zone joined",
         "event_type":"RegionJoin"
      },
      {  
         "event_count":0,
         "event_name":"Zone left",
         "event_type":"RegionLeave"
      },
      {  
         "event_count":3,
         "event_name":"Motion started",
         "event_type":"MotionInRegionOn"
      },
      {  
         "event_count":2,
         "event_name":"Motion finished",
         "event_type":"MotionInRegionOff"
      },
      {  
         "event_count":0,
         "event_name":"Object dwell",
         "event_type":"Loitering"
      },
      {  
         "event_count":0,
         "event_name":"Crowd appear",
         "event_type":"CrowdOn"
      },
      {  
         "event_count":0,
         "event_name":"Crowd disappear",
         "event_type":"CrowdOff"
      },
	  {  
         "event_count":0,
         "event_name":"Tailgating",
         "event_type":"Tailgating"
      },
      {  
         "event_count":0,
         "event_name":"Abandoned item",
         "event_type":"AbandonedObject"
      },
      {  
         "event_count":5,
         "event_name":"Object appear",
         "event_type":"ObjectAppear"
      },
      {  
         "event_count":4,
         "event_name":"Object disappear",
         "event_type":"ObjectDisappear"
      },
      {  
         "event_count":1,
         "event_name":"Camera obstructed",
         "event_type":"Sabotage"
      },
      {  
         "event_count":0,
         "event_name":"Camera disconnected",
         "event_type":"CameraDisconnected"
      }
   ],
   "rule_id_aggregate":[  
      {  
         "event_count":5,
         "rule_id":"ab68d96d-b1a6-4b94-8092-3ece52cf707d",
         "rule_name":"Motion detection"
      },
      {  
         "event_count":1,
         "rule_id":"471fa55d-967b-46a7-b77f-5b9ce6af82ee",
         "rule_name":"Line 1"
      },
      {  
         "event_count":2,
         "rule_id":"689351ab-239c-420f-b22e-cfc27fce6806",
         "rule_name":"Line 2"
      },
      {  
         "event_count":2,
         "rule_id":"0e5f132d-3a81-4e16-993c-6a8d4a47e5e1",
         "rule_name":"Line 3"
      }
   ],
   "since_time":"2019-05-20T17:00:00.4024906+03:00",
   "until_time":"2019-05-20T18:00:00.4024906+03:00"
}

4

Webhooks example

A very good example of utilizing webhooks is using Google Sheets as a cloud storage for your Camlytics Single events - you can use those to collect data from multiple locations, build customized charts, etc.

To automate submission of data into your Google Sheet, fill in the columns headers with POST request fields names (channel_id, channel_name, event_name, etc.) and click Tools > Script editor. You will be redirected to a Google Script page. Copy and paste the sample script below into the script editor.

You can get more information on how to set up the script here.

    function doPost(request){
      return handleResponse(request);
    }
    	
    // How to use
    //  1. Enter sheet name where data is to be written below
            var SHEET_NAME = "Sheet1";
            
    //  2. Run > setup
    //
    //  3. Publish > Deploy as web app 
    //    - enter Project Version name and click 'Save New Version' 
    //    - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously) 
    //
    //  4. Copy the 'Current web app URL' and post this in your Camlytics Single webhook URL
    //
    //  5. Insert column names on your destination sheet matching the parameter names of the data you are passing in (exactly matching case)
    	
    var SCRIPT_PROP = PropertiesService.getScriptProperties();
    	
    function handleResponse(request) {
      var lock = LockService.getPublicLock();
      lock.waitLock(1000);
      
      try {
        var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
        var sheet = doc.getSheetByName(SHEET_NAME);
        
        var headRow = 1;
        
        var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
        var nextRow = sheet.getLastRow() + 1;
        var row = []; 
        var postData = JSON.parse(request.postData.getDataAsString());
        
        for (i in headers){
            row.push(postData[headers[i]]);
        }
        sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
        
        return ContentService
              .createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
              .setMimeType(ContentService.MimeType.JSON);
      } catch(e){
        return ContentService
        .createTextOutput(JSON.stringify({"result":"error", "error": e }))
              .setMimeType(ContentService.MimeType.JSON);
      } finally {
        lock.releaseLock();
      }
    }
    	
    function setup() {
        var doc = SpreadsheetApp.getActiveSpreadsheet();
        SCRIPT_PROP.setProperty("key", doc.getId());
    }	

In the end you will receive the production script URL that you will insert into your Camlytics Single events webhook settings in similar format: https://script.google.com/macros/s/aKfycbwRo7V-DNXQSCjplDs-j43Y7evXioFNvy_bQs-NNnofPJ41bA52c67/exec

Example of output in the Google Sheet that you are going to receive:

camlytics google sheet

If you want to get the aggregated event counts (for example, how many people crossed Line 1 for the last hour or for the last day, the following code will insert a new sheet on every call (every hour or every day).

    function doPost(request){
      return handleResponse(request);
    }
    	
    // How to use
           
    //  1. Run > setup
    //
    //  2. Publish > Deploy as web app 
    //    - enter Project Version name and click 'Save New Version' 
    //    - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously) 
    //
    //  3. Copy the 'Current web app URL' and post this in your Camlytics Single webhook URL
    	
    var SHEET_NAME = (new Date()).toLocaleDateString() + ' ' + (new Date()).toLocaleTimeString();
    SpreadsheetApp.getActiveSpreadsheet().insertSheet(SHEET_NAME);
    var SCRIPT_PROP = PropertiesService.getScriptProperties();
    	
    function handleResponse(request) {
      var lock = LockService.getPublicLock();
      lock.waitLock(1000);
      
      try {
        var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
        var sheet = doc.getSheetByName(SHEET_NAME);
        
        var headRow = 1;
        
        var headers = ["rule_name", "event_count"];
        var nextRow = sheet.getLastRow() + 1;
        var row = ["Source name", "Event count"]; 
        sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
        var nextRow = sheet.getLastRow() + 1;
        row = [];
        
        var postData = JSON.parse(request.postData.getDataAsString());
        
        for (j in postData["rule_id_aggregate"]){
          for (i in headers){
            row.push(postData["rule_id_aggregate"][j][headers[i]]);
          }
          sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
          var nextRow = sheet.getLastRow() + 1;
          row = [];
        }
        
        return ContentService
              .createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
              .setMimeType(ContentService.MimeType.JSON);
      } catch(e){
        return ContentService
        .createTextOutput(JSON.stringify({"result":"error", "error": e }))
              .setMimeType(ContentService.MimeType.JSON);
      } finally {
        lock.releaseLock();
      }
    }
    	
    function setup() {
        var doc = SpreadsheetApp.getActiveSpreadsheet();
        SCRIPT_PROP.setProperty("key", doc.getId());
    }

Example of output in the Google Sheet that you are going to receive when events are fired:

camlytics google sheets