> ## Documentation Index
> Fetch the complete documentation index at: https://docs.worldvisagroup.com/llms.txt
> Use this file to discover all available pages before exploring further.

# FCM Push Integration with WorldVisa

> Configure the FCM push provider in WorldVisa: connect your Firebase service account, register subscriber device tokens, and send push notifications.

This guide explains the process of configuring and using FCM with WorldVisa, from getting your credentials to sending your first notification.

> [!NOTE]
>
> WorldVisa uses FCM version V1

## Step 1: Generate your service account key from Firebase

Get your project's service account credentials from the Firebase Console.

1. Log in to the [Firebase console](https://console.firebase.google.com/).
2. Create a new Firebase project or select an existing project.

   ![Select Firebase Project](https://mintcdn.com/wv-enterprise/l3bkwl1N_3mOn9aW/images/developers/channels-and-providers/push/select-firebase-project.png?fit=max\&auto=format\&n=l3bkwl1N_3mOn9aW\&q=85\&s=4117cf08e4ca850bf890b52c0aaa8c59)
3. Click the gear icon ⚙️ next to **Project Overview**.
4. Select **Project settings**.

   ![Firebase Project Settings](https://mintcdn.com/wv-enterprise/l3bkwl1N_3mOn9aW/images/developers/channels-and-providers/push/firebase-project-settings.png?fit=max\&auto=format\&n=l3bkwl1N_3mOn9aW\&q=85\&s=c6e6c5c5269690a506686e1b5b39dc7a)
5. Click the **Service accounts** tab.
6. Click the **Generate new private key** button. A confirmation menu appears.

   ![Firebase Service Accounts](https://mintcdn.com/wv-enterprise/l3bkwl1N_3mOn9aW/images/developers/channels-and-providers/push/firebase-service-accounts.png?fit=max\&auto=format\&n=l3bkwl1N_3mOn9aW\&q=85\&s=797f6eb3069114bb3316350fc1b05264)
7. Click **Generate key** to download a JSON file containing your credentials.

   ![Firebase generate private key confirmation dialog](https://mintcdn.com/wv-enterprise/l3bkwl1N_3mOn9aW/images/developers/channels-and-providers/push/confirmation-menu.png?fit=max\&auto=format\&n=l3bkwl1N_3mOn9aW\&q=85\&s=f39c04a8c16953c99f913d86831595d0)
8. Open the downloaded JSON file and ensure it contains these fields:
   ```json theme={null}
   {
     "type": "service_account",
     "project_id": "PROJECT_ID",
     "private_key_id": "PRIVATE_KEY_ID",
     "private_key": "PRIVATE_KEY",
     "client_email": "FIREBASE_ADMIN_SDK_EMAIL",
     "client_id": "CLIENT_ID",
     "auth_uri": "https://accounts.google.com/o/oauth2/auth",
     "token_uri": "https://oauth2.googleapis.com/token",
     "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
     "client_x509_cert_url": "CLIENT_X509_CERT_URL"
   }
   ```

## Step 2: Connect FCM to WorldVisa

Add the credentials to your FCM integration in the WorldVisa dashboard.

1. Log in to the WorldVisa dashboard.
2. Navigate to the **Integration Store**.
3. Click **Connect provider**.
4. Click the **Push** tab, then select **Firebase Cloud Messaging (FCM)**.
5. Open the JSON file you downloaded from Firebase in [Step 1](https://docs.worldvisagroup.com/developers/integrations/push/fcm.md#step-1-generate-your-service-account-key-from-firebase).
6. Copy the entire content of the JSON file and paste it into the **Service Account** field in the FCM integration modal.

   ![FCM integration](https://mintcdn.com/wv-enterprise/l3bkwl1N_3mOn9aW/images/developers/channels-and-providers/push/fcm-integration.png?fit=max\&auto=format\&n=l3bkwl1N_3mOn9aW\&q=85\&s=56171b008117158bc5eb45139ce2cf30)
7. Click **Create Integration** to save the integration.

## Step 3: Register a subscriber's device token

Before WorldVisa can send a push notification to your subscriber, you must associate their device's unique push token with their WorldVisa subscriber profile.

You can do this by making an API call to update the subscriber's credentials.

```bash theme={null}
curl -L -X PUT "${WV_API_URL}/v1/subscribers/<SUBSCRIBER_ID>/credentials" \
-H 'Content-Type: application/json' \
-H "Authorization: ApiKey ${WV_API_KEY}" \
-d '{
  "providerId": "fcm",
  "credentials": {
    "deviceTokens": [
      "token1",
      "token2"
    ]
  },
  "integrationIdentifier": "string"
}'
```

### Remove device tokens

When a subscriber logs out or uninstalls your app, remove their FCM device token so notifications are not delivered to the wrong user. See [Remove device tokens](https://docs.worldvisagroup.com/developers/integrations/push#remove-device-tokens) on the Push channel guide for removing a specific token, clearing all tokens for a provider, and automatic stale-token cleanup for FCM.

## Step 4: Send a notification

Now you're ready to send a push notification. You can trigger a notification to a subscriber who has a registered device token.

```bash theme={null}
curl --location "${WV_API_URL}/v1/events/trigger" \
--header 'Content-Type: application/json' \
--header "Authorization: ApiKey ${WV_API_KEY}" \
-d '{
    "name": "workflowId",
    "to": [
        "subscriberId"
    ],
    "payload": {
        "key": "value"
    },
    "overrides": {
        "providers": {
            "fcm": {
                "topic": "topic-123"
            }
        }
    }
}'
```

## Configure FCM overrides

Save an FCM override on the Push step when you need Firebase [HTTP v1 Message](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#Message) fields beyond the step subject and body — for example `data`, platform payloads (`android`, `apns`, `webpush`), `fcmOptions`, or routing (`token`, `tokens`, `topic`, `condition`). The override is stored on the step, so it is versioned and promoted with the workflow, and every trigger sends it without changing your trigger call.

> [!NOTE]
>
> Provider content overrides in the workflow editor are rolling out gradually and may not be available on your Push step yet. Overrides passed at trigger time work regardless. See [provider content overrides](https://docs.worldvisagroup.com/developers/integrations/push#provider-content-overrides).

FCM overrides are validated against the FCM HTTP v1 `Message` shape, plus WorldVisa's multicast `tokens` key. The editor autocompletes supported field names, validates the JSON, and flags unsupported fields.

Supported top-level keys: `notification`, `data`, `android`, `apns`, `webpush`, `fcmOptions`, `token`, `tokens`, `topic`, and `condition`. `token`, `topic`, and `condition` match the HTTP v1 target fields; `tokens` is WorldVisa's multicast alias (Firebase Admin `MulticastMessage`). Step content overrides use the HTTP v1 field names (including `webpush`); trigger examples elsewhere on this page may still show WorldVisa's `webPush` alias.

`notification.body` is the primary content key. If your override omits it, WorldVisa uses the rendered Push step body.

### Routing with content overrides

You may set exactly one of `token`, `tokens`, `topic`, or `condition` in a step content override. These fields support [Liquid](https://docs.worldvisagroup.com/developers/workflow/add-notification-content/personalize-content.md#apply-logic-with-liquidjs), for example `topic: "org-{{subscriber.data.orgId}}"`.

When you omit routing keys, WorldVisa fills device tokens from the subscriber's credentials for normal deliveries.

> [!WARNING]
>
> A static `topic` or `condition` in a step content override is evaluated once per matching subscriber. If a trigger targets N subscribers, WorldVisa sends N topic (or condition) broadcasts. Prefer a [trigger-time](https://docs.worldvisagroup.com/developers/integrations/trigger-overrides.md) `topic` when you want a single broadcast for the whole trigger, or use subscriber-specific Liquid so each subscriber resolves a distinct target.

Trigger overrides for these routing keys still work. When the same routing field is set both on the step and at trigger time, the trigger value wins. See [provider override scopes](https://docs.worldvisagroup.com/developers/integrations/trigger-overrides.md#provider-override-scopes).

### Routing with `_passthrough`

Routing keys also take effect inside `_passthrough.body`, which is merged last and therefore wins over the same field set on the step or at trigger time. You own the destination when you set these fields.

Because FCM addresses one destination per message, a routing key in `_passthrough.body` replaces the whole set rather than adding to it. In the example below the message goes to `news_updates` only — the `tokens` array is dropped, not sent alongside:

```json theme={null}
{
  "overrides": {
    "providers": {
      "fcm": {
        "tokens": ["token1", "token2"],
        "_passthrough": {
          "body": {
            "topic": "news_updates"
          }
        }
      }
    }
  }
}
```

WorldVisa ignores a passthrough routing value it cannot address — anything that is not a non-empty string, or for `tokens` an array of non-empty strings — and falls back to the routing set below it. Unlike the schematized keys, `_passthrough` is not validated, so a typo or a wrong type is silently ignored instead of flagged.

The per-subscriber fan-out warning above applies to a `topic` or `condition` set in `_passthrough` too.

See the [FCM HTTP v1 Message reference](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#Message) for the full field list.

## Web push with relative links

Suppose you're using the Firebase (FCM) provider to send push notifications to web browsers via WorldVisa and want users to be returned to the website after clicking the notification.

In that case, you must use the `link` property with a relative URL.

```bash theme={null}
curl --location "${WV_API_URL}/v1/events/trigger" \
--header 'Content-Type: application/json' \
--header "Authorization: ApiKey ${WV_API_KEY}" \
-d '{
    "name": "workflowId",
    "to": [
        "subscriberId"
    ],
    "payload": {
        "key": "value"
    },
    "overrides": {
        "providers": {
            "fcm": {
                "webPush": {
                    "fcmOptions": {
                        "link": "/foo"
                    }
                }
            }
        }
    }
}'
```

## Frequently asked questions

> [accordion] FCM cost
>
> As per Firebase [pricing](https://firebase.google.com/pricing), **Cloud Messaging** product is free to use. If other Firebase products are used, then the cost are charged per the product.

> [accordion] The registration token is not a valid FCM registration token
>
> You might come across an error such as: `Sending message failed due to "The registration token is not a valid FCM registration token"`. This error happens because of an invalid or stale token. The fix for this is:
>
> 1. Remove the old tokens.
> 2. Generate a new token.
> 3. Save the new token into user subscribers.

> [accordion] FCM notifications sent successfully with no error but push notification is not received in device
>
> Try to generate a new token after clearing device cache and retry with this fresh token.

> [accordion] Sending message failed due to 'Requested entity was not found'
>
> This error occurs when your token is no longer valid. To fix this, generate a new token and use it.

> [accordion] Subscriber does not have a configured channel error
>
> This error occurs if the FCM integration is active, but the subscriber is missing from the FCM credentials (deviceTokens). The credentials (deviceTokens) for the subscriber needs to be set.

> [accordion] How to send desktop notifications using FCM
>
> Desktop notifications for websites can be sent using FCM webpush.

## Activity tracking

FCM supports [push activity tracking](https://docs.worldvisagroup.com/developers/integrations/push/push-activity-tracking.md). Enable the **Push Activity Tracking** toggle on the FCM integration. Your app reads the WorldVisa message id from the notification and forwards it as `eventId`.

WorldVisa adds `__nvMessageId` to the FCM `data` payload.

* On a notification message, `data` contains `__nvMessageId` and any `data` keys from your FCM override. Other trigger payload fields stay off the FCM message.
* On a data-only message, set `type` to `data` under `overrides.providers.fcm`. `data` then contains the trigger payload, `__nvMessageId`, `title`, `body`, and `message`.

FCM requires every `data` value to be a string. `__nvMessageId` is already a string. Leave that key in place. An override `data` object is merged on top, and a matching key replaces WorldVisa's value.

```javascript theme={null}
import messaging from '@react-native-firebase/messaging';

const trackNotificationOpen = async (remoteMessage) => {
  await fetch("https://your-api.com/api/notifications/events", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      eventType: "opened",
      eventId: remoteMessage?.data?.__nvMessageId,
    }),
  });
};

messaging().onNotificationOpenedApp(trackNotificationOpen);

messaging().getInitialNotification().then((remoteMessage) => {
  if (remoteMessage) {
    trackNotificationOpen(remoteMessage);
  }
});
```

Forward `delivered`, `clicked`, `dismissed`, or `failed` the same way when your app observes those events. Your backend then calls [WorldVisa's activity endpoint](https://docs.worldvisagroup.com/developers/integrations/push/push-activity-tracking.md#step-3-forward-events-to-WorldVisa-from-your-backend).


## Related topics

- [Pushpad Push Integration with WorldVisa](https://docs.worldvisagroup.com/developers/integrations/push/pushpad.md)
- [Pusher Beams Push Integration with WorldVisa](https://docs.worldvisagroup.com/developers/integrations/push/pusher-beams.md)
- [OneSignal Push Integration with WorldVisa](https://docs.worldvisagroup.com/developers/integrations/push/onesignal.md)
- [Activity Tracking](https://docs.worldvisagroup.com/developers/integrations/push/push-activity-tracking.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.