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.
RASP Callbacks
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.
Malware Callbacks
Callbacks are also triggered when an APK linked to an application transitions between malware states:
| Callback type | Description |
|---|---|
MALWARE_DETECTED |
An APK linked to the application was classified as malware. |
MALWARE_REMOVED |
An APK previously classified as malware was unlinked from the application, or is not classified as malware anymore. |
MALWARE_HEALED |
The application no longer has any malware-classified APK of a specific malware type linked, having had at least one before. |
A callback is dispatched only when the malware type is BANKER.
Like RASP callbacks, malware callbacks are replayed on a Client ID update: the platform replays all
previously recorded malware detection, removal, and healed events for the device, subject to the same BANKER-only
dispatch filter described above.
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 iap_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 iap_app_type_callback_config (app_type_id, url, retry_attempts, retry_backoff)
VALUES (
(SELECT id FROM iap_app_type WHERE source_package_name = 'com.example.app'),
'https://custom-system.example.com/webhook',
3,
'PT2S'
);
Authentication
Callbacks can be secured using mutual TLS (mTLS). Authentication is configured by storing a JSON document in the
authentication column of the iap_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 INAPPPROTECTION_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 |
|---|---|---|
event.type |
string | Callback type: DEVICE_SECURITY_VIOLATED, DEVICE_SECURITY_RESTORED, MALWARE_DETECTED, MALWARE_REMOVED or MALWARE_HEALED |
event.info.type |
string | Name of the flag that changed for DEVICE_SECURITY_VIOLATED / DEVICE_SECURITY_RESTORED callbacks, malware type for malware callbacks (always BANKER) |
event.info.name |
String | Application name (present only for malware callbacks) |
event.info.packageName |
String | Application package name (present only for malware callbacks) |
event.info.apkSignature |
String | Application signature (present only for malware callbacks) |
event.info.installation.timestamp |
long | Unix timestamp in seconds of first detection of an application installation (present only for malware callbacks) |
event.info.installation.installer |
string | Identification of the installer (present only for malware callbacks) |
event.timestamp |
long | Unix epoch timestamp in seconds when the flag change was detected |
device.appPackageName |
string | Package name of the mobile application |
device.audienceGroupId |
string | Distinguishes users from different customer systems (e.g. RETAIL, CORPORATE) |
device.clientDeviceId |
string | Customer-assigned device ID |
device.clientId |
string | Customer-assigned client ID |
device.deviceId |
string (UUID) | System-assigned device ID |
device.timestampFirstSeen |
long | Unix epoch timestamp in seconds when the device was first registered |
device.timestampLastSeen |
long | Unix epoch timestamp in seconds of the most recent activity |
device.sourcePackageName |
string | Package name of the source application |
device.sourceInstaller |
string | Package name of the installer that distributed the source application |
device.deviceInfo.os |
string | Operating system name (e.g. android, huawei, ios, mac_os, tv_os) |
device.deviceInfo.platform |
string | Platform identifier: android or apple |
device.deviceInfo.brand |
string | Device manufacturer brand |
device.deviceInfo.model |
string | Device model identifier |
device.deviceInfo.versionSdkInt |
integer | Operating system version |
device.deviceInfo.versionSecurityPatch |
string | Security patch level of the operating system |
device.deviceInfo.versionRelease |
string | The user-visible version string |
device.deviceInfo.versionIncremental |
string | The value used by the underlying source control to represent the device firmware build |
device.deviceInfo.tags |
string | Tags describing the operating system build |
device.flags[].name |
string | Name of the flag associated with the device. |
device.flags[].score |
integer | Risk score associated with the flag |
device.flags[].timestamp |
long | Unix epoch timestamp in seconds when the flag was detected |
device.malware[].type |
string | Type of the detected malware (always BANKER). Present only for malware callbacks, empty otherwise |
device.malware[].name |
string | Application name of the malware APK |
device.malware[].packageName |
string | Package name of the malware APK |
device.malware[].apkSignature |
string | SHA-256 digest of the malware APK |
device.malware[].installation.timestamp |
long | Unix epoch timestamp in seconds when the malware APK was first linked to the application |
device.malware[].installation.installer |
string | Package name of the installer that distributed the malware APK, if known |
device.highestApkThreat.name |
string | Name of the highest evaluated threat level for the application’s linked APK (e.g. MALWARE, DANGEROUS), omitted if not evaluated |
device.highestApkThreat.score |
integer | Score of device.highestApkThreat.name |
device.highestDeviceThreat.name |
string | Name of the highest-scoring flag currently assigned to the device. |
device.highestDeviceThreat.score |
integer | Score of device.highestDeviceThreat.name |
The device.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: RASP Callback
{
"event": {
"info": {
"type": "ROOTED"
},
"type": "DEVICE_SECURITY_VIOLATED",
"timestamp": 1745490600
},
"device": {
"appPackageName": "com.wultra.trader",
"audienceGroupId": "RETAIL",
"clientDeviceId": "device-abc",
"clientId": "user-123",
"deviceId": "f3a1c2e4-0000-0000-0000-000000000001",
"timestampFirstSeen": 1735689600,
"timestampLastSeen": 1745490600,
"sourcePackageName": "com.wultra.test",
"sourceInstaller": "com.google.android.packageinstaller",
"deviceInfo": {
"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": 1745490600
},
{
"name": "DEVELOPER_MODE",
"score": 70,
"timestamp": 1745490300
}
],
"malware": [],
"highestApkThreat": {
"name": "SAFE",
"score": 0
},
"highestDeviceThreat": {
"name": "ROOTED",
"score": 90
}
}
}
Example: Malware Callback
{
"event": {
"info": {
"name": "CoinBase",
"type": "BANKER",
"packageName": "net.bhldc.kuxz",
"apkSignature": "54eeef11a8197e686b7827e180b0e8d8fee4882ae4af67828dd7e11140d708ac",
"installation": {
"installer": "com.google.android.packageinstaller",
"timestamp": 1785640763
}
},
"type": "MALWARE_DETECTED",
"timestamp": 1785640766
},
"device": {
"appPackageName": "com.wultra.test.bank",
"audienceGroupId": "RETAIL",
"clientDeviceId": "167662723c2ace97",
"clientId": "user-123",
"deviceId": "226d7c8d-4abe-442b-acd1-e6c440598785",
"timestampLastSeen": 1785640763,
"timestampFirstSeen": 1785640722,
"sourcePackageName": "cz.csob.smart",
"sourceInstaller": "com.android.vending",
"deviceInfo": {
"os": "android",
"tags": "release-keys",
"brand": "Redmi",
"model": "23108RN04Y",
"platform": "android",
"versionSdkInt": 35,
"versionRelease": "15",
"versionIncremental": "OS2.0.210.0.VGPEUXM",
"versionSecurityPatch": "2026-05-01"
},
"malware": [
{
"name": "CoinBase",
"type": "BANKER",
"packageName": "net.bhldc.kuxz",
"apkSignature": "54eeef11a8197e686b7827e180b0e8d8fee4882ae4af67828dd7e11140d708ac",
"installation": {
"installer": "com.google.android.packageinstaller",
"timestamp": 1785640763
}
}
],
"flags": [
{
"name": "ROOTED",
"score": 90,
"timestamp": 1745490600
},
{
"name": "DEVELOPER_MODE",
"score": 70,
"timestamp": 1745490300
}
],
"highestApkThreat": {
"name": "MALWARE",
"score": 100
},
"highestDeviceThreat": {
"name": "ROOTED",
"score": 90
}
}
}