1C-Bitrix Integration with Firebase Cloud Messaging

Push notifications are key to user engagement, but standard services don't always fit into the 1C-Bitrix architecture. We develop Firebase Cloud Messaging integration with custom code, fully adapting it to your project. Our team delivers a turnkey solution—from token setup to sending via the current FCM HTTP v1 API—ensuring reliable operation and ongoing support.

Our competencies:

Frequently Asked Questions

When your project outgrows third-party push services, you need a direct integration with Firebase Cloud Messaging (FCM). But FCM's HTTP v1 API demands a custom OAuth 2.0 setup, token management, and platform-specific payloads. Unlike OneSignal, FCM is a low-level transport without built-in UI or segmentation. We specialize in building this integration for high-load projects, ensuring stable delivery even under heavy traffic. The final cost is determined after a thorough analysis of your infrastructure and requirements.

How to Set Up FCM HTTP v1 API in 1C-Bitrix

Google has deprecated the Legacy HTTP API (server key). All new integrations must use HTTP v1 API with OAuth 2.0 authorization via a Service Account. If your project still uses https://fcm.googleapis.com/fcm/send, it will stop working. The HTTP v1 endpoint is POST https://fcm.googleapis.com/v1/projects/{project_id}/messages:send. Authorization is done with a Bearer token obtained from a Service Account JSON file through the Google Auth Library.

Service Account and Authorization

In Firebase Console → Project Settings → Service Accounts → Generate new private key. Download the JSON file and place it outside the webroot, e.g., /var/www/site/storage/firebase/service-account.json. Obtain the token via JWT. Install the dependency: composer require google/auth. Cache the token — it is valid for 1 hour. Regenerating it on every request is wasteful.

use Google\Auth\Credentials\ServiceAccountCredentials;

class FcmAuthService
{
    private ServiceAccountCredentials $credentials;

    public function __construct(string $serviceAccountPath)
    {
        $this->credentials = new ServiceAccountCredentials(
            'https://www.googleapis.com/auth/firebase.messaging',
            json_decode(file_get_contents($serviceAccountPath), true)
        );
    }

    public function getAccessToken(): string
    {
        $token = $this->credentials->fetchAuthToken();
        return $token['access_token'];
    }

    public function getCachedToken(): string
    {
        $cacheKey = 'fcm_access_token';
        $cached = \Bitrix\Main\Data\Cache::createInstance();
        if ($cached->initCache(3500, $cacheKey, '/fcm/')) {
            return $cached->getVars()['token'];
        }
        $token = $this->getAccessToken();
        $cached->startDataCache();
        $cached->endDataCache(['token' => $token]);
        return $token;
    }
}

For the FCM HTTP v1 API, PHP 8.1 or higher is required. Ensure the curl extension is enabled.

Registering the FCM Token on the Frontend

import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from 'firebase/messaging';

const app = initializeApp({
  apiKey: "...",
  authDomain: "project.firebaseapp.com",
  projectId: "project-id",
  messagingSenderId: "123456789",
  appId: "1:123456789:web:abc"
});

const messaging = getMessaging(app);

async function initPush() {
  try {
    const token = await getToken(messaging, { vapidKey: 'YOUR_VAPID_KEY' });
    if (token) {
      await fetch('/local/api/fcm/register', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Bitrix-Csrf-Token': BX.bitrix_sessid()
        },
        body: JSON.stringify({ fcm_token: token, platform: 'web' })
      });
    }
  } catch (err) {
    console.warn('Push permission denied:', err);
  }
}

onMessage(messaging, (payload) => {
  new Notification(payload.notification.title, {
    body: payload.notification.body,
    icon: '/local/templates/main/images/push-icon.png'
  });
});

For background notifications, you need a Service Worker at /firebase-messaging-sw.js in the site root:

importScripts('https://www.gstatic.com/firebasejs/10.7.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/10.7.0/firebase-messaging-compat.js');

firebase.initializeApp({ /* config */ });
const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
  self.registration.showNotification(payload.notification.title, {
    body: payload.notification.body,
    data: payload.data,
  });
});

Storing and Sending Notifications

Database Table Structure for FCM Tokens

class FcmTokenTable extends \Bitrix\Main\ORM\Data\DataManager
{
    public static function getTableName(): string
    {
        return 'local_fcm_tokens';
    }

    public static function getMap(): array
    {
        return [
            new \Bitrix\Main\ORM\Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
            new \Bitrix\Main\ORM\Fields\IntegerField('USER_ID'),
            new \Bitrix\Main\ORM\Fields\StringField('TOKEN', ['required' => true]),
            new \Bitrix\Main\ORM\Fields\StringField('PLATFORM'), // web, android, ios
            new \Bitrix\Main\ORM\Fields\DatetimeField('CREATED_AT'),
            new \Bitrix\Main\ORM\Fields\DatetimeField('LAST_USED_AT'),
            new \Bitrix\Main\ORM\Fields\StringField('ACTIVE'),
        ];
    }
}

When a token is updated (FCM changes tokens on app reinstall), search by the old token and replace it, rather than duplicating the record.

Sending a Notification

class FcmService {
    private FcmAuthService $auth;
    private string $projectId;

    public function sendToUser(int $userId, string $title, string $body, array $data = []): void {
        $tokens = FcmTokenTable::getList([
            'filter' => ['USER_ID' => $userId, 'ACTIVE' => 'Y'],
            'select' => ['TOKEN', 'PLATFORM'],
        ])->fetchAll();

        foreach ($tokens as $tokenRow) {
            $this->sendToToken($tokenRow['TOKEN'], $title, $body, $data, $tokenRow['PLATFORM']);
        }
    }

    private function sendToToken(string $token, string $title, string $body, array $data, string $platform): void {
        $message = [
            'token' => $token,
            'notification' => ['title' => $title, 'body' => $body],
            'data' => array_map('strval', $data),
        ];

        if ($platform === 'android') {
            $message['android'] = [
                'priority' => 'high',
                'notification' => ['channel_id' => 'orders', 'icon' => 'ic_notification'],
            ];
        } elseif ($platform === 'ios') {
            $message['apns'] = [
                'headers' => ['apns-priority' => '10'],
                'payload' => ['aps' => ['sound' => 'default', 'badge' => 1]],
            ];
        }

        $accessToken = $this->auth->getCachedToken();
        $projectId = $this->projectId;
        $url = "https://fcm.googleapis.com/v1/projects/{$projectId}/messages:send";

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode(['message' => $message]),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                "Authorization: Bearer {$accessToken}",
            ],
        ]);

        $response = json_decode(curl_exec($ch), true);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode === 404 || ($response['error']['code'] ?? 0) === 404) {
            FcmTokenTable::updateByToken($token, ['ACTIVE' => 'N']);
        }
    }
}

Common Problems During FCM Integration

The following errors are frequently encountered during setup:

  • Invalid Service Account: The JSON file is corrupted or has incorrect permissions. Ensure the file is readable by the web server and contains the correct project_id.
  • Stale token: If the client does not refresh the token, notifications stop arriving. Implement token refresh on the client and handle 404 errors on the server.
  • Quota exceeded: FCM has a limit on requests per second. For bulk sends, use topics and add pauses between requests.

Topics vs. Individual Tokens: What to Choose?

FCM supports sending to topics (/topics/promo_electronics) which is convenient for bulk campaigns without storing tokens. Subscription to a topic is done via REST API. For transactional notifications (e.g., a specific user's order), use individual tokens only. Topics are better for promotional blasts, while individual tokens are for personalized alerts.

How to Handle FCM Errors?

Common Error Cause Solution
404 NOT_FOUND Token is stale Deactivate the token in the database
403 Forbidden Invalid Service Account or project Check configuration and permissions
400 InvalidToken Token does not match format Verify that the token was obtained from Firebase SDK

For bulk sends, topics can be used, but individual tokens offer more control and personalization.

Work Process

  1. Analysis — Study the website architecture, define push notification scenarios.
  2. Design — Design the token storage structure, integration with Bitrix events.
  3. Implementation — Set up Service Account, write token registration and sending logic.
  4. Testing — Verify on all platforms (web, Android, iOS), emulate error scenarios.
  5. Deployment — Deploy to production, set up monitoring.

What's Included in the Work

  • Development of a frontend module for FCM token registration.
  • Implementation of a PHP sending service supporting HTTP v1 API with token caching.
  • Creation of a token storage table with ORM mapping.
  • Integration with the 1C-Bitrix event system (order creation, status change).
  • Configuration of a Service Worker for background notifications.
  • Documentation for deployment and maintenance.
  • 30-day warranty on the integration.

Time Estimates

Task Duration
Service Account, FCM HTTP v1 client, token cache 2–3 days
Token registration (web + android/ios) 3–4 days
Event-driven sending (order events) + error handling 2–3 days
Service Worker, foreground/background notifications 2–3 days
Subscription management from user profile, topics 3–5 days
Full package 3–4 weeks

Timeframes are approximate and depend on project complexity. Exact deadlines are determined after an audit.

Get a consultation on implementing FCM in your project. Order a turnkey integration with a 30-day warranty.