Internal API EN
Custom Events v2 is a local ERP internal event system. It runs customer PHP code inside the current ERP PHP process without HTTP requests, webhooks, or external queues.
The old legacy/Config/custom_api.txt mechanism with the api_function(...) function remains a legacy contract. In v2, old names are used only for the compatibility map. New customer code must use CustomEvent::... constants.
Files
There is one working customer file:
evolution/CustomEvents/v2/handlers.php
Example:
evolution/CustomEvents/v2/handlers.example.php
List of all constants:
evolution/CustomEvents/Runtime/v2/CustomEvent.php
Map of old names to new events:
evolution/CustomEvents/Runtime/v2/CustomEventLegacyEventMap.php
Cache:
var/cache/CustomEvents/handlers.v2.cache.php
Log:
var/log/custom-events-v2.log
How to write handlers
One registration function is used: internal_event(...).
Several handlers can be registered one after another in the same file:
internal_event(
CustomEvent::TASK_CREATED,
static function ($event): bool {
$taskId = $event->get('task_id');
return true;
},
);
internal_event(
CustomEvent::CUSTOMER_STATUS_CHANGE_BEFORE,
static function ($event): bool|string {
if ((int)$event->get('new_status_id') === 0) {
return 'Changing the customer to this status is forbidden';
}
return true;
},
);
internal_event(
CustomEvent::CUSTOMER_CARD_PRIMARY_CONTENT_RENDER,
static function ($event): string {
$customerId = (int)$event->get('customer_id');
return '<div>Additional customer information #' . $customerId . '</div>';
},
);
The handler always receives one parameter: $event.
Data is read without type wrappers:
$taskId = $event->get('task_id');
$customerId = $event->get('customer_id');
$data = $event->all();
If a specific type is required, cast the value in your code:
$taskId = (int)$event->get('task_id');
$comment = (string)$event->get('comment');
Handler result
The handler returns a simple value:
| Return | Meaning |
|---|---|
true
|
The handler completed successfully |
false
|
For a *.before event, block the standard operation
|
null
|
Do not change anything |
| string | For *.before, block the operation with a reason text; for *.render, output a string or HTML
|
*.before events can cancel the standard operation. Other events must not cancel an action that has already been completed.
Example: blocking an operation
internal_event(
CustomEvent::CUSTOMER_STATUS_CHANGE_BEFORE,
static function ($event): bool|string {
if ((int)$event->get('new_status_id') === 0) {
return 'Changing the customer to this status is forbidden';
}
return true;
},
);
Example: outputting HTML
internal_event(
CustomEvent::CUSTOMER_CARD_PRIMARY_CONTENT_RENDER,
static function ($event): string {
$customerId = (int)$event->get('customer_id');
return '<div>Additional customer information #' . $customerId . '</div>';
},
);
Validation, cache, and log
When evolution/CustomEvents/v2/handlers.php changes, ERP checks the syntax with php -l. If the syntax is valid, the file is copied to var/cache/CustomEvents/handlers.v2.cache.php.
The runtime log is written as JSON Lines to var/log/custom-events-v2.log. One line is one handler call, error, or fact that no handlers exist.
Example line:
{"ts":"2026-05-10T12:01:03+03:00","event":"task.created","has_handlers":true,"handlers":1,"handler_index":0,"duration_ms":2.341,"memory_kb":18,"result":"allow","message":null}
The log is rotated to:
var/log/custom-events-v2.log.1
Errors
If an error occurs in a handler, ERP writes it to the log and continues according to the rules of the specific event.
The handler runs inside the same PHP process as the ERP core. Thousands of operations pass through the core, so slow or faulty customer code can stop or destabilize the entire system. Do not use exit, die, endless loops, heavy SQL queries without limits, or long external operations. Keep handlers short and predictable.
Recommendations
- Use only
CustomEvent::...constants. - Do not write the event string manually.
- Keep handlers short.
- Do not call HTTP/webhook from high-frequency events.
- Do not use
exit,die, endless loops, or heavy selections without limits. - Return
true,false,null, or a string.
All events
All v2 events are listed below. The complete technical list of constants is in evolution/CustomEvents/Runtime/v2/CustomEvent.php.
The event fields are the current data contract.
Buildings
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::BUILDING_CREATED
|
After creating a building | building_id, data
|
CustomEvent::BUILDING_CHANGED
|
After editing a building | building_id, data
|
Commutation
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::COMMUTATION_CREATE_BEFORE
|
Before creating commutation between objects | source_type, source_id, target_type, target_id, data
|
CustomEvent::COMMUTATION_DELETE_BEFORE
|
Before deleting commutation between objects | source_type, source_id, target_type, target_id, data
|
Dashboard
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::DASHBOARD_TOP_CONTENT_RENDER
|
When rendering text at the top of the dashboard | employee_id, data
|
Equipment
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::DEVICE_CHANGED
|
After editing equipment | device_id, device_type, data
|
CustomEvent::DEVICE_NOTIFICATION_DOWN
|
When equipment unavailability is recorded | device_id, device_type, ip, data
|
CustomEvent::DEVICE_NOTIFICATION_UP
|
When equipment availability is restored | device_id, device_type, ip, data
|
CustomEvent::DEVICE_INTERFACE_PORT_NUMBER_RENDER
|
When rendering the port number in the interface table | device_id, interface_id, port_number, data
|
CustomEvent::DEVICE_INTERFACE_ADDITIONAL_DATA_RENDER
|
When rendering additional content in the equipment card | device_id, data
|
Customers
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::CUSTOMER_CREATED
|
After creating a customer | customer_id, data
|
CustomEvent::CUSTOMER_CHANGE_BEFORE
|
Before editing a customer | customer_id, data
|
CustomEvent::CUSTOMER_CHANGED
|
After editing a customer | customer_id, data
|
CustomEvent::CUSTOMER_MERGED
|
After merging customers | customer_id, target_customer_id, data
|
CustomEvent::CUSTOMER_STATUS_CHANGE_BEFORE
|
Before changing a customer status | customer_id, new_status_id, old_status_id, data
|
CustomEvent::CUSTOMER_STATUS_CHANGED
|
After changing a customer status | customer_id, new_status_id, old_status_id, data
|
CustomEvent::CUSTOMER_TARIFF_CHANGE_BEFORE
|
Before changing a customer tariff | customer_id, billing_id, new_tariff_id, old_tariff_id, data
|
CustomEvent::CUSTOMER_TARIFF_CHANGED
|
After changing a customer tariff | customer_id, billing_id, new_tariff_id, old_tariff_id, data
|
CustomEvent::CUSTOMER_BALANCE_CHANGED
|
When a customer balance changes | customer_id, amount, data
|
CustomEvent::CUSTOMER_FORMER_TRANSFER_BEFORE
|
Before moving a customer to former customers | customer_id, data
|
CustomEvent::CUSTOMER_FORMER_TRANSFERRED
|
After moving a customer to former customers | customer_id, data
|
CustomEvent::CUSTOMER_FORMER_RESTORE_BEFORE
|
Before restoring a customer from former customers | customer_id, data
|
CustomEvent::CUSTOMER_FORMER_RESTORED
|
After restoring a customer from former customers | customer_id, data
|
CustomEvent::CUSTOMER_DISCONNECT_PLAN_BEFORE
|
Before scheduling customer disconnection | customer_id, data
|
CustomEvent::CUSTOMER_DISCONNECT_PLANNED
|
After scheduling customer disconnection | customer_id, data
|
CustomEvent::CUSTOMER_DISCONNECT_BEFORE
|
Before disconnecting a customer | customer_id, data
|
CustomEvent::CUSTOMER_DISCONNECTED
|
After disconnecting a customer | customer_id, data
|
CustomEvent::CUSTOMER_DISCONNECT_CANCEL_BEFORE
|
Before cancelling customer disconnection | customer_id, data
|
CustomEvent::CUSTOMER_DISCONNECT_CANCELLED
|
After cancelling customer disconnection | customer_id, data
|
CustomEvent::CUSTOMER_SERVICE_ENABLE_BEFORE
|
Before enabling a service for a customer | customer_id, service_id, data
|
CustomEvent::CUSTOMER_SERVICE_ENABLED
|
After enabling a service for a customer | customer_id, service_id, data
|
CustomEvent::CUSTOMER_SERVICE_DISABLE_BEFORE
|
Before disabling a service for a customer | customer_id, service_id, data
|
CustomEvent::CUSTOMER_SERVICE_DISABLED
|
After disabling a service for a customer | customer_id, service_id, data
|
Customer IP/MAC
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::CUSTOMER_IP_ADD_BEFORE
|
Before adding an IP/MAC address | customer_id, ip, mac, subnet_property, data
|
CustomEvent::CUSTOMER_IP_ADDED
|
After adding an IP/MAC address | customer_id, ip, mac, subnet_property, data
|
CustomEvent::CUSTOMER_IP_DELETE_BEFORE
|
Before deleting an IP/MAC address | customer_id, ip, mac, subnet_property, data
|
CustomEvent::CUSTOMER_IP_DELETED
|
After deleting an IP/MAC address | customer_id, ip, mac, subnet_property, data
|
Customer tags
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::CUSTOMER_TAG_ADD_BEFORE
|
Before adding a tag to a customer | customer_id, tag_id, data
|
CustomEvent::CUSTOMER_TAG_ADDED
|
After adding a tag to a customer | customer_id, tag_id, data
|
CustomEvent::CUSTOMER_TAG_DELETE_BEFORE
|
Before deleting a customer tag | customer_id, tag_id, data
|
CustomEvent::CUSTOMER_TAG_DELETED
|
After deleting a customer tag | customer_id, tag_id, data
|
Customer portal
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::CUSTOMER_PORTAL_REGISTRATION_BEFORE
|
Before registering a customer in the customer portal | customer_id, data
|
CustomEvent::CUSTOMER_PORTAL_REGISTERED
|
After registering a customer in the customer portal | customer_id, data
|
CustomEvent::CUSTOMER_PORTAL_LOGIN_BEFORE
|
Before a customer logs in to the customer portal | customer_id, data
|
CustomEvent::CUSTOMER_PORTAL_DASHBOARD_RENDER
|
When rendering content on the customer portal dashboard | customer_id, data
|
CustomEvent::CUSTOMER_PORTAL_PAGE_RENDER
|
When rendering content on customer portal pages | customer_id, page_mode, page_id, data
|
CustomEvent::CUSTOMER_PORTAL_HEAD_RENDER
|
When rendering content after head in the customer portal
|
customer_id, data
|
Customer card
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::CUSTOMER_CARD_PRIMARY_CONTENT_RENDER
|
When rendering the main content in the customer card | customer_id, mode, employee_id, data
|
CustomEvent::CUSTOMER_CARD_SECONDARY_CONTENT_RENDER
|
When rendering additional content in the customer card | customer_id, mode, employee_id, ip_mac, data
|
CustomEvent::CUSTOMER_CARD_IP_MAC_CONTENT_RENDER
|
When rendering information near customer IP/MAC addresses | customer_id, ip, mac, data
|
CustomEvent::CUSTOMER_CARD_SMS_CONTENT_RENDER
|
When rendering SMS sending content in the customer card | customer_id, data
|
Employees
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::EMPLOYEE_MESSAGE_CREATED
|
After creating a message for an employee | receiver_employee_id, message_id, data
|
CustomEvent::EMPLOYEE_CHANGED
|
After editing an employee | employee_id, data
|
CustomEvent::EMPLOYEE_PERSONAL_SECTION_CONTENT_RENDER
|
When rendering information in an employee personal section | employee_id, data
|
Timesheet
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::EMPLOYEE_TIMESHEET_PRINT_HEADER_RENDER
|
When rendering the printed timesheet header | employee_id, period, data
|
CustomEvent::EMPLOYEE_TIMESHEET_PRINT_FOOTER_RENDER
|
When rendering the printed timesheet footer | employee_id, period, data
|
Warehouse
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::INVENTORY_TRANSFER_BEFORE
|
Before moving inventory items | inventory_id, operation_id, data
|
CustomEvent::INVENTORY_TRANSFERRED
|
After moving inventory items | inventory_id, operation_id, data
|
Tasks
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::TASK_CARD_RENDER
|
When rendering content in the task card | task_type_id, task_id, employee_id, data
|
CustomEvent::TASK_WORK_DATE_RENDER
|
When rendering content near the work date | task_type_id, task_id, employee_id, data
|
CustomEvent::TASK_CREATE_BEFORE
|
Before creating a task | task_type_id, author_employee_id, data
|
CustomEvent::TASK_CREATED
|
After creating a task | task_id, task_type_id, author_employee_id, data
|
CustomEvent::TASK_DELETE_BEFORE
|
Before deleting a task | task_id, data
|
CustomEvent::TASK_CHANGE_BEFORE
|
Before editing a task | task_id, data
|
CustomEvent::TASK_CHANGED
|
After editing a task | task_id, data
|
CustomEvent::TASK_COMMENT_CREATE_BEFORE
|
Before adding a task comment | task_id, comment, data
|
CustomEvent::TASK_COMMENT_CREATED
|
After adding a task comment | task_id, comment_id, comment, data
|
CustomEvent::TASK_COMMENT_CHANGED
|
After editing a task comment | task_id, comment_id, comment, data
|
CustomEvent::TASK_COMMENT_TEXT_RENDER
|
When rendering task comment text | task_id, comment_id, comment, data
|
CustomEvent::TASK_DIVISION_ASSIGN_BEFORE
|
Before adding a division to a task | task_id, division_id, data
|
CustomEvent::TASK_DIVISION_REMOVE_BEFORE
|
Before removing a division from a task | task_id, division_id, data
|
CustomEvent::TASK_EMPLOYEE_ASSIGN_BEFORE
|
Before adding an assignee to a task | task_id, employee_id, data
|
CustomEvent::TASK_EMPLOYEE_REMOVE_BEFORE
|
Before removing an assignee from a task | task_id, employee_id, data
|
CustomEvent::TASK_WATCHER_DIVISION_ASSIGN_BEFORE
|
Before adding a division as a watcher | task_id, division_id, data
|
CustomEvent::TASK_WATCHER_EMPLOYEE_ASSIGN_BEFORE
|
Before adding an employee as a watcher | task_id, employee_id, data
|
CustomEvent::TASK_OBJECT_ATTACHED
|
After adding an object to a task | task_id, object_type, object_id, data
|
CustomEvent::TASK_OBJECT_DETACHED
|
After removing an object from a task | task_id, object_type, object_id, data
|
CustomEvent::TASK_RETURNED_TO_AUTHOR
|
After returning a task to the author | task_id, data
|
CustomEvent::TASK_STATE_CHANGE_BEFORE
|
Before changing a task status | task_id, old_state_id, new_state_id, data
|
CustomEvent::TASK_STATE_CHANGED
|
After changing a task status | task_id, old_state_id, new_state_id, data
|
Communications installations
| Constant | When called | $event data
|
|---|---|---|
CustomEvent::NODE_CARD_ADDITIONAL_DATA_RENDER
|
When rendering additional content in the communications installation card | node_id, data
|
CustomEvent::NODE_CARD_PRIMARY_CONTENT_RENDER
|
When rendering the main content in the communications installation card | node_id, data
|