Hilfebereich Set up a mobile app for push notifications (FCM V1 & APNs)

Set up a mobile app for push notifications (FCM V1 & APNs)

Set up a mobile app for push notifications (FCM V1 & APNs)

This guide covers integrating SMSBAT push notifications into your iOS and Android apps.


Stage 1. Firebase project and service account (FCM V1)

SMSBAT sends push through FCM V1 on both Android and iOS. That means you upload exactly one file to SMSBAT: the Firebase service account. The APNs key is never uploaded to SMSBAT — Firebase needs it, we don’t (see Stage 3).

1. Get the service account from Firebase

  1. Firebase Console → Project Settings → Service accounts tab.
  2. Generate new private key → confirm → a .json file downloads.

This is not the same file as google-services.json

google-services.json and GoogleService-Info.plist ship inside the app. The service account is a private server key and belongs only in SMSBAT. Never put it in app code, a repository, or a chat message.

2. Create the integration in SMSBAT Omni

  1. Open Integrations and pick Firebase from the list on the left.
  2. Click Create.
  3. Fill in two fields:
    • Name — any label that helps you recognise the app in the list (for example, Omnichannel Contact Center).
    • Service account JSON — click Choose and select the downloaded file.
  4. Click Create.

There is no field for a package name or bundle ID here — SMSBAT reads the Project ID from the file itself and shows it in the table.

3. Check that the integration came up

A row appears with Name, Project ID, Status and Created At. The working state is Active.

The buttons at the end of the row:

ButtonAction
Pencil (blue)change the name or replace the service account file
Refresh (green)re-read the key and re-check access to FCM
Bin (red)delete the integration

The Project ID must match the one in your app

Compare Project ID in the table against project_id in google-services.json (Android) and GoogleService-Info.plist (iOS). If they differ, the app is registered in one Firebase project while SMSBAT sends to another. Tokens will look valid, nothing will arrive, and no error will be returned. This is the most common cause of “everything is configured and nothing comes through”.

If you rotate the key in Firebase, upload the new file through the pencil button and press the green one. A revoked key stops working silently.

4. Application key

Requests from the app to the SMSBAT Push API are authenticated with the application key issued for your app in the Omni panel, passed as a header:

X-Push-App-Key: <application key>

See the Push API overview for the full request reference.


Stage 2. Android (Kotlin / Java)

1. Dependencies

In your module’s build.gradle:

dependencies {
    implementation 'com.google.firebase:firebase-messaging-ktx:23.4.0'
    implementation 'com.google.firebase:firebase-installations-ktx:17.2.0'
}

2. Register the Firebase Installation ID (FID)

When the user signs in or the app starts, read the FID and send it to SMSBAT:

FirebaseInstallations.getInstance().id.addOnCompleteListener { task ->
    if (task.isSuccessful) {
        val fid = task.result
        registerInstallationOnSmsbat(fid, currentUserId)
    }
}

fun registerInstallationOnSmsbat(fid: String, userId: String) {
    val json = JSONObject().apply {
        put("externalUserId", userId)
        put("firebaseInstallationId", fid)
        put("platform", "android")
        put("notificationsEnabled", true)
    }

    // HTTP POST to https://restapi.smsbat.com/api/push/registerInstallation
    // Header: X-Push-App-Key = YOUR_PUSH_APP_KEY
}

3. Handle the push and report delivered

In your FirebaseMessagingService:

class MyFirebaseMessagingService : FirebaseMessagingService() {

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        val data = remoteMessage.data
        val notificationGuid = data["guid"]

        if (!notificationGuid.isNullOrEmpty()) {
            // 1. Confirm delivery so SMSBAT stops the cascade
            sendDeliveryStatus(notificationGuid, "delivered")
        }

        // 2. Draw the local notification yourself (NotificationManager)
        showNotification(data["title"], data["body"], data)
    }

    private fun sendDeliveryStatus(guid: String, status: String) {
        // HTTP POST to https://restapi.smsbat.com/api/push/notifications/$guid/status
        // Header: X-Push-App-Key = YOUR_PUSH_APP_KEY
        // Body: { "status": "delivered", "occurredAt": "2026-08-07T12:00:00Z" }
    }
}

Why you draw the banner yourself

SMSBAT sends data-only messages so the app can report delivered before the user opens anything. The system does not render a banner for data-only messages — the app must do it.


Stage 3. iOS (Swift / APNs)

On iOS the APNs key is uploaded to Firebase, not to SMSBAT: Firebase Console → Cloud Messaging → APNs Authentication Key. FCM V1 then delivers to Apple on your behalf.

1. Add a Notification Service Extension

To confirm delivery and handle rich content (images, sounds, buttons), add a Notification Service Extension target in Xcode:

import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        if let bestAttemptContent = bestAttemptContent {
            let userInfo = bestAttemptContent.userInfo
            if let guid = userInfo["guid"] as? String {
                // Report delivered to SMSBAT
                sendPushStatus(guid: guid, status: "delivered")
            }
            contentHandler(bestAttemptContent)
        }
    }
}

2. Handle the tap (seen)

In your AppDelegate or SceneDelegate:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo
    if let guid = userInfo["guid"] as? String {
        // Report seen to SMSBAT
        sendPushStatus(guid: guid, status: "seen")
    }
    completionHandler()
}

Result

Once integrated, the app receives notifications instantly, the cascade stops as soon as push is delivered so paid channels are not charged, and you get accurate delivery and read statistics.

If something does not arrive, work through Push troubleshooting — it covers the failures that produce no error at all.