Webhooks

You can set up FindFace Multi 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 a counter record occurs, FindFace Multi will send an HTTP request to the URL configured for the webhook.

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

In this section:

Configure Webhook

Important

The user must have corresponding permissions to create, view, change or delete a webhook. To manage permissions, navigate to SettingsRole.

Note

To use the webhooks, make sure that at least one of the following parameters is specified in /opt/findface-multi/configs/findface-multi-legacy/findface-multi-legacy.py: SERVICE_EXTERNAL_ADDRESS or EXTERNAL_ADDRESS.

To create and configure a webhook, do the following:

  1. Navigate to the Settings tab. Click Webhooks.

  2. Click + New webhook.

    create_webhook_en

  3. Specify the webhook header.

    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.

    Important

    To receive all messages since the connection loss, should it happen, set 0. Set 1 to omit old messages.

  7. FindFace Multi will be automatically sending notifications on events, episodes, and counter records that match given filters.

    There are two ways to configure filters:

    • visually

    • by code

    To configure filters visually, click Configure.

    Generic filters for recognition events (face, body, vehicle):

    • Matches: filter events only with/without matches, or all events.

    • Watch lists: filter events only for a selected watch list, or all events.

    • Camera groups: filter only events from a selected group of cameras.

    • Cameras: filter only events from a selected camera.

    • Record name: filter events with a given record name.

    • Event’s best shot: filter all events of a track, only events with real-time snapshots, only one event with the best snapshot at the end of a track.

    • Line: filter events with a given line crossing.

    • Line crossing direction: filter events with line crossing of a given direction, or all events.

    • Has reverse crossing: filter events with/without reverse crossing.

    Filters specific for face recognition events:

    • Age: filter events with people of a given age.

    • Beard: filter events by the fact of having a beard.

    • Emotions: filter events with given emotions.

    • Gender: filter events with people of a given gender.

    • Glasses: filter events by the fact of wearing glasses.

    • Liveness: filter events by face liveness.

    • Face mask: filter events by the fact of wearing a face mask.

    • Head turn: filter events by degree of head turn.

    • Head tilt: filter events by degree of head tilt.

    Filters specific for body recognition events:

    • Gender by body: filter only events with people of a given gender or all events.

    • Age by body: filter only events with people of a given age.

    • Headwear: filter only events with a person wearing headgear of a given type: hat/cap, hood/headscarf, none.

    • Vest: filter only events with a person wearing a vest of a given color.

    • Helmet: filter only events with a person wearing a helmet of a given color.

    • Upper clothes color: filter only events with a person wearing a top of a given color.

    • Lower clothes color: filter only events with a person wearing a bottom of a given color.

    • Upper clothes type: filter only events with a person wearing upper body wear of a given specific type: jacket, coat, sleeveless vest, sweatshirt, T-shirt, shirt, dress.

    • Lower body clothes: filter only events with a person wearing lower body wear of a given type: pants, skirt, shorts, obscured.

    • Upper body clothes: filter only events with a person wearing upper body wear of a given generalized category: long sleeves, short sleeves, no sleeve.

    • Bag on the back: filter only events with a person wearing/not wearing a bag on the back.

    • Bag in hand: filter only events with a person wearing/not wearing a bag in hand.

    Filters specific for vehicle recognition events:

    • Make: filter vehicle events by vehicle make.

    • Model: filter vehicle events by vehicle model.

    • Vehicle body type: filter only events with vehicles of a given body type: suv, sedan, crossover, convertible, coupe, shooting brake, pickup, van, minivan, limousine.

    • Vehicle body color: filter only events with vehicles of a given color.

    • Country: filter only events with vehicles registered in a given country.

    • License plate number: filter an event with a given plate number.

    • Special vehicle: filter only events with vehicles belonging to a given type: police, fire service and EMERCOM vehicles, gas rescue and emergency services, military, municipal vehicles, and others.

    • Vehicle category: filter only events with vehicles belonging to a given category: motorcycle, scooter, car, car with a trailer, truck, truck with a trailer, bus, articulated bus, and others.

    • Vehicle weight and body size: filter only events with vehicles of a given weight and body size.

    • Vehicle orientation: filter only events with vehicles of a given orientation.

    Note

    License plate color, Region are disabled by default. To enable these parameters, uncomment "license_plate_number_color", "license_plate_region" in the section FFSECURITY_UI_CONFIG in the configuration file /opt/findface-multi/configs/findface-multi-legacy/findface-multi-legacy.py.

    sudo vi /opt/findface-multi/configs/findface-multi-legacy/findface-multi-legacy.py
    
    
    FFSECURITY_UI_CONFIG = {
            ...
            "cars": {
                "features": {
                  ...
                  "license_plate_number_color": [
                            "unknown",
                            "white",
                            "yellow",
                            "blue",
                            "green",
                            "grey",
                  ],
                   ...
                  "license_plate_region": ["unknown", "DXB", "SHJ", "ADH", "AJM", "UAK", "RAK", "FUJ"],
                  ...
                },
              ....
             },
      }
    

    Restart the findface-multi-findface-multi-legacy-1 container after you have applied the changes.

    sudo docker container restart findface-multi-findface-multi-legacy-1
    

    Episodes with individuals:

    • Episode types: filter episodes by status (open/have events/close).

    • Matches: faces: filter episodes only with/without face matches, or all events.

    • Matches: bodies: filter episodes only with/without body matches, or all events.

    • Watch lists: filter episodes only for a selected watch list, or all episodes.

    • Camera groups: filter only episodes from a selected group of cameras.

    • Cameras: filter only episodes from a selected camera.

    • Record name: filter episodes with a given record name.

    • Count events: filter only episodes with a given number of events.

    Episodes with vehicles:

    • Episode types: filter episodes by status (open/have events/close).

    • Matches: filter episodes only with/without matches, or all events.

    • Watch lists: filter episodes only for a selected watch list, or all episodes.

    • Camera groups: filter only episodes from a selected group of cameras.

    • Cameras: filter only episodes from a selected camera.

    • Record name: filter episodes with a given record name.

    • Episode ID: filter an episode with a given ID.

    • Count events: filter only episodes with a given number of events.

    Counter records:

    • Camera groups: filter only counter records from a selected group of cameras.

    • Cameras: filter only counter records from a selected camera.

    • Count faces ≥: filter counter records by count of faces.

    • Count bodies ≥: filter counter records by count of bodies.

    • Count vehicles ≥: filter counter records by count of vehicles.

    • Counter ID: filter counter records with a given ID.

    • Minimum distance: send a notification if the detected minimum distance is in specified range.

    • Maximum distance: send a notification if the detected maximum distance is in specified range.

    • Average distance: send a notification if the detected average distance is in specified range.

    For a number of filters there’s also an option to specify a confidence threshold.

    Note

    Several parameters are available in the code mode only and are not represented as visual filters. To properly configure these parameters by code, read their descriptions.

    To configure filters by code, switch to the Code view. Use the following descriptions:

    Generic filters for recognition events (face, body, vehicle):

    Sections: face_events, body_events, car_events.

    • "matched_lists": watch list ID, [integer].

    • "camera_groups": camera group ID, [integer].

    • "cameras": camera ID, [integer].

    • "matched_card": matched record ID, [integer].

    • "matched": the matched status. Set true or false if only matched or unmatched events must trigger sending a notification, boolean.

    • "confidence_gte": minimum confidence, number. Min 0, Max 1.

    • "bs_type": object tracking mode, [string]. Possible values: overall, realtime.

    • "line": line crossing ID, [integer].

    • "line_crossing_direction": line crossing direction, [enum]. Possible values: AB, BA.

    • "backward_line_crossing": Set true or false if event has or hasn’t reverse crossing, boolean.

    Filters specific for face recognition events:

    Section: face_events.

    • "headpose_yaw_angle_gte": minimum head turn, integer (degrees). If a head is turned fully to the left, the yaw angle is -180. If it is turned fully to the right, it’s 180. The neutral head position is 0.

    • "headpose_yaw_angle_lte": maximum head turn, integer (degrees). If a head is turned fully to the left, the yaw angle is -180. If it is turned fully to the right, it’s 180. The neutral head position is 0.

    • "headpose_pitch_angle_gte": minimum head tilt, integer (degrees). If a head is tilted forward with the chin touching the chest, it’s -180. If a head is tilted backward facing the sky, it’s 180. The neutral head position is 0.

    • "headpose_pitch_angle_lte": maximum head tilt, integer (degrees). If a head is tilted forward with the chin touching the chest, it’s -180. If a head is tilted backward facing the sky, it’s 180. The neutral head position is 0.

    • "gender": gender, [string]. Possible values: "male", "female", [string].

    • "age_lte": maximum age, integer.

    • "age_gte": minimum age, integer.

    • "glasses": glasses, [string]. Possible values: "none", "eye" (eyeglasses), "sun" (sunglasses).

    • "emotions": emotions, [string]. Possible values: "any", "angry", "fear", "sad", "neutral", "disgust", "happy", "surprise".

    • "beard": beard, [string]. Possible values: "none", "beard".

    • "medmask": face mask, [string]. Possible values: "correct", "incorrect", "none".

    • "liveness": liveness, [string]. Possible values: "real", "fake".

    • "temperature_gte": minimum temperature, number.

    • "liveness_gte": minimum algorithm confidence that a face belongs to a live person, number. Min 0, Max 1.

    Filters specific for body recognition events:

    Section: body_events.

    • "headwear": type of headgear (hat/cap, hood/headscarf, none), [string]. Possible values: "hat", "hood", "none".

    • "upper_clothes": generalized category of upper body wear (long sleeves, short sleeves, no sleeve), [string]. Possible values: "long_sleeves", "short_sleeves", "without_sleeves".

    • "detailed_upper_clothes": specific type of upper body wear (jacket, coat, sleeveless vest, sweatshirt, T-shirt, shirt, dress), [string]. Possible values: "jacket", "coat", "sleeveless", "sweatshirt", "t-shirt", "shirt", "dress".

    • "top_color": top clothing color, [string]. Possible values: white, "black", "grey", "brown", "red", "orange", "yellow", "green", "lightblue", "blue", "purple", "pink", "beige", "violet".

    • "lower_clothes": type of lower body wear (pants, skirt, shorts, nondescript), [string]. Possible values: "pants", "obscured", "skirt", "shorts".

    • "bottom_color": bottom clothing color, [string]. Possible values: white, "black", "grey", "brown", "red", "orange", "yellow", "green", "lightblue", "blue", "purple", "pink", "beige", "violet".

    • "bag_hand": whether a person has a bag in hand(s), [string]. Possible values: "none", "hand".

    • "bag_ground": whether a person has a bag on the ground. Possible values: "ground", "none".

    • "bag_back": whether a person has a bag on the back, [string]. Possible values: "none", "back".

    • "vest_type_score_gte": minimum recognition confidence of a vest presence, number. Min 0, Max 1.

    • "vest_type_score_lte": maximum recognition confidence of a vest presence, number. Min 0, Max 1.

    • "vest_type": presence of personal protective equipment in the form of a vest, [string]. Possible values: "green/yellow", "orange", "not_visible", "none".

    • "helmet_type_score_lte": maximum recognition confidence of a helmet presence, number. Min 0, Max 1.

    • "helmet_type_score_gte": minimum recognition confidence of a helmet presence, number. Min 0, Max 1.

    • "helmet_type": presence of personal protective equipment in the form of a helmet, [string]. Possible values: "red/orange", "white", "other", "not_visible", "none".

    • "age_group_score_lte": maximum age group recognition confidence, number. Min 0, Max 1.

    • "age_group_score_gte": minimum age group recognition confidence, number. Min 0, Max 1.

    • "age_group": age by group, [string]. Possible values: "0-16", "17-35", "36-50", "50+".

    • "gender_score_lte": maximum gender recognition confidence, number.

    • "gender_score_gte": minimum gender recognition confidence, number.

    • "body_gender": gender, [string]. Possible values: "male", "female".

    Filters specific for vehicle recognition events:

    Section: car_events.

    • "category_confidence_gte": minimum recognition confidence of the vehicle category, number. Min 0, Max 1.

    • "category_confidence_lte": maximum recognition confidence of the vehicle category, number. Min 0, Max 1.

    • "category_type": vehicle category, [string]. Possible values: "unknown", "A", "B", "BE", "C", "CE", "D", "DE", "other".

    • "color" vehicle color, [string]. Possible values: "beige", "black", "blue", "brown", "cyan", "gold", "green", "grey", "orange", "pink", "purple", "red", "silver", "violet", "white", "yellow".

    • "body": vehicle body style, [string]. Possible values: "suv", "sedan", "crossover", "convertible", "coupe", "wagon", "cab", "minibus", "minivan", "limousine".

    • "make": vehicle make, [string]. Check out the corresponding event filter to see what makes are supported in the current version.

    • "model": vehicle model, [string]. Check out the corresponding event filter to see what models are supported in the current version.

    • "license_plate_number": license plate number, [string]. Wildcards are not supported.

    • "license_plate_number_color": license plate color, [string]. Possible values: "unknown", "white", "yellow", "blue", "green", "grey".

    • "license_plate_number_color_confidence_lte": maximum recognition confidence of the license plate color, number.

    • "license_plate_number_color_confidence_gte": minimum recognition confidence of the license plate color, number.

    • "license_plate_country": license plate country, [string]. Check out the corresponding event filter to see what countries are supported in the current version.

    • "license_plate_region": license plate region, [string]. Check out the corresponding event filter to see what regions are supported in the current version.

    • "special_vehicle_type": special vehicle type, [string]. Possible values: "taxi", "route_transport", "car_sharing", "ambulance", "police", "rescue_service", "gas_service", "military", "road_service", "other_special", "not_special".

    • "weight_type": vehicle weight type, [string]. Possible values: "B_light", "B_heavy", "C_light", "C_heavy", "D_light", "D_long", "other".

    • "weight_type_confidence_lte": maximum recognition confidence of the vehicle weight type, number. Min 0, Max 1.

    • "weight_type_confidence_gte": minimum recognition confidence of the vehicle weight type, number. Min 0, Max 1.

    • "orientation": vehicle orientation, [string]. Possible values: "front", "back", "side".

    • "orientation_confidence_lte": maximum recognition confidence of the vehicle orientation, number. Min 0, Max 1.

    • "orientation_confidence_gte": minimum recognition confidence of the vehicle orientation, number. Min 0, Max 1.

    Episodes with individuals:

    Section: human_episodes.

    • "allowed_types": episode status, [string]. Possible values: an episode opening (episode_open), adding a new event into an episode (episode_event), an episode closing (episode_close).

    • "matched_lists": watch list ID, [integer].

    • "cameras": camera ID, [integer].

    • "camera_groups": camera group ID, [integer].

    • "events_count_gte": minimum number of events in an episode, integer.

    • "events_count_lte": maximum number of events in an episode, integer.

    • "face_matched": the matched status of face events in an episode, boolean. Set true if only matched faces or false if only unmatched faces must trigger sending a notification.

    • "body_matched": the matched status of body events in an episode, boolean. Set true if only matched bodies or false if only unmatched bodies must trigger sending a notification.

    Episodes with vehicles:

    Section: car_episodes.

    • "allowed_types": episode status, [string]. Possible values: an episode opening (episode_open), adding a new event into an episode (episode_event), an episode closing (episode_close).

    • "matched_lists": watch list ID, [integer].

    • "cameras": camera ID, number.

    • "camera_groups": camera group ID, [integer].

    • "events_count_gte": minimum number of events in an episode, integer.

    • "events_count_lte": maximum number of events in an episode, integer.

    • "car_matched": the matched status of car events in an episode, boolean. Set true if only matched cars or false if only unmatched cars must trigger sending a notification.

    Counter records:

    Section: counters.

    • "counter": counter ID, [integer].

    • "cameras": camera ID, [integer].

    • "camera_groups": camera group ID, [integer].

    • "faces_count_gte": minimum number of faces in a counter record, integer.

    • "faces_count_lte": maximum number of faces in a counter record, integer.

    • "silhouettes_count_gte": minimum number of bodies in a counter record, integer.

    • "silhouettes_count_lte": maximum number of bodies in a counter record, integer.

    • "cars_count_gte": minimum number of vehicles in a counter record, integer.

    • "cars_count_lte": maximum number of vehicles in a counter record, integer.

    • "proximity_min_lte": send a notification if the minimum detected distance in meters is less than this value, number.

    • "proximity_min_gte": send a notification if the minimum detected distance in meters is greater than this value, number.

    • "proximity_avg_lte": send a notification if the average detected distance in meters is less than this value, number.

    • "proximity_avg_gte": send a notification if the average detected distance in meters is greater than this value, number.

    • "proximity_max_lte": send a notification if the maximum detected distance in meters is less than this value, number.

    • "proximity_max_gte": send a notification if the maximum detected distance in meters is greater than this value, number.

    Example

    Note

    This example is given for reference only, substitute your values in corresponding fields.

    {
      "name": "AA",
      "active": false,
      "url": "http://example.com",
      "batch_size": 1,
      "filters": {
        "face_events": {
          "matched_lists": [
            -1
          ],
          "camera_groups": [
            -1
          ],
          "cameras": [
            1
          ],
          "matched_card": [
            1
          ],
          "matched": false,
          "confidence_gte": 0,
          "bs_type": [
            "A"
          ],
          "line": [
            1
          ],
          "line_crossing_direction": [
            "AB"
          ],
          "backward_line_crossing": false,
          "headpose_yaw_angle_gte": -180,
          "headpose_yaw_angle_lte": -180,
          "headpose_pitch_angle_gte": -180,
          "headpose_pitch_angle_lte": -180,
          "gender": [
            "A"
          ],
          "age_lte": 0,
          "age_gte": 0,
          "glasses": [
            "A"
          ],
          "emotions": [
            "A"
          ],
          "beard": [
            "A"
          ],
          "medmask": [
            "A"
          ],
          "liveness": [
            "A"
          ],
          "temperature_gte": 0,
          "liveness_gte": 0
        },
        "body_events": {
          "matched_lists": [
            -1
          ],
          "camera_groups": [
            -1
          ],
          "cameras": [
            1
          ],
          "matched_card": [
            1
          ],
          "matched": false,
          "confidence_gte": 0,
          "bs_type": [
            "A"
          ],
          "line": [
            1
          ],
          "line_crossing_direction": [
            "AB"
          ],
          "backward_line_crossing": false,
          "headwear": [
            "A"
          ],
          "upper_clothes": [
            "A"
          ],
          "detailed_upper_clothes": [
            "A"
          ],
          "top_color": [
            "A"
          ],
          "lower_clothes": [
            "A"
          ],
          "bottom_color": [
            "A"
          ],
          "bag_hand": [
            "A"
          ],
          "bag_ground": [
            "A"
          ],
          "bag_back": [
            "A"
          ],
          "vest_type_score_gte": 0,
          "vest_type_score_lte": 0,
          "vest_type": [
            "A"
          ],
          "helmet_type_score_lte": 0,
          "helmet_type_score_gte": 0,
          "helmet_type": [
            "A"
          ],
          "age_group_score_lte": 0,
          "age_group_score_gte": 0,
          "age_group": [
            "A"
          ],
          "gender_score_lte": 0,
          "gender_score_gte": 0,
          "body_gender": [
            "A"
          ]
        },
        "car_events": {
          "matched_lists": [
            -1
          ],
          "camera_groups": [
            -1
          ],
          "cameras": [
            1
          ],
          "matched_card": [
            1
          ],
          "matched": false,
          "confidence_gte": 0,
          "bs_type": [
            "A"
          ],
          "line": [
            1
          ],
          "line_crossing_direction": [
            "AB"
          ],
          "backward_line_crossing": false,
          "category_confidence_gte": 0,
          "category_confidence_lte": 0,
          "category_type": [
            "A"
          ],
          "color": [
            "A"
          ],
          "body": [
            "A"
          ],
          "make": [
            "A"
          ],
          "model": [
            "A"
          ],
          "license_plate_number": [
            "A"
          ],
          "license_plate_number_color": [
            "A"
          ],
          "license_plate_number_color_confidence_lte": 0,
          "license_plate_number_color_confidence_gte": 0,
          "license_plate_country": [
            "A"
          ],
          "license_plate_region": [
            "A"
          ],
          "special_vehicle_type": [
            "A"
          ],
          "weight_type": [
            "A"
          ],
          "weight_type_confidence_lte": 0,
          "weight_type_confidence_gte": 0,
          "orientation": [
            "A"
          ],
          "orientation_confidence_lte": 0,
          "orientation_confidence_gte": 0
        },
        "human_episodes": {
          "allowed_types": [
            "A"
          ],
          "matched_lists": [
            -1
          ],
          "cameras": [
            1
          ],
          "camera_groups": [
            -1
          ],
          "events_count_gte": 0,
          "events_count_lte": 1,
          "face_matched": false,
          "body_matched": false
        },
        "car_episodes": {
          "allowed_types": [
            "A"
          ],
          "matched_lists": [
            -1
          ],
          "cameras": [
            1
          ],
          "camera_groups": [
            -1
          ],
          "events_count_gte": 0,
          "events_count_lte": 1,
          "car_matched": false
        },
        "counters": {
          "counter": [
            0
          ],
          "cameras": [
            0
          ],
          "camera_groups": [
            -1
          ],
          "faces_count_gte": 1,
          "faces_count_lte": 0,
          "silhouettes_count_gte": 1,
          "silhouettes_count_lte": 0,
          "cars_count_gte": 1,
          "cars_count_lte": 0,
          "proximity_min_lte": 0,
          "proximity_min_gte": 0,
          "proximity_avg_lte": 0,
          "proximity_avg_gte": 0,
          "proximity_max_lte": 0,
          "proximity_max_gte": 0
        },
        "areas": {
          "area_in": [
            0
          ],
          "camera_in": [
            0
          ],
          "camera_group_in": [
            -1
          ]
        }
      },
      "send_attempts": 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 vehicle events:

    { "car_events": {} }
    

    Example #2. Get notifications of the opening of matched episodes that feature human faces and bodies:

    { "human_episodes": { "allowed_types": ["episode_open"], "face_matched": true, "body_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 a body event from the camera group 1 or 3 if a matched record is 12 or 25.

    {
            "body_events": {
                    "camera_groups": [1, 3],
                    "matched_card": [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 Multi, 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.

To view a webhook pulling status, execute:

sudo journalctl CONTAINER_NAME=findface-multi-findface-multi-legacy-1 -f | grep 'Webhook'

Verbose Webhooks

By default, webhook notifications contain only IDs of such entities as cards, watch lists, cameras, and camera groups. It is possible to get the full content of the mentioned entities by switching webhooks to the verbose mode.

To do so, open the /opt/findface-multi/configs/findface-multi-legacy/findface-multi-legacy.py configuration file and set 'VERBOSE_WEBHOOKS': True:

sudo vi /opt/findface-multi/configs/findface-multi-legacy/findface-multi-legacy.py

...
FFSECURITY = {
    ...
    # send serialized cards, card-lists, camera and camera groups in webhooks
    'VERBOSE_WEBHOOKS': True,
    ...
}
...

Be sure to restart the findface-multi-findface-multi-legacy-1 container after making changes.

sudo docker container restart findface-multi-findface-multi-legacy-1