Webhooks

You can set up FindFace Security to automatically send notifications about specific events, episodes, and counter records to a given URL. To do so, create and configure a webhook. In this case, when such an event, episode, or counter record occurs, FindFace Security will send an HTTP request to the URL configured for the webhook.

You can use webhooks for various purposes, for example, to notify a user about a specific event, invoke required behavior on a target website, solve security tasks such as automated access control, etc.

In this section:

Configure Webhook

Important

You need Administrator privileges to create a webhook.

Note

To use the webhooks, be sure that at least one of the following parameters is specified in /etc/ffsecurity/config.py: SERVICE_EXTERNAL_ADDRESS or EXTERNAL_ADDRESS.

To create and configure a webhook, do the following:

  1. Navigate to the Preferences tab. Click Webhooks.

  2. Click +.

    create_webhook_en

  3. Specify the webhook title.

    webhook_en

  4. Specify URL to automatically send notifications to.

  5. You can send notifications in batches. Specify the maximum number of notifications in a webhook batch. The actual number may be less.

  6. Specify the maximum number of attempts to send a notification. The interval between attempts increases exponentially with a maximum of 100 seconds.

  7. FindFace Security will be automatically sending notifications on events, episodes, and counters which match given filters. The following filters are available:

    Events:

    • allowed_bs_types: face tracking mode, possible values: overall, realtime.
    • camera_group_in: camera group id, number.
    • camera_in: camera id, number.
    • matched_lists_in: watch list id, number.
    • matched_dossier_in: matched dossier id, number.
    • matched: event matched status (true or false), boolean.
    • confidence_gte: minimum confidence, number.

    Episodes:

    • allowed_types: episode status, possible values: an episode opening (episode_open), adding a new event into an episode (episode_event), an episode closing (episode_close).
    • camera_group_in: camera group id, number.
    • camera_in: camera id, number.
    • matched_lists_in: watch list id, number.
    • matched: event matched status (true or false), boolean.
    • events_count_gte: minimum number of events in an episode, number.
    • events_count_lte: maximum number of events in an episode, number.

    Counters:

    • counter_in: counter id, number
    • camera_group_in: camera group id, number.
    • camera_in: camera id, number
    • faces_gte: minimum number of faces in a counter record, number.
    • faces_lte: maximum number of faces in a counter record, number.
    • silhouettes_gte: minimum number of silhouettes in a counter record, number.
    • silhouettes_lte: maximum number of silhouettes in a counter record, number.
    {
            "events": {
                    "allowed_bs_types": [
                            "overall",
                            "realtime"
                    ],
                    "camera_group_in": [],
                    "camera_in": [],
                    "matched_lists_in": [],
                    "matched_dossier_in": [],
                    "matched": true,
                    "confidence_gte": 0.75
            },
            "episodes": {
                    "allowed_types": [
                            "episode_open",
                            "episode_event",
                            "episode_close"
                    ],
                    "camera_group_in": [],
                    "camera_in": [],
                    "matched_lists_in": [],
                    "matched": true,
                    "events_count_gte": 0,
                    "events_count_lte": 999
            },
            "counters": {
                    "counter_in": [],
                    "camera_group_in": [],
                    "camera_in": [],
                    "faces_gte": 0,
                    "faces_lte": 0,
                    "silhouettes_gte": 0,
                    "silhouettes_lte": 0
            }
    }
    

    Important

    Use only filters which match your search needs. To turn off a filter, remove it from a webhook. Do not leave a filter empty ([]) as in this case the result of filtration will be empty as well.

    Note

    To get all notifications, pass only curly braces without any enclosed filters:

    {}
    

    Tip

    Example #1. Get notifications about all events:

    { "events": {} }
    

    Example #2. Get notifications of the opening of matched episodes:

    { "episodes": { "allowed_types": ["episode_open"], "matched": true }} - отправлять только события создания эпизода, которое сматчилось с досье.
    

    Note

    You can specify several values for filters with square braces. In this case, the webhook will be triggered once one of the values from this filter has been matched. In the example below, you will get an event from the camera group 1 or 3 if a matched dossier is 12 or 25.

    {
            "events": {
                    "camera_group_in": [1, 3],
                    "matched_dossier_in": [12, 25],
            },
    }
    
  8. Check Active.

  9. Click Save.

Webhook in Action

Try out a webhook by capturing event notifications with a simple web server in Python:

from pprint import pprint
from aiohttp import web


