Webhooks
MOR and M4 can send **outbound HTTP POST** requests to URLs you configure when certain events occur. There are two delivery formats:
- Query-string webhooks — HTTP POST with an empty body; event data is appended to your configured URL as query string parameters (Call End, Warning Balance).
- JSON webhooks — HTTP POST with a JSON body and
Content-Type: application/json(Alerts).
Overview
| Webhook type | Product | When it fires | Request format |
|---|---|---|---|
| Call End | MOR | A completed call whose source device has a webhook URL | POST, empty body, query string |
| Warning Balance | MOR | User balance drops below the configured admin warning threshold | POST, empty body, URL built from template |
| Alert / Clear | MOR, M4 | An alert is raised or cleared, and the matching notify option is enabled | POST, JSON body |
Call End Webhook
Configuration
- Per device: Device edit → Advanced → Webhook URL for Call End (field
webhook_url_for_call_end). - Default for new devices: SETTINGS → Default Device → same field.
- Legacy API write: MOR API MOR API device update parameter
webhook_url_for_call_end(not included in hash). An empty value clears the URL. - Legacy API read: MOR API device details get tag
webhook_url_for_call_end. - URL must start with
http://orhttps://.
When it fires
- MOR checks for newly completed calls approximately every 10 seconds.
- Only calls where the source device has a non-empty webhook URL are considered.
- Only calls with
calltimewithin the last ~2 hours are eligible. - On first use, delivery starts from the current newest call — historical calls are not sent.
- After a restart, MOR resumes from the last successfully delivered call instead of skipping or re-sending older calls.
Request format
- Method: HTTP POST
- Body: empty
- Parameters: query string on the configured URL
If your base URL already contains query parameters (for example, https://example.com/hook?api_key=secret), MOR merges call parameters with & (single ?). Parameter values are URL-encoded.
| Parameter | Description |
|---|---|
user_id |
User id associated with the call |
device_id |
Source device id |
calltime |
Call date/time |
src |
Caller source |
dst |
Destination |
hangupcause |
Hangup cause code |
billsec |
Billed seconds |
call_price |
Call price in the user's currency |
balance_at_the_end_of_call |
User balance in the user's currency at send time |
currency |
User currency code (for example USD, EUR)
|
Examples
Bare base URL:
Base URL with existing query parameter:
- Configured:
http://192.168.1.142:8080/test?api_key=mytoken - Sent:
http://192.168.1.142:8080/test?api_key=mytoken&user_id=2&device_id=80&...
Limitations
- Only the source device webhook URL is used (not the destination device).
- Delivery is not real-time at hangup — expect up to ~10 seconds polling delay.
- Call-end and warning-balance webhooks are delivered through the same outbound notification pipeline.
- Wiki paste — Webhooks: URL encoding and calltime
- Status:** Section patch — insert on existing page **Webhooks** on wiki.kolmisoft.com.
- Page title:** `Webhooks`
- Verified links:** none required in this fragment (host page is Webhooks).
- Placement:** Under `== Call End Webhook ==`, after the parameter table in `=== Request format ===` and **before** `=== Examples ===`.
---
URL encoding (query parameters)
MOR sends call-end data as a query string on your configured URL. Each parameter name and value is URL-encoded so that reserved characters do not break the request.
Why you may see %3A and %2B in calltime
The calltime value is an ISO 8601 date/time, for example 2026-06-11T13:36:03.000+00:00. In a query string, characters such as colons and plus signs must be encoded:
| Encoded sequence | Character | Typical role in calltime
|
|---|---|---|
%3A |
: |
Separates hours, minutes, and seconds (for example 13%3A36%3A03)
|
%2B |
+ |
Starts a numeric UTC offset (for example %2B00%3A00 for UTC)
|
A full encoded calltime may look like:
calltime=2026-06-11T13%3A36%3A03.000%2B00%3A00
After URL decoding, that is the same instant as 2026-06-11T13:36:03.000+00:00.
Decoding on your server
Use your platform’s standard URL-decoding for query parameters (for example, urllib.parse.parse_qs in Python, parse_str / urldecode in PHP, or framework request helpers). Do not treat the raw query substring as a plain timestamp without decoding.
Why the plus sign is encoded
In application/x-www-form-urlencoded query strings, an unencoded + is often interpreted as a space. Encoding + as %2B keeps the timezone offset intact.
UTC with a Z suffix (equivalent form)
MOR sends calltime in ISO 8601 with a numeric timezone offset (for example ...+00:00), which produces %2B in the encoded URL. The same UTC instant can also be written with a trailing Z (for example, 2025-11-04T22:52:23Z). That form is shorter and would avoid %2B, but colons still encode as %3A:
calltime=2025-11-04T22%3A52%3A23Z
When decoding, treat Z and +00:00 as the same UTC offset.
Other parameters
The same encoding rules apply to all call-end query parameters (for example, src, dst, currency). Only values that contain reserved characters will show percent-escapes in the logged URL.
Warning Balance Webhook
MOR-only. See Warning balance for the full feature (email, audio announcement, scheduling).
Configuration
On User Details (user edit), in the Warning Balance section:
- Enable Active for Warning Balance.
- Set Send warning when balance drops lower than thresholds (including the admin threshold that triggers the webhook).
- Check Admin Webhook and set the webhook URL on the same row (
http://orhttps://required). - The webhook is not tied to email — it can run with webhook only (Active enabled, threshold and URL set) even if email notifications are disabled.
- Admin Webhook fields are available from an admin or accountant account editing the user.
The URL is a template: MOR substitutes Email variables into the URL the same way as email bodies (for example, https://example.com/hook?user=<%= username %>&balance=<%= balance %>).
When it fires
- Fires when the same conditions that send the admin Warning Balance email are met (user balance below the admin warning threshold).
- Warning Balance checks run on an hourly schedule — delivery may lag briefly after the balance crosses the threshold.
- If Every day at is selected for Warning Balance email timing, the webhook follows that schedule as well (not on every balance change).
Request format
- Method: HTTP POST
- Body: empty
- URL: rendered from the configured Admin Webhook URL template after variable substitution
Common variables include username, balance, nice_balance, warning_email_balance, nice_warning_email_balance, currency, and user_id. See Email variables for the full list.
Example
Configured URL:
https://example.com/warning?user=<%= username %>&balance=<%= balance %>¤cy=<%= currency %>
Sent request (POST to rendered URL, empty body):
https://example.com/warning?user=john&balance=4.50¤cy=USD
Alert Webhooks
When an alert is raised or cleared, MOR/M4 can POST a JSON notification to every contact in the alert's notification group that has a non-empty Webhook URL.
MOR configuration
- Contacts — set Webhook URL per contact: ADDONS → Monitorings → Contacts (Alert Contacts).
- Groups — assign contacts to a group: ADDONS → Monitorings → Groups (Alert Groups).
- Alerts — on alert edit (Alerts):
- Group to Notify — select the contact group.
- Notify On Alert via Webhook — send webhook when the alert is raised.
- Notify On Clear via Webhook — send webhook when the alert is cleared.
See Monitorings Addon and Alerts for alert parameters, clear rules, and examples.
M4 configuration
Same webhook payload as MOR. Configuration paths on M4:
- Contacts — set Webhook URL on each alert contact (see M4 Alerts).
- Alerts — under SECURITY → Alerts (M4 Alerts):
- Group to Notify — select the contact group.
- Notify On Alert via Webhook / Notify On Clear via Webhook — same options as MOR.
When it fires
- ALERT — when the alert condition is met and Notify On Alert via Webhook is enabled on that alert.
- CLEAR — when the alert clears and Notify On Clear via Webhook is enabled on that alert.
- One HTTP request is sent to each contact in the selected group whose Webhook URL is non-empty.
- Contact webhook URLs must start with
http://orhttps://.
Request format
- Method: HTTP POST
- Content-Type:
application/json - Body: JSON object
| Field | Description |
|---|---|
type |
Trigger type: ALERT or CLEAR
|
group_id |
Alert group id |
alert_id |
Alert id |
alert_name |
Alert name |
object_id |
Id of the monitored object |
object_name |
Human-readable object name |
cause |
Alert parameter / cause (for example CALLS TOTAL)
|
value |
Current measured value (number) |
count |
Data count (integer) |
timestamp |
Date/time when the alert or clear triggered (YYYY-MM-DD HH:MM:SS)
|
Example payload
{
"type": "ALERT",
"group_id": 12,
"alert_id": 42,
"alert_name": "Test",
"object_id": 123,
"object_name": "Example OP",
"cause": "CALLS TOTAL",
"value": 150.0,
"count": 150,
"timestamp": "2026-02-26 12:34:56"
}
See also
- Alerts — MOR alert configuration and examples
- M4 Alerts — M4 alert configuration
- Warning balance — Warning Balance email, audio, and scheduling
- Alert Contacts — contact webhook URLs for MOR alerts
- Alert Groups — group contacts for alert notifications
- Email variables — template variables for Warning Balance webhook URLs
- MOR API device update — set
webhook_url_for_call_endvia API - MOR API device details get — read
webhook_url_for_call_end - MOR API — legacy API overview