Webhook payload templates¶
Webhook templates let you replace the default webhook payload with custom text. A template is evaluated separately for every webhook event and can use the fields of that event as variables. The rendered payload can use JSON, XML, plain text, or any other format expected by the receiving system.
Configure a template in Settings Integration Targets when creating or editing a webhook target. Leave the field empty to send the default webhook payload.
Note
A template replaces the complete request body, and the rendered text is sent exactly as produced. Regardless of the payload format, the HTTP Content-Type header is application/json. The receiving system must accept the rendered payload with this content type.
Available variables¶
The following variables are available for every event:
| Variable | Type | Description |
|---|---|---|
eventId |
string | Unique identifier of the event. |
queryId |
string | Identifier of the Rule that produced the event. |
queryDisplayName |
string | Display name of the Rule. |
queryTypeId |
string | Identifier of the Use Case. |
queryTypeDisplayName |
string | Display name of the Use Case. |
A payload also contains exactly one of these variables:
| Variable | Type | Description |
|---|---|---|
detections |
array | Detections affected by an alarm event. Detection fields use names such as video_id, frame_time, track_id, and obj_type. |
result |
object | A counting result containing its aggregation window and count or statistical values. |
For complete field descriptions and examples, see Webhook payload.
Custom header values¶
The custom header value supports the same variables and template syntax as the request body. The custom header key is static and must be a valid HTTP header name.
For example, configure the custom header key as X-Query-Id and its value as:
Each request then contains the query identifier in the X-Query-Id header. The rendered value must not contain line breaks or other control characters.
Variable substitution¶
Use {{ and }} to insert a value.
{
"eventId": "{{ eventId }}",
"query": "{{ queryDisplayName }}",
"queryType": "{{ queryTypeDisplayName }}"
}
Templates do not have to produce JSON. For example, a plain-text payload can be written as:
Event {{ eventId }} from {{ queryDisplayName }}
{% for detection in detections %}
- {{ detection.obj_type }} on video {{ detection.video_id }}
{% endfor %}
When producing JSON, surround substituted strings with quotation marks. Numeric and Boolean values should normally remain unquoted.
Use a dot to access an object field and brackets to access an array item:
{
"videoId": "{{ detections[0].video_id }}",
"objectType": "{{ detections[0].obj_type }}",
"trackId": {{ detections[0].track_id }}
}
Variable and field names are case-sensitive.
Loops¶
Use a for block to process every item in an array. The block ends with endfor.
{
"eventId": "{{ eventId }}",
"objects": [
{% for detection in detections %}
{
"type": "{{ detection.obj_type }}",
"trackId": {{ detection.track_id }},
"confidence": {{ detection.confidence }}
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}
The special loop variable provides information about the current iteration:
| Variable | Description |
|---|---|
loop.index |
Current iteration number, starting at 1. |
loop.index0 |
Current iteration number, starting at 0. |
loop.first |
true for the first iteration. |
loop.last |
true for the last iteration. |
When producing JSON, the loop.last check in the example prevents a trailing comma after the final object.
Conditionals¶
Use if, elseif, and else blocks to select output based on the event. The block ends with endif.
{
"eventId": "{{ eventId }}",
{% if detections %}
"kind": "detection",
"itemCount": {{ detections | length }}
{% elseif result %}
"kind": "counting-result",
"windowStart": "{{ result.windowStart }}",
"windowEnd": "{{ result.windowEnd }}"
{% else %}
"kind": "unknown"
{% endif %}
}
Use is not null before accessing an optional field:
{% if result.count is not null %}
"value": {{ result.count }}
{% elseif result.minimum is not null %}
"average": {{ result.average }},
"minimum": {{ result.minimum }},
"maximum": {{ result.maximum }}
{% else %}
"average": {{ result.average }}
{% endif %}
Conditions support the comparison operators ==, !=, >, <, >=, and <=, and the logical operators and, or, and not.
{% if detection.confidence >= 0.8 and detection.obj_type == "person" %}
"priority": "high"
{% else %}
"priority": "normal"
{% endif %}
Filters¶
Filters transform a value and are applied with the | character. Common filters include:
| Filter | Example | Result |
|---|---|---|
length |
{{ detections | length }} |
Number of detections. |
upper |
{{ queryDisplayName | upper }} |
Uppercase text. |
lower |
{{ queryDisplayName | lower }} |
Lowercase text. |
default |
{{ value | default("unknown") }} |
Fallback when a value is empty or missing. |
join |
{{ values | join(", ") }} |
Array values joined into text. |
Filters can be chained from left to right:
Troubleshooting¶
- Ensure the rendered output follows the format expected by the receiving system. For JSON, pay particular attention to quotation marks and commas around loops and conditionals.
- Use the exact variable names shown on this page. Names are case-sensitive.
- Guard optional fields with
is not nullbefore using them. - Remember that
detectionsandresultare mutually exclusive. - The integration-target connection test sends a fixed request and uses sample event values for a templated custom header. Validate the rendered body and actual header value by running a query that uses the target.
- If template evaluation fails, no webhook request is sent for that event.