async def handle(request):
    pprint(await request.json())
    return web.Response(status=200)


app = web.Application()
# for aiohttp v 3.x
# app.add_routes([web.post('/', handle)])

# for aiohttp v 2.x
app.router.add_post('/', handle)

web.run_app(app, port=8888)

Important

A webhook catcher that you use must return an HTTP 200 response after receiving the webhook request from FindFace Security, like in the example above.

If no filters are configured for a webhook, this web server will be getting notifications about all events, episodes, and counter records that occur in the system. The notifications have the following format:

Event

[{'acknowledged': True,
  'acknowledged_by': None,
  'acknowledged_date': '2020-05-18T15:08:38+00:00',
  'acknowledged_reaction': '',
  'bs_type': 'overall',
  'camera': None,
  'camera_group': 1,
  'confidence': 0.0,
  'created_date': '2020-05-18T15:08:38+00:00',
  'episode': None,
  'event_type': 'event_created',
  'face': 'http://172.17.46.134/uploads/2020/05/18/event/150842_face_AgohWm.jpg',
  'features': {'age': None,
               'beard': None,
               'emotions': None,
               'gender': None,
               'glasses': None,
               'liveness': None,
               'medmask': None},
  'frame': 'http://172.17.46.134/uploads/2020/05/18/event/150842_full_frame_Y3vtGe.jpg',
  'frame_coords_bottom': 320,
  'frame_coords_left': 117,
  'frame_coords_right': 170,
  'frame_coords_top': 242,
  'id': '4267625862518432158',
  'looks_like_confidence': None,
  'matched': False,
  'matched_dossier': None,
  'matched_face': '',
  'matched_lists': [-1],
  'quality': -0.000766,
  'scores': {'liveness_score': None,
             'quality': -0.000766480341553,
             'track': {'first_timestamp': '2020-05-18T15:08:38',
                       'id': '43277e17b1c2-44',
                       'last_timestamp': '2020-05-18T15:08:39'},
             'track_duration_seconds': 2.502499999999997},
  'video_source': 1,
  'webhook_type': 'events'}]

Episode opening

[{'acknowledged': True,
  'acknowledged_by': None,
  'acknowledged_date': None,
  'acknowledged_reaction': '',
  'best_event': '4267637154774219594',
  'camera_groups': [1],
  'cameras': [],
  'closed_date': None,
  'created_date': '2020-05-18T16:18:49.111880Z',
  'event_type': 'episode_open',
  'events_count': 1,
  'features': None,
  'id': 2118,
  'last_event': {'acknowledged': True,
                 'acknowledged_by': None,
                 'acknowledged_date': '2020-05-18T16:18:46+00:00',
                 'acknowledged_reaction': '',
                 'camera': None,
                 'camera_group': 1,
                 'confidence': 0.0,
                 'created_date': '2020-05-18T16:18:46+00:00',
                 'episode': 2118,
                 'face': 'http://172.17.46.134/uploads/2020/05/18/event/161849_face_j2TQwk.jpg',
                 'features': {'age': None,
                              'beard': None,
                              'emotions': None,
                              'gender': None,
                              'glasses': None,
                              'liveness': None,
                              'medmask': None},
                 'frame': 'http://172.17.46.134/uploads/2020/05/18/event/161849_full_frame_vTfuH9.jpg',
                 'frame_coords_bottom': 327,
                 'frame_coords_left': 778,
                 'frame_coords_right': 901,
                 'frame_coords_top': 161,
                 'id': '4267637154774219594',
                 'looks_like_confidence': None,
                 'matched': False,
                 'matched_dossier': None,
                 'matched_face': '',
                 'matched_lists': [-1],
                 'quality': -0.000311,
                 'scores': {'liveness_score': None,
                            'quality': -0.000311948591843,
                            'track': {'first_timestamp': '2020-05-18T16:18:46',
                                      'id': '1ee9a3612af3-9',
                                      'last_timestamp': '2020-05-18T16:18:47'},
                            'track_duration_seconds': 2.039999999999999},
                 'video_source': 2},
  'matched_event': None,
  'matched_lists': [-1],
  'open': True,
  'webhook_type': 'episodes'}]

Episode closing

