Skip to main content

FCM Token Registration API

This document explains how the GOFA app registers a device push token with the backend.

Why this endpoint exists

A push notification can only be sent after the mobile app has:

  1. requested notification permission from the user,
  2. received a native FCM token from Firebase,
  3. identified the current signed-in user, and
  4. stored the token in Firestore under that user.

In the current GOFA mobile architecture:

  • the Flutter shell gets the native FCM token,
  • the WebView frontend asks Flutter for that token through a bridge,
  • the frontend sends the token to the backend,
  • the backend stores it under the signed-in user document.

Endpoint

POST /api/fcm/register

Authentication

This endpoint requires a signed-in user.

Use one of the following:

  • Authorization: Bearer <firebase_id_token>
  • or the authenticated session cookie flow already used by the app

In the current mobile flow, the frontend uses a Firebase ID token.

Request body

{
"fcmToken": "string",
"platform": "ios",
"installationId": "native-1772433667723-17uxidu",
"deviceInfo": {
"source": "flutter_webview",
"environment": "uat",
"app": "silvercare"
}
}

Field meaning

  • fcmToken: the native FCM token returned by Firebase Messaging
  • platform: usually ios, android, or web
  • installationId: a stable installation identifier for one app installation on one device
  • deviceInfo: optional metadata for debugging and device tracking

Response

Successful response:

{
"success": true,
"tokenHash": "...",
"tokenKey": "installation:native-1772433667723-17uxidu"
}

How the backend stores tokens

The current implementation stores tokens in the user document under:

Clients/{clientId}/ClientUsers/{uid}/fcmTokens

When installationId is provided, the backend uses this key format:

installation:{installationId}

This is important because it prevents duplicate token entries for the same app installation.

Important implementation detail

Do not generate installationId in the WebView using localStorage if the app can load from different origins.

Why:

  • Web storage is scoped by origin.
  • If the app runs on different URLs such as https://..., http://192.168.x.x:5173, or another dev host, the browser storage changes.
  • That produces multiple installation records for the same phone.

Recommended approach:

  • Generate and persist installationId in the Flutter shell.
  • Return it to the frontend through the WebView bridge.

Current GOFA implementation

Relevant backend file:

  • gofa-web-nextjs/src/app/api/fcm/register/route.ts

Relevant frontend files:

  • sc-gofa-beta1/src/services/fcmTokenService.ts
  • sc-gofa-beta1/src/services/nativeFcmRegistrationService.ts

Relevant Flutter file:

  • gofa-silvercare-flutter/lib/screens/webview_screen.dart

A mature app should not register a token on every render.

Recommended timing:

  1. after the user signs in successfully,
  2. after notification permission is granted,
  3. after a token refresh event,
  4. when the signed-in user changes,
  5. optionally as a low-frequency heartbeat.

Troubleshooting

Problem: duplicate fcmTokens entries

Likely cause:

  • unstable installationId

Fix:

  • move installationId generation to native Flutter storage

Problem: token exists but pushes do not arrive

Possible causes:

  • APNs key is not configured in Firebase for the iOS app
  • notification permission is not granted
  • the backend is sending only data and not a notification payload