Push Notification Configuration
A feature of CP Commerce Admin rather than an applet of its own: you write a notification, pick the website and the topic, and publish it now or schedule it, and the backend sends it through Firebase Cloud Messaging to every device subscribed to that topic. Nothing posts. Three things must line up — a Firebase credential on the website record, which BigLedger support places there; an app build registered with the same Firebase project; and devices subscribed to the topic. A publish that Firebase refused still shows the same success message, so prove a send on a test device, and a scheduled notification goes out only once its scheduled job has been added for your tenant.
Your job, and the screen for it
| The job | Screen or tab | Read |
|---|---|---|
| Send a notification now — save first, then prove it on a test device: the success toast shows even when Firebase refused | CP Commerce Admin › Notification › Create or Edit, Details tab: pick website and topic, then Publish Now | Notification — Create / Details; Lifecycle and effects |
| Schedule a notification for later — only once the scheduler job is on your clock | Notification › Edit › Scheduled tab; add the clock in the Scheduler applet if its picker offers the processor, otherwise ask BigLedger | Lifecycle and effects; Troubleshooting |
| Create a topic and subscribe member segments to it — rename Topic Name freely, not Topic Code | CP Commerce Admin › Topics › Create; Edit › Member Label Link | Topic — Create |
| Let new installs receive notifications without signing in — existing devices keep old subscriptions until they re-register | Website › edit: set Default Topic, leave Restrict Notification by Member unticked | Website settings that control subscriptions |
| Find out why a published notification never arrived | A test device subscribed to the topic; the Firebase reply in the server log, through BigLedger support | Troubleshooting |
| Set up Firebase, the app build and publish permissions — BigLedger support places the credential | Firebase console; the app build; CP Commerce Admin › Settings › Permission Set / Role Permission | Before you can use it |
Overview
Push notifications are a feature of the CP Commerce Admin applet, not a separate applet. A marketing or operations user writes a notification under CP Commerce Admin → Notification, picks the website and the topic it goes to, and presses Publish Now (or schedules it). The backend sends it through Firebase Cloud Messaging (FCM) to every device subscribed to that topic, and the Customer Portal mobile app shows it and opens the linked page when the customer taps it.
Three things have to line up for a notification to arrive: the Website record must carry a Firebase service-account credential, the app build must be registered with the same Firebase project, and the customer’s device must be subscribed to the topic — which the Website’s Default Topic and Restrict Notification by Member settings decide. This page documents all three from the code. The old version of this page reproduced one customer’s Firebase project and build identifiers; those are deliberately absent here.
Where it fits
| Piece | What it does | Where it is configured |
|---|---|---|
| Website record | Holds the Firebase service-account credential, the Default Topic and Restrict Notification by Member flags. | CP Commerce Admin → Website → edit (flags); the credential has no screen — see Configuration. |
| Topics | The channels a device subscribes to. A notification is always sent to one topic. Member labels can auto-subscribe segments. | CP Commerce Admin → Topics. |
| Notification | Title, body, optional post image and deep link, sent to a topic on publish. | CP Commerce Admin → Notification. |
| Scheduler | Fires a saved notification at a date-time. | Notification edit → Scheduled tab. |
| Customer Portal app (built per customer with Capacitor) | Asks for permission, registers with FCM, stores the device token, subscribes to topics, opens the deep link on tap. | The app build (Firebase config files, capacitor.config.ts). |
| Backend | Reads the website credential, talks to FCM (send to topic / device, subscribe / unsubscribe tokens). | Nothing to configure beyond the website credential. |
Upstream: Membership Admin and Customer supply the members and member labels that drive topic subscriptions. Downstream: nothing — a notification writes a read/unread link per subscriber and stops.
Screens and menus
All screens are in CP Commerce Admin (see that page for the full menu):
- Notification → listing, Create, Edit (Details tab with Publish Now; Scheduled tab; Posts sub-listing with Main / Manage Image).
- Topics → listing, Create, Edit (Details; Manage Image; Member Label Link — which member labels auto-subscribe to this topic).
- Website → edit → the Default Topic drop-down and the Restrict Notification by Member checkbox.
The storefront has a second door to the same records. The Webstore Management Dashboard’s
Notification tile (the Website Builder side, under
layout-menu/notifications-listing) opens a Notification Manager that writes the same notification
record through the same endpoint as the console’s Notification screen, so a notification created on either
side appears on both, and Publish Now and the Scheduled tab mean the same thing in both places. The
differences are cosmetic: the tile’s listing is cards with a search box, an active/inactive toggle and a
Scheduled Notifications calendar instead of a table; its create form does not ask for a website (it is
already inside one) and starts with Status ACTIVE; and scheduling is on its edit screen, not its create
form. The topic and post pickers on both forms are look-ups only — they do not create a topic or a post.
So everyone who can open the Website Builder can also send a push notification from it; who those people
are is the User Manager’s business.
Screenshots withdrawn; a recapture on a demo Firebase project is on the list.
Configuration
Before you can use it
- A Firebase project with Cloud Messaging API (V1) enabled, one Android app and one iOS app registered under the package name / bundle ID your app build uses, and — for iOS — an APNs authentication key uploaded under Cloud Messaging → Apple app configuration. Download
google-services.jsonandGoogleService-Info.plistfrom that project. - A service account for that project (Firebase console → Project settings → Service accounts → Generate new private key). The downloaded JSON is what the backend needs — see the next section.
- A Website record in CP Commerce Admin for the storefront, with a code; the mobile app sends this code as the
websiteCodeheader on every call, and the backend uses it to find the credential. - At least one Topic. Topics are tenant-wide, not per website; the website you send with decides which app’s copy of the topic is used. If you want every app install to receive notifications without signing in, also set it as the website’s Default Topic (below).
- CMS notification permissions for the user who publishes — see Feature visibility / permissions.
The Firebase credential on the Website record
BigLedger does not use a Firebase server key or a platform-wide credential for Customer Portal pushes. It uses the service-account JSON stored on the website itself, found by the website code, and requires all eleven service-account fields to be present and non-null:
type, project_id, private_key_id, private_key, client_email, client_id, auth_uri, token_uri, auth_provider_x509_cert_url, client_x509_cert_url, universe_domain
If any is missing or null the call fails with INCORRECT_CONFIGURATION_WEBSITE_CONFIG_FIREBASE. The value is the service-account file pasted verbatim under one key:
{
"firebase": {
"type": "service_account",
"project_id": "<your-firebase-project-id>",
"private_key_id": "…",
"private_key": "-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk-…@<project>.iam.gserviceaccount.com",
"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": "…",
"universe_domain": "googleapis.com"
}
}Two facts about how the credential is used matter operationally:
- The credential is loaded once per tenant + website and then kept. A rotated key takes effect only after BigLedger restarts the service, not immediately — ask for that when you rotate it.
- Each website can point at its own Firebase project. A notification for website A is sent with website A’s credential to topic names prefixed with website A’s code, so an app build registered with project B never receives it.
Website settings that control subscriptions
Set on CP Commerce Admin → Website → edit. They are saved with the website and read by both the admin applet and the mobile app. Anyone with access to the Website edit screen can change them.
| Setting (UI) | What it controls | Default | Effect when changed |
|---|---|---|---|
| Default Topic | The topic every app install subscribes to on first launch, without signing in, when notifications are not restricted to members. | empty — no automatic subscription | New installs subscribe to the new topic; existing devices keep their old subscriptions until they re-register. |
| Restrict Notification by Member | false: the device subscribes to the Default Topic anonymously as soon as it has a token. true: nothing is subscribed until the customer signs in; then the member’s label-linked topics (plus the DEFAULT topic) are restored for the new device token. | unchecked (false) | Existing anonymous subscriptions are not removed by flipping it; they stay until the token is refreshed. |
Note the two different notions of “default topic”: the app subscribes to the website’s Default Topic (above), while restoring a signed-in member’s subscriptions adds the topic whose Description is literally DEFAULT and fails with NO DEFAULT TOPIC IS DEFINED FOR THIS TENANT. KINDLY MAKE SURE 'DEFAULT' TOPIC IS SET. when there is none. Give the same topic both roles.
Topic naming in FCM
The FCM topic a device is subscribed to, and a notification is sent to, is built from the website code, the topic’s internal ID and the topic code. Renaming a topic’s code therefore changes the FCM topic; devices subscribed under the old code stop receiving until they re-subscribe.
App build
The Customer Portal app (Ionic 7 / Angular 19 / Capacitor 5) uses @capacitor/push-notifications 5.1. The base repository ships with placeholder app IDs; each customer build sets its own and adds:
capacitor.config.ts→plugins.PushNotifications.presentationOptions: ["badge", "sound", "alert"](how a foreground notification is shown).android/app/google-services.json— the Android Gradle build applies the Google Services plugin only when this file exists; without it the build succeeds and pushes silently do not work.ios/App/App/GoogleService-Info.plist, plus the Push Notifications and Background Modes → Remote notifications capabilities in Xcode and a provisioning profile that includes push.environment.isApp = true. The base repository hasisApp: falsein every environment file; the effects that subscribe to the Default Topic and restore a member’s subscriptions on a new token run only when this flag is true, so a web build never subscribes anything.
There is no BigLedger applet setting for any of this; the shared Application Settings screen of CP Commerce Admin has no notification keys.
Feature visibility / permissions
Notifications need API_TNT_DM_CMS_NOTIFICATION_OWNER / _ADMIN or the targeted API_TNT_DM_CMS_NOTIFICATION_CREATE (create, publish, initialise processors), _UPDATE, _DELETE, _READ. Assign them through CP Commerce Admin → Settings → Permission Set / Role Permission. The app’s own subscription calls need no permission: they are made for the website, not for a user, so there is nothing to grant on the app side.
Fields
Notification — Create / Details
Title becomes the notification’s heading and Description its body, exactly as typed; Description is optional, so a title-only notification is allowed.
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Select Website | The website whose Firebase credential sends this push, and whose code starts the FCM topic name. | Yes | Not saved with the notification. Reopen a notification and the box is empty, and the link choices stay hidden until you pick a website again — so you choose the website afresh on every send, and nothing stops two sends of one notification going to two websites’ apps. It does not filter the Topic list. |
| Select Topic | The topic the message is sent to. | Yes | The list is every topic in the tenant — topics belong to no website. The same topic sent under two websites is two different FCM topics, because the website code is part of the name. The backend rejects a topic that no longer exists. |
| Status | Record status. | Yes | Nothing reads it when sending. Neither Publish Now nor the scheduler checks it, so an INACTIVE notification still goes out; it is a label for your own listing, not a switch. |
| Link Type | What a tap opens: a layout instance (page), a post, or an external URL. | No | Drives the read-only Deeplink URL. For an external link, what you type in External URL (up to 255 characters) is copied into Deeplink URL as it stands — nothing checks it is a working address, so open it yourself before you publish. |
| Layout Instance + Query Parameters | Page of the website to open, with optional query values. | No | Shown for the layout link type. |
| Select Post | CMS post to link; its first image becomes the notification image. | No | The image is sent as the post image’s public link. |
| Deeplink URL | Computed from the choices above. | — | Read-only; sent with the notification as deeplink_url. |
| Publish Now (button) | Sends immediately. | — | Disabled while the form is invalid; toast “Please select webite before publishing!” when no website is selected. It sends the last saved version, fetched afresh from the server — a title or body you changed and did not SAVE is not what goes out. |
Notification — Scheduled tab
Code is an optional label for the schedule; the server uses it only to name the schedule in its own log when the notification behind it has been deleted.
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Website | Website whose credential and code the scheduler will use. | Yes | This is the only website a notification ever keeps — stored on the schedule, not on the notification. It can differ from the one you last picked on Details, so a scheduled send and a Publish Now of the same notification can reach different apps. |
| Scheduled Datetime | When to send. | Yes | Stored as next_execution_date. The backend supports recurring schedules (is_recurring + rrule), but the applet form exposes only a single date-time. |
Topic — Create
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Topic Code | Part of the FCM topic name. | Yes | Changing it later changes the FCM topic (see Topic naming). |
| Topic Name | The name people see. | Yes | Safe to rename: it is not part of the FCM topic name, unlike Topic Code, so subscribed devices are unaffected. |
| Status | Record status. | Yes | Sending does not check it: a notification published to an INACTIVE topic still goes to every device subscribed to it. To stop a topic receiving, stop sending to it. |
| Description | Free text — set to exactly DEFAULT on the topic the backend should treat as the member default. | No | See Website settings. |
Lifecycle and effects
Push notifications are not documents: nothing posts, no stock or GL is touched. What happens on each action:
Publish Now needs a website (without one: Kindly Provide the appropriate websiteCode). It marks the notification published, loads the website credential, loads the topic (refused if it is gone), builds the message (title, body, first post image, deep link) and sends it to the topic. It then adds one read/unread entry per subscriber of the topic — this is what the app’s in-app notification list shows.
A Firebase refusal does not fail the publish. The error comes back as a message in the reply instead, so the read/unread entries are created even when Firebase rejected the send. The admin screen does not show that message: its toast is the fixed text The notification has been published successfully whatever Firebase said, and the notification is marked sent. So the screen cannot tell you a send worked — prove it on a test device subscribed to the topic, and if nothing arrives, ask BigLedger support for the reply in the server log.
Scheduled → a schedule on the notification. The scheduled job NOTIFICATION_SCHEDULER_PROCESSOR picks every schedule that is due and not deleted, publishes exactly as above using the schedule’s website, then either moves the next run on by the recurrence rule (recurring) or ends the schedule (one-off). A schedule whose notification has been deleted is skipped.
Check that the job is scheduled before you schedule anything. NOTIFICATION_SCHEDULER_PROCESSOR is not in the default set of scheduled jobs a new tenant is given, so it has to be added deliberately in the Scheduler Applet. Assume you do not have it until you have looked. Without it a scheduled notification saves correctly, shows a future Scheduled Datetime, and is never sent — no error, no status change, nothing on the screen that would tell you. If you need scheduled sends, get the job scheduled first and send one test notification dated a few minutes out to prove it.
Device side (app builds only): on start the app checks permission, prompts, registers for push and keeps the device token on the device — across logout too. Then, if Restrict Notification by Member is false and a Default Topic is set and not yet subscribed, it subscribes the device to that topic without anyone signing in. On sign-in (or when restricted) it restores the member’s subscriptions for this device: the member’s outdated device tokens are unsubscribed and removed, and the member’s label-linked topics plus the DEFAULT topic are subscribed under the new token. Unsubscribing a topic in the app removes that subscription.
Tap on a notification → if it carries a deep link the app navigates to it; otherwise it just opens.
Member Label Link on a topic → subscribes every member carrying that label (with a stored device token) to the topic; removing the link unsubscribes them.
Related applets
- CP Commerce Admin — the applet this feature belongs to; Website, Topics and Notification menus.
- Membership Admin — member classes and labels that the Topic → Member Label Link uses to build segments.
- Customer — the customer / member records that carry the labels.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Publish (or any subscribe call) fails with INCORRECT_CONFIGURATION_WEBSITE_CONFIG_FIREBASE | The website’s Firebase credential is missing, or one of the eleven service-account keys is absent or null (a common one is universe_domain, missing from older service-account downloads). | Send support the complete, current service-account JSON and ask them to update the website. |
Kindly Provide the appropriate websiteCode / toast Please select webite before publishing! | Publish was requested without a website. | Select the website on the notification, save, publish again. |
| Publish refused because the topic no longer exists | The topic was deleted after the notification was created. | Re-select a live topic. |
| Publish shows published successfully but nobody receives anything | The Firebase error comes back as a message, not as a failure, and the screen shows a fixed success toast instead of it. Typical causes: credential for the wrong project, Cloud Messaging API not enabled, service account without the Firebase Cloud Messaging API role. | Ask support for the Firebase reply (it is in the server log); fix the Firebase project or credential. |
| Devices of one app get a notification, another app’s devices do not | The website picked at send time decides which app’s topic is used, and it is picked afresh on every send — the notification does not remember it. | Check which website you chose; send again with the other. |
| Devices never subscribe to the Default Topic | Either the Website has no Default Topic, Restrict Notification by Member is true, or the build is not an app build (environment.isApp false) — the subscription effects are gated on all three. | Set the Default Topic, untick the restriction (or accept members-only), confirm the app build’s environment file. |
NO DEFAULT TOPIC IS DEFINED FOR THIS TENANT. KINDLY MAKE SURE 'DEFAULT' TOPIC IS SET. on sign-in / device restore | No topic has Description exactly DEFAULT; restoring a member’s subscriptions looks at the topic description, not the website’s Default Topic. | Set the description of the default topic to DEFAULT. |
TOPIC_MANAGEMENT_RESPONSE_ERROR when subscribing | FCM refused the token: stale/invalid token, or the token was issued by an app registered under a different Firebase project than the website credential. | Reinstall or re-register the app; make sure the build’s google-services.json / GoogleService-Info.plist come from the same project as the website credential. |
| Rotated the service-account key but the old one is still used | The credential is loaded once per tenant + website and kept until the service restarts. | Ask BigLedger support to restart the service after changing the credential. |
Android: no token, google-services.json not found, Push Notifications won't work in the build log | The file is not at android/app/google-services.json, or the package name differs from the one registered in Firebase. | Place the file; match the package name. Test on a physical device — emulators without Google Play services get no token. |
| iOS: no token / notifications never arrive | No APNs authentication key uploaded in Firebase Cloud Messaging, missing Push Notifications / Background Modes capability, or a provisioning profile without push. | Upload the APNs key, add the capabilities, rebuild with a push-enabled profile; test on a physical device. |
| Notifications stop after a topic code was changed | The FCM topic name embeds the topic code. | Have devices re-subscribe (new token or re-login), or revert the code. |
| Scheduled notification did not go out at the exact minute | The notification scheduler runs on your tenant’s clock and sends everything that has fallen due since its last run. | Expect a delay of up to one clock interval; check that the scheduler row is not DELETED and its notification still exists. |
| Scheduled notification never went out at all | The notification scheduler is probably not on your tenant’s clock — it is not part of the default set a tenant is created with. | In the Scheduler applet, add a clock for NOTIFICATION_SCHEDULER_PROCESSOR if its Select Processor picker offers it; otherwise ask BigLedger. Until it exists, use Publish Now rather than the Scheduled tab. |
Related documentation
- CP Commerce Admin — Notification, Topics, Website settings, permissions.
- E-Commerce module
- Capacitor Push Notifications plugin and Firebase Cloud Messaging — vendor documentation for the native side.