Appearance
Android SDK
Persistent device identification, registration, and real-time fraud detection for Android.
Installation
SDK Access
The Android SDK is provided during onboarding. Follow the installation instructions in your welcome documentation, or contact your Honeypot representative.
Requirements: Android API 21+, Kotlin 1.8+
Permissions:
xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />Initialization
Initialize once in your Application class:
kotlin
class App : Application() {
override fun onCreate() {
super.onCreate()
Honeypot.init(this) {
apiKey = BuildConfig.HONEYPOT_KEY
endpoint = "https://your-honeypot.honeypot.run"
}
}
}Device ID
Get the persistent device identifier. Survives app reinstalls, cannot be spoofed:
kotlin
val deviceId: String = Honeypot.deviceIdDevice Registration
Register devices to users. Honeypot maintains the registry — you don't need to build one.
Register a Device
kotlin
// Register this device to a user
val result = Honeypot.registerDevice(userId = "agent-12345") {
set("role", "bank_agent")
set("branch", "lagos-central")
set("registered_by", "admin@bank.com")
}
result.onSuccess { registration ->
// Device is now registered
println("Registered: ${registration.deviceId}")
println("User: ${registration.userId}")
println("Registered at: ${registration.registeredAt}")
}Check Registration Status
kotlin
// Check if current device is registered
val status = Honeypot.device.registration
when {
!status.isRegistered -> {
// Device not registered - show registration flow
}
status.userId != currentUserId -> {
// Device registered to different user - security alert
}
!status.isActive -> {
// Device was deactivated - block access
}
else -> {
// Device is registered and trusted
}
}Registration in Event Response
Every event response includes registration status:
kotlin
val result = Honeypot.track("Login")
result.onSuccess { response ->
// Registration info included automatically
val isRegistered = response.device.isRegistered
val registeredTo = response.device.registeredTo // userId or null
val registeredAt = response.device.registeredAt
// Plus risk signals
val riskScore = response.riskScore
val tags = response.tags
}Identify Users
Link events to a user identity:
kotlin
Honeypot.identify("user@example.com")
// Or with metadata
Honeypot.identify("agent-12345") {
set("role", "bank_agent")
set("branch", "lagos-central")
}Event Tracking
Track events and get real-time risk signals:
kotlin
val result = Honeypot.track("P2P Transfer") {
set("recipient_id", recipientId)
set("amount", amount)
set("currency", "NGN")
}
result.onSuccess { response ->
// Device registration status
val isRegistered = response.device.isRegistered
val isTrusted = response.device.isTrusted
// Risk assessment
val riskScore = response.riskScore
val tags = response.tags // ["vpn", "emulator", etc.]
// Behavioral data
val txCount = response.behaviors["count_transactions_1h"]?.count ?: 0
}Full Example: Agent Onboarding
kotlin
class AgentOnboardingViewModel : ViewModel() {
fun onboardAgent(agentId: String, branchCode: String) = viewModelScope.launch {
// Step 1: Check for device risks before registration
val checkResult = Honeypot.track("Agent Onboarding Started") {
set("agent_id", agentId)
set("branch_code", branchCode)
}
checkResult.onSuccess { response ->
when {
// Block compromised devices
response.tags.containsAny("emulator", "rooted", "hooked") -> {
_state.value = OnboardingState.Rejected("Device not supported")
return@onSuccess
}
// Check if device already registered to someone else
response.device.isRegistered && response.device.registeredTo != agentId -> {
_state.value = OnboardingState.Rejected(
"Device already registered to another agent"
)
return@onSuccess
}
// Flag high-risk for manual review
response.riskScore > 0.5 -> {
_state.value = OnboardingState.PendingReview
return@onSuccess
}
}
// Step 2: Register the device
registerDevice(agentId, branchCode)
}
}
private suspend fun registerDevice(agentId: String, branchCode: String) {
val result = Honeypot.registerDevice(userId = agentId) {
set("role", "bank_agent")
set("branch", branchCode)
set("registered_at", Clock.System.now().toString())
}
result.onSuccess { registration ->
Honeypot.identify(agentId) {
set("type", "agent")
set("branch", branchCode)
}
_state.value = OnboardingState.Success(registration.deviceId)
}
result.onFailure { error ->
_state.value = OnboardingState.Error(error.message)
}
}
}Full Example: Transaction with Device Verification
kotlin
class TransferViewModel : ViewModel() {
fun transfer(recipientId: String, amount: Double) = viewModelScope.launch {
val result = Honeypot.track("P2P Transfer") {
set("recipient_id", recipientId)
set("amount", amount)
set("currency", "NGN")
}
result.onSuccess { response ->
// First: Is this a known, registered device?
if (!response.device.isRegistered) {
_state.value = TransferState.Blocked("Please register this device first")
return@onSuccess
}
if (!response.device.isTrusted) {
_state.value = TransferState.Blocked("Device has been flagged. Contact support.")
return@onSuccess
}
// Second: Check for fraud signals
if (response.tags.containsAny("vpn", "proxy", "tor")) {
_state.value = TransferState.Blocked("Please disable VPN")
return@onSuccess
}
// Third: Velocity limits
val txCount = response.behaviors["count_transactions_1h"]?.count ?: 0
if (txCount > 10) {
_state.value = TransferState.Blocked("Too many transactions")
return@onSuccess
}
// Fourth: Step-up auth for risky situations
if (response.device.ageDays < 7 || response.riskScore > 0.3) {
_state.value = TransferState.RequiresBiometric
return@onSuccess
}
// Proceed with transfer
_state.value = TransferState.Ready
}
}
}Response Object
kotlin
data class HoneypotResponse(
val deviceId: String,
val device: DeviceInfo,
val riskScore: Double,
val tags: Set<String>,
val behaviors: Map<String, Behavior>,
val phoneIntel: PhoneIntel?, // If phone number provided
val emailIntel: EmailIntel? // If email provided
)
data class DeviceInfo(
// Registration status
val isRegistered: Boolean,
val isTrusted: Boolean, // Registered AND not flagged
val registeredTo: String?, // userId this device is registered to
val registeredAt: Instant?,
val role: String?, // "bank_agent", "customer", "driver", etc.
val metadata: Map<String, Any>, // Custom registration metadata
// Device metadata
val ageDays: Int,
val isNew: Boolean,
val model: String?,
val osVersion: String?
)
data class DeviceRegistration(
val deviceId: String,
val userId: String,
val role: String,
val registeredAt: Instant,
val metadata: Map<String, Any>
)
data class Behavior(
val count: Int?, // For count operations
val sum: Double?, // For sum operations
val unique: Int?, // For unique operations
val values: List<String>? // Unique values (if requested)
)Device Management API
kotlin
// Register device with role
Honeypot.registerDevice(userId = "agent-123") {
set("role", "bank_agent")
set("branch", "lagos-central")
}
// Check current registration
val registration = Honeypot.device.registration
if (registration.role == "bank_agent") {
// Show agent UI
}
// Deactivate this device (lost/stolen)
Honeypot.deactivateDevice(reason = "reported_stolen")Supervisor API (REST)
bash
# List all devices for a branch
GET /api/devices?role=bank_agent&branch=lagos-central
# Deactivate a specific device
POST /api/devices/{device_id}/deactivate
{ "reason": "agent_terminated", "by": "supervisor-001" }
# Transfer device to new agent
POST /api/devices/{device_id}/transfer
{ "new_user_id": "agent-456", "by": "supervisor-001" }Risk Tags
| Tag | Severity | Description |
|---|---|---|
emulator | Critical | Running on emulator |
rooted | Critical | Root access detected |
hooked | Critical | Frida/Xposed detected |
vpn | High | VPN connection |
proxy | High | Proxy detected |
tor | Critical | Tor network |
new_device | Medium | Device < 24h old |
unregistered | Medium | Device not registered |
multi_user | High | Registered to multiple users |
Offline Support
Critical for agent banking in areas with poor connectivity:
kotlin
// Events are queued automatically when offline
Honeypot.track("Agent Deposit") {
set("amount", 50000)
set("customer_id", customerId)
}
// Returns immediately with cached device info
// Syncs to server when connectivity returns
// Check sync status
val pending = Honeypot.pendingEvents
val lastSync = Honeypot.lastSyncTime
// Force sync when connectivity available
Honeypot.sync()Offline behavior:
- Events queued in local database (SQLite)
- Device registration status cached locally
- Risk decisions use cached data + local checks (emulator, root)
- Auto-sync when connectivity returns
- Conflict resolution: server wins for registration, merge for events
Next Steps
- Device Registration for Banking — Full banking implementation
- Event Payload Reference — Complete response fields
- Behaviors — Transaction velocity, limits
- REST API — Backend integration