Customizing Webhook Payloads
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/kotlin/com/fathiraz/flowbell/data/remote/dto/WebhookPayload.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/mappers/NotificationMapper.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/services/WebhookService.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/services/NotificationListenerService.kt
- app/src/main/kotlin/com/fathiraz/flowbell/core/utils/HttpRequestUtils.kt
- README.md
FlowBell employs a standardized, structured JSON payload to forward Android notifications to remote webhook endpoints. This system ensures that every notification captured by the NotificationListenerService is enriched with comprehensive metadata, including application details, device information, and security signatures, before being transmitted via HTTPS.
The payload architecture is designed for interoperability with automation tools like n8n, Zapier, and custom server implementations. It encapsulates the notification content, media references, and technical identifiers necessary for downstream processing and deduplication.
Webhook Payload Structure
The core of the customization system lies in the WebhookPayload Data Transfer Object (DTO). This structure organizes notification data into seven logical segments to provide a complete context of the captured event.
The diagram above illustrates the hierarchical relationship of the payload components.
Sources: app/src/main/kotlin/com/fathiraz/flowbell/data/remote/dto/WebhookPayload.kt:11-33, README.md:210-252
Component Definitions
| Component | Description | Fields |
|---|---|---|
| Identity | Top-level unique identifiers. | id (UUID), timestamp (ISO 8601) |
| App Info | Details of the app that triggered the notification. | packageName, name, version |
| Notification | The actual alert content and metadata. | title, text, subText, priority |
| Media | URIs and Base64 encoded icon data. | iconUri, largeIconUri, iconBase64, largeIconBase64 |
| Device | Hardware and software specifications of the sender. | id, platform, version, model, manufacturer |
| Security | Integrity and authentication metadata. | signature, nonce, algorithm |
Sources: app/src/main/kotlin/com/fathiraz/flowbell/data/remote/dto/WebhookPayload.kt:35-108
Data Flow and Payload Assembly
The generation of a webhook payload involves mapping raw Android StatusBarNotification data into the structured DTO. This process is orchestrated by the NotificationListenerService and handled specifically by the NotificationMapper.
The flow shows how incoming notification data is transformed into a serializable payload for network transmission.
Sources: app/src/main/kotlin/com/fathiraz/flowbell/data/services/NotificationListenerService.kt:501-536, app/src/main/kotlin/com/fathiraz/flowbell/data/mappers/NotificationMapper.kt:82-117
Mapping Logic
The NotificationMapper performs several critical transformations:
- Priority Mapping: Converts Android integer priorities (e.g.,
PRIORITY_MAX) into human-readable strings like "urgent", "high", or "normal". - Timestamp Formatting: Converts millisecond epoch timestamps into ISO 8601 strings using
DateTimeFormatter.ISO_INSTANT. - Unique Identity: Assigns a new
UUIDto each payload to ensure downstream idempotency. - Security Nonce: Generates a unique nonce for every request to prevent replay attacks.
Sources: app/src/main/kotlin/com/fathiraz/flowbell/data/mappers/NotificationMapper.kt:120-130, app/src/main/kotlin/com/fathiraz/flowbell/data/services/NotificationListenerService.kt:543-552
Payload Enhancement and Security
The WebhookService provides an additional layer for processing payloads before they are finalized. This includes enhancing the payload with media data and applying digital signatures.
Signature Generation
Security is enforced using the HMAC-SHA256 algorithm. The WebhookService uses a secret key (when configured) to generate a hex-encoded signature of the serialized JSON payload. This signature is then embedded in the SecurityPayload object.
val mac = Mac.getInstance("HmacSHA256")
val secretKeySpec = SecretKeySpec(secretKey.toByteArray(), "HmacSHA256")
mac.init(secretKeySpec)
val signature = mac.doFinal(payloadJson.toByteArray())
val signatureHex = signature.joinToString("") { "%02x".format(it) }
Sources: app/src/main/kotlin/com/fathiraz/flowbell/data/services/WebhookService.kt:87-98
Validation and Constraints
Before transmission, the system validates the payload to ensure all required fields are populated and that the total size does not exceed hardware or network limits (default 1024 KB).
Sources: app/src/main/kotlin/com/fathiraz/flowbell/data/services/WebhookService.kt:119-148
Transmission and Testing
The HttpRequestUtils utility handles the final delivery of the payload. It adds standard headers such as Content-Type: application/json and a custom User-Agent: FlowBell/1.0. For testing purposes, the system can generate a dummy payload that mirrors the production structure exactly, allowing users to verify their webhook endpoints without waiting for a real notification.
Sources: app/src/main/kotlin/com/fathiraz/flowbell/core/utils/HttpRequestUtils.kt:133-162, app/src/main/kotlin/com/fathiraz/flowbell/core/utils/HttpRequestUtils.kt:216-220
Customizing webhook payloads in FlowBell is achieved through the structured DTO architecture and mapping logic, ensuring that forwarded data is consistently formatted, secure, and rich in context.