[{'acknowledged': True,
  'acknowledged_by': None,
  'acknowledged_date': None,
  'acknowledged_reaction': '',
  'best_event': {'acknowledged': True,
                 'acknowledged_by': None,
                 'acknowledged_date': '2020-05-18T15:09:57+00:00',
                 'acknowledged_reaction': '',
                 'camera': None,
                 'camera_group': 1,
                 'confidence': 0.0,
                 'created_date': '2020-05-18T15:09:57+00:00',
                 'episode': 518,
                 'face': 'http://172.17.46.134/uploads/2020/05/18/event/151012_face_5LlHQL.jpg',
                 'features': {'age': None,
                              'beard': None,
                              'emotions': None,
                              'gender': None,
                              'glasses': None,
                              'liveness': None,
                              'medmask': None},
                 'frame': 'http://172.17.46.134/uploads/2020/05/18/event/151012_full_frame_CdNn2N.jpg',
                 'frame_coords_bottom': 299,
                 'frame_coords_left': 917,
                 'frame_coords_right': 1005,
                 'frame_coords_top': 179,
                 'id': '4267626103667833809',
                 'looks_like_confidence': None,
                 'matched': False,
                 'matched_dossier': None,
                 'matched_face': '',
                 'matched_lists': [-1],
                 'quality': -0.653877,
                 'scores': {'liveness_score': None,
                            'quality': -0.653877139091491,
                            'track': {'first_timestamp': '2020-05-18T15:09:57',
                                      'id': '43277e17b1c2-231',
                                      'last_timestamp': '2020-05-18T15:09:57'},
                            'track_duration_seconds': 0.250255555555554},
                 'video_source': 1},
  'camera_groups': [1],
  'cameras': [],
  'closed_date': '2020-05-18T15:10:42.870851Z',
  'created_date': '2020-05-18T15:10:12.201230Z',
  'event_type': 'episode_close',
  'events_count': 1,
  'features': None,
  'id': 518,
  'last_event': {'acknowledged': True,
                 'acknowledged_by': None,
                 'acknowledged_date': '2020-05-18T15:09:57+00:00',
                 'acknowledged_reaction': '',
                 'camera': None,
                 'camera_group': 1,
                 'confidence': 0.0,
                 'created_date': '2020-05-18T15:09:57+00:00',
                 'episode': 518,
                 'face': 'http://172.17.46.134/uploads/2020/05/18/event/151012_face_5LlHQL.jpg',
                 'features': {'age': None,
                              'beard': None,
                              'emotions': None,
                              'gender': None,
                              'glasses': None,
                              'liveness': None,
                              'medmask': None},
                 'frame': 'http://172.17.46.134/uploads/2020/05/18/event/151012_full_frame_CdNn2N.jpg',
                 'frame_coords_bottom': 299,
                 'frame_coords_left': 917,
                 'frame_coords_right': 1005,
                 'frame_coords_top': 179,
                 'id': '4267626103667833809',
                 'looks_like_confidence': None,
                 'matched': False,
                 'matched_dossier': None,
                 'matched_face': '',
                 'matched_lists': [-1],
                 'quality': -0.653877,
                 'scores': {'liveness_score': None,
                            'quality': -0.653877139091491,
                            'track': {'first_timestamp': '2020-05-18T15:09:57',
                                      'id': '43277e17b1c2-231',
                                      'last_timestamp': '2020-05-18T15:09:57'},
                            'track_duration_seconds': 0.250255555555554},
                 'video_source': 1},
  'matched_event': None,
  'matched_lists': [-1],
  'open': False,
  'webhook_type': 'episodes'}]

Counter record

[{'camera': 3,
  'camera_group': 1,
  'counter': 2,
  'counter_name': 'smosh',
  'created_date': '2020-05-18T16:15:06.679592Z',
  'event_type': 'counter_record',
  'faces_bbox': [[[700, 210], [894, 210], [894, 464], [700, 464]],
                 [[160, 190], [304, 190], [304, 394], [160, 394]]],
  'faces_count': 2,
  'fullframe': 'http://172.17.46.134/uploads/2020/05/18/counters/161506_fullframe_7Z8n7X.jpg',
  'id': 16,
  'silhouettes_bbox': [[[15, 135], [584, 135], [584, 709], [15, 709]],
                       [[585, 80], [1194, 80], [1194, 684], [585, 684]],
                       [[0, 380], [69, 380], [69, 714], [0, 714]]],
  'silhouettes_count': 3,
  'thumbnail': 'http://172.17.46.134/uploads/2020/05/18/counters/161506_thumb_XLMFwE.jpg',
  'webhook_type': 'counters'}]

To view a webhook pulling status, execute:

sudo journalctl -u findface-security.service | grep 'WebhooksManager'

Success:

May 18 21:21:38 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] Updating "events" workers for webhooks: {2}
May 18 21:21:52 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:9KHqkQg7-VW:aa3af58f] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.002617
May 18 21:21:52 qa-2 ffsecurity[17851]: INFO     [WebhooksManager:2] <queue:  0> Webhook worker(id-2, type-"events") sent batch(len-1, type-"events"): ['4267685965791894192']
May 18 21:21:53 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:v59UsC1V-VW:75c4a9ec] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.002386
May 18 21:21:53 qa-2 ffsecurity[17851]: INFO     [WebhooksManager:2] <queue:  0> Webhook worker(id-2, type-"events") sent batch(len-1, type-"events"): ['4267685968207813297']
May 18 21:21:53 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:vKNlXiIn-VW:c0219d31] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.004499
May 18 21:21:53 qa-2 ffsecurity[17851]: INFO     [WebhooksManager:2] <queue:  0> Webhook worker(id-2, type-"events") sent batch(len-1, type-"events"): ['4267685968837561053']
May 18 21:21:55 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:zZO8v4LJ-VW:feff75dd] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.001905
May 18 21:21:55 qa-2 ffsecurity[17851]: INFO     [WebhooksManager:2] <queue:  0> Webhook worker(id-2, type-"events") sent batch(len-1, type-"events"): ['4267685973269790230']
May 18 21:21:57 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:EbpDel24-VW:083688e2] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.002017
May 18 21:21:57 qa-2 ffsecurity[17851]: INFO     [WebhooksManager:2] <queue:  0> Webhook worker(id-2, type-"events") sent batch(len-1, type-"events"): ['4267685977917324748']
May 18 21:21:57 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:L5XoQTdq-VW:6f1e397f] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.009237
May 18 21:21:57 qa-2 ffsecurity[17851]: INFO     [WebhooksManager:2] <queue:  0> Webhook worker(id-2, type-"events") sent batch(len-1, type-"events"): ['4267685979796372941']
May 18 21:21:58 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:ZZ33mwuv-VW:a4cad3a2] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.008542
May 18 21:21:58 qa-2 ffsecurity[17851]: INFO     [WebhooksManager:2] <queue:  0> Webhook worker(id-2, type-"events") sent batch(len-1, type-"events"): ['4267685980899116054']
May 18 21:21:58 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:BfAQRgp0-VW:4c19b207] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.003183
May 18 21:21:58 qa-2 ffsecurity[17851]: INFO     [WebhooksManager:2] <queue:  0> Webhook worker(id-2, type-"events") sent batch(len-1, type-"events"): ['4267685982215838395']

Failure:

May 18 21:29:09 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:jrGdiC7e-VW:2def51cf] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.003909
May 18 21:29:09 qa-2 ffsecurity[17851]: WARNING  [WebhooksManager:2] <queue:  1> Webhook worker(id-2, type-"events") Error sending webhook: 405, message='Not Allowed'. Attempt 2 out of 10. Next attempt in 0.729 seconds.
May 18 21:29:10 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:jgqLszI7-VW:6a7fea19] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.002402
May 18 21:29:10 qa-2 ffsecurity[17851]: WARNING  [WebhooksManager:2] <queue:  2> Webhook worker(id-2, type-"events") Error sending webhook: 405, message='Not Allowed'. Attempt 3 out of 10. Next attempt in 1.968 seconds.
May 18 21:29:10 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:LLGB1RRR-VW:053d7c7d] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.003794
May 18 21:29:11 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:4Vl23NQD-VW:a4640479] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.037162
May 18 21:29:11 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:QKY577ed-VW:41cd531a] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.005274
May 18 21:29:12 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:SVSrlj1n-VW:973ae0dd] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.004273
May 18 21:29:12 qa-2 ffsecurity[17851]: WARNING  [WebhooksManager:2] <queue:  6> Webhook worker(id-2, type-"events") Error sending webhook: 405, message='Not Allowed'. Attempt 4 out of 10. Next attempt in 5.314 seconds.
May 18 21:29:12 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:phoO3HFd-VW:9c6812d1] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.019604
May 18 21:29:13 qa-2 ffsecurity[17851]: INFO     [WebhooksManager] [SC:WDMmZ5MO-VW:842b3397] Webhook updater processing message(type-"events:event_created"). Consumer reception delta: 0.231164