Callbacks
The In-App Protection platform supports integration through HTTP callbacks. When a security-relevant state change is detected on a device, the Integration API sends an HTTP POST request to a pre-configured URL. This allows external systems to receive security events without active polling.
Callbacks are triggered when a set of critical security flags assigned to a device changes. Following flag types are currently classified as critical:
| Flag | Description |
|---|---|
JAILBROKEN |
The device has been jailbroken (iOS) |
ROOTED |
The device has been rooted (Android) |
UNWANTED_APPS |
A potentially harmful application is installed |
When any of the listed critical flags is assigned to a device, a DEVICE_SECURITY_VIOLATED callback type is sent.
When any of the listed critical flags is unassigned from a device, a DEVICE_SECURITY_RESTORED callback type is sent.
Note that DEVICE_SECURITY_RESTORED does not imply the device is fully secure — other critical flags may still be active.
Each callback represents a single flag change. If multiple critical flags change simultaneously, a separate callback is
generated for each individual change.
Additionally, when a Client ID is updated, the platform replays all previously recorded critical flag changes for the device. This ensures that the external system can associate the device’s security history with the updated user identity.
Configuration
Callback delivery is configured per application type. Each configuration entry defines a target endpoint and delivery behavior. Multiple entries can be defined for the same application type, in which case each configured endpoint receives its own HTTP POST request for every event.
Configuration is stored in the mlw_app_type_callback_config database table and must be managed directly at the
database level.
Configuration Fields
| Column | Type | Default | Description |
|---|---|---|---|
app_type_id |
integer | Identifier of the application type to which this configuration applies | |
url |
varchar(2048) | Destination URL for the HTTP POST | |
retry_attempts |
integer | 3 |
Maximum number of retry attempts after a failed delivery |
retry_backoff |
varchar(64) | PT2S |
Delay between retry attempts, in ISO 8601 duration format (e.g., PT2S = 2 seconds) |
authentication |
text | JSON-serialized authentication configuration (see below) |
Example of Inserting a Callback Configuration
INSERT INTO mlw_app_type_callback_config (app_type_id, url, retry_attempts, retry_backoff)
VALUES (
(SELECT id FROM mlw_app_type WHERE name = 'com.example.app'),
'https://custom-system.example.com/webhook'
);
Authentication
Callbacks can be secured using mutual TLS (mTLS). Authentication is configured by storing a JSON document in the
authentication column of the mlw_app_type_callback_config. The structure is as follows:
{
"certificate": {
"enabled": true,
"useCustomKeyStore": true,
"keyStoreLocation": "classpath:keystore.p12",
"keyStoreContent": "<base64-encoded-keystore>",
"keyStorePassword": "secret",
"keyAlias": "client",
"keyPassword": "secret",
"useCustomTrustStore": true,
"trustStoreLocation": "classpath:truststore.p12",
"trustStoreContent": "<base64-encoded-truststore>",
"trustStorePassword": "secret",
"handshakeTimeout": "PT10S"
}
}
Key and trust material can be provided either as a file location (keyStoreLocation, trustStoreLocation) or as
base64-encoded content (keyStoreContent, trustStoreContent). If the authentication field is NULL or enabled is
set to false, no authentication is applied.
The Web Client configuration used for callback delivery is cached for performance reasons. The cache is refreshed
according to the MLW_CALLBACK_WEBCLIENT_REFRESHCACHEAFTER configuration, by default every 5 minutes. When updating
the callback configuration, update also the timestamp_last_updated column.
Callback Request
HTTP Method and Headers
Callbacks are delivered as HTTP POST requests.
| Header | Description |
|---|---|
Idempotency-Key |
A UUID uniquely identifying the callback request. Can be used by the recipient to deduplicate deliveries in at-least-once scenarios. |
Content-Type |
application/json |
Request Body
The request body is a JSON object with the following structure:
| Field | Type | Description |
|---|---|---|
type |
string | Callback type: DEVICE_SECURITY_VIOLATED or DEVICE_SECURITY_RESTORED |
flagName |
string | Name of the flag that changed |
timestamp |
long | Unix epoch timestamp in milliseconds when the flag change was detected |
application.appPackageName |
string | Package name of the mobile application |
application.clientDeviceId |
string | Customer-assigned device ID |
application.clientId |
string | Customer-assigned client ID |
application.deviceId |
string (UUID) | System-assigned device ID |
application.timestampFirstSeen |
long | Unix epoch timestamp in milliseconds when the device was first registered |
application.timestampLastSeen |
long | Unix epoch timestamp in milliseconds of the most recent activity |
application.sourcePackageName |
string | Package name of the source application |
application.sourceInstaller |
string | Package name of the installer that distributed the source application |
application.device.os |
string | Operating system name (e.g. android, huawei, ios, mac_os, tv_os) |
application.device.platform |
string | Platform identifier: android or apple |
application.device.brand |
string | Device manufacturer brand |
application.device.model |
string | Device model identifier |
application.device.versionSdkInt |
integer | Operating system version |
application.device.versionSecurityPatch |
string | Security patch level of the operating system |
application.device.versionRelease |
string | The user-visible version string |
application.device.versionIncremental |
string | The value used by the underlying source control to represent the device firmware build |
application.device.tags |
string | Tags describing the operating system build |
application.flags[].name |
string | Name of the flag associated with the device |
application.flags[].score |
integer | Risk score associated with the flag |
application.flags[].timestamp |
long | Unix epoch timestamp in milliseconds when the flag was detected |
The application.flags field represents all flags currently active on the device at the time of dispatching. When a
callback is replayed (for example, after a client ID change), the flags reflect the active state at the time of replay,
not at the time of the original event.
Example
{
"type": "DEVICE_SECURITY_VIOLATED",
"flagName": "ROOTED",
"timestamp": 1745490600000,
"application": {
"appPackageName": "com.wultra.trader",
"clientDeviceId": "device-abc",
"clientId": "user-123",
"deviceId": "f3a1c2e4-0000-0000-0000-000000000001",
"timestampFirstSeen": 1735689600000,
"timestampLastSeen": 1745490600000,
"sourcePackageName": "com.wultra.test",
"sourceInstaller": "com.google.android.packageinstaller",
"device": {
"os": "android",
"platform": "android",
"brand": "Samsung",
"model": "SM-G950F",
"versionSdkInt": 28,
"versionSecurityPatch": "2019-08-01",
"versionRelease": "9",
"versionIncremental": "G950FXXS5DSH8",
"tags": "release-keys"
},
"flags": [
{
"name": "ROOTED",
"score": 90,
"timestamp": 1745490600000
},
{
"name": "DEVELOPER_MODE",
"score": 70,
"timestamp": 1745490300000
}
]
}
}