Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    Documentation

    Welcome — mission & audiences

    Welcome to Ring Platform - Gateway Between Humanity and the Quantum World

    Library hub

    Welcome to Ring Platform - Gateway Between Humanity and the Quantum World

    Getting Started

    Index
    Prerequisites
    Installation
    Database migrations
    First Success Validation
    Troubleshooting
    Next Steps

    Architecture

    Index
    Backend modes and databases
    Data Model
    Authentication Architecture
    Email AI-CRM Architecture
    PaymentConductor architecture
    News Kingdom architecture
    Proxy and internationalization
    Real Time
    Security

    Features

    Platform Features
    Authentication
    Email AI-CRM System
    Entities
    Opportunities
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Web3 Wallet
    Multi-Vendor Store
    Payment Integration
    PaymentConductor
    WayForPay Payment Integration
    News Module - Digital Newspaper Experience

    API

    Index
    Authentication
    Email AI-CRM API
    Entities
    Opportunities
    Messaging API
    Notifications API
    Wallet
    Store API

    CLI

    Ring CLI (enterprise only)

    Customization

    Index
    Branding
    Features
    Localization
    Themes
    Components

    Deployment

    Index
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery

    Development

    Index
    Local Setup
    Code Structure
    Community tooling
    Ring MCP Server
    OSS vs enterprise
    Whitelabel Navigation
    Best Practices

    Examples

    Index
    Quick Start
    Authentication
    Email AI-CRM Tutorial
    Api Integration
    Web3 Integration
    White Label
    Real World

    Integrations

    Ethereum wallets (Wagmi v3)

    Quick entry (CTOs · auditors · agents)

    Library hub
    Welcome — mission & audiences
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP
    Deploy (Docker · k8s)
    Security & compliance reads
    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    Documentation

    Welcome — mission & audiences

    Welcome to Ring Platform - Gateway Between Humanity and the Quantum World

    Library hub

    Welcome to Ring Platform - Gateway Between Humanity and the Quantum World

    Getting Started

    Index
    Prerequisites
    Installation
    Database migrations
    First Success Validation
    Troubleshooting
    Next Steps

    Architecture

    Index
    Backend modes and databases
    Data Model
    Authentication Architecture
    Email AI-CRM Architecture
    PaymentConductor architecture
    News Kingdom architecture
    Proxy and internationalization

    Features

    Platform Features
    Authentication
    Email AI-CRM System
    Entities
    Opportunities
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Web3 Wallet

    API

    Index
    Authentication
    Email AI-CRM API
    Entities
    Opportunities
    Messaging API
    Notifications API
    Wallet
    Store API

    CLI

    Ring CLI (enterprise only)

    Customization

    Index
    Branding
    Features
    Localization
    Themes
    Components

    Deployment

    Index
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery

    Development

    Index
    Local Setup
    Code Structure
    Community tooling
    Ring MCP Server
    OSS vs enterprise
    Whitelabel Navigation
    Best Practices

    Examples

    Index
    Quick Start
    Authentication
    Email AI-CRM Tutorial
    Api Integration
    Web3 Integration
    White Label
    Real World

    Integrations

    Ethereum wallets (Wagmi v3)

    Quick entry (CTOs · auditors · agents)

    Library hub
    Welcome — mission & audiences
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP
    Deploy (Docker · k8s)
    Security & compliance reads
    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    Documentation

    Welcome — mission & audiences

    Welcome to Ring Platform - Gateway Between Humanity and the Quantum World

    Library hub

    Welcome to Ring Platform - Gateway Between Humanity and the Quantum World

    Getting Started

    Index
    Prerequisites
    Installation
    Database migrations
    First Success Validation
    Troubleshooting
    Next Steps

    Architecture

    Index
    Backend modes and databases
    Data Model
    Authentication Architecture
    Email AI-CRM Architecture
    PaymentConductor architecture
    News Kingdom architecture
    Proxy and internationalization

    Features

    Platform Features
    Authentication
    Email AI-CRM System
    Entities
    Opportunities
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Web3 Wallet

    API

    Index
    Authentication
    Email AI-CRM API
    Entities
    Opportunities
    Messaging API
    Notifications API
    Wallet
    Store API

    CLI

    Ring CLI (enterprise only)

    Customization

    Index
    Branding
    Features
    Localization
    Themes
    Components

    Deployment

    Index
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery

    Development

    Index
    Local Setup
    Code Structure
    Community tooling
    Ring MCP Server
    OSS vs enterprise
    Whitelabel Navigation
    Best Practices

    Examples

    Index
    Quick Start
    Authentication
    Email AI-CRM Tutorial
    Api Integration
    Web3 Integration
    White Label
    Real World

    Integrations

    Ethereum wallets (Wagmi v3)

    Quick entry (CTOs · auditors · agents)

    Library hub
    Welcome — mission & audiences
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP
    Deploy (Docker · k8s)
    Security & compliance reads
    Member Blogs
    Scientific Editor
    Locale System
    Security & Compliance
    NFT Marketplace
    Token Staking System
    Performance Optimization Patterns
    Mobile Experience
    Admin API
    Workflow
    Code Style
    Performance
    Testing
    Deployment
    Debugging
    Contributing
    Api Examples
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)
    Real Time
    Security
    Multi-Vendor Store
    Payment Integration
    PaymentConductor
    WayForPay Payment Integration
    News Module - Digital Newspaper Experience
    Member Blogs
    Scientific Editor
    Locale System
    Security & Compliance
    NFT Marketplace
    Token Staking System
    Performance Optimization Patterns
    Mobile Experience
    Admin API
    Workflow
    Code Style
    Performance
    Testing
    Deployment
    Debugging
    Contributing
    Api Examples
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)
    Real Time
    Security
    Multi-Vendor Store
    Payment Integration
    PaymentConductor
    WayForPay Payment Integration
    News Module - Digital Newspaper Experience
    Member Blogs
    Scientific Editor
    Locale System
    Security & Compliance
    NFT Marketplace
    Token Staking System
    Performance Optimization Patterns
    Mobile Experience
    Admin API
    Workflow
    Code Style
    Performance
    Testing
    Deployment
    Debugging
    Contributing
    Api Examples
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)

    Push Notifications with FCM (Ring-Powered)

    Ring Platform stores FCM tokens in your primary database (PostgreSQL or Firestore by backend mode), one row per user per device. React apps register tokens via a Server Action; non-React clients use a rate-limited API. Both paths call the same server-only DB layer so behavior and security stay consistent everywhere. How modes differ (Postgres-primary vs full Firebase, DB_HYBRID_MODE): Backend modes and databases.

    Overview: Ring-Powered FCM Logic

    "Ring-powered" FCM means a single, backend-agnostic design:

    • Token store as source of truth — The fcm_tokens table (or collection) holds all registration tokens. Stored payload lives in a JSONB data column where applicable (PostgreSQL). No secondary cache; the database is the registry.
    • One row per device per user — A composite unique constraint on (user_id, device_fingerprint) ensures one record per device. The token value is not unique, so FCM token rotation updates the same row instead of creating duplicates.
    • React app → Server Action — The primary path for browser and React Native web is the upsertFcmToken Server Action. The server derives user_id from auth() only; the client never sends it.
    • Non-React clients → API route — Mobile apps or external services call POST /api/notifications/fcm/register with the same payload. This endpoint is rate-limited per user (for example, 10 requests per minute).
    • Lifecycle in data — Each row carries status (active | stale | invalid) and invalidatedAt. Reactive cleanup runs when FCM returns errors for a token; scheduled jobs mark stale tokens and optionally hard-delete after a retention window.
    • Backend mode — The token store is backend-agnostic. BackendSelector routes by DB_BACKEND_MODE to PostgreSQL (e.g. k8s-postgres-fcm, ) or Firestore (). One code path; no branching in the Server Action or API route.

    Push Notifications with FCM (Ring-Powered)

    Ring Platform stores FCM tokens in your primary database (PostgreSQL or Firestore by backend mode), one row per user per device. React apps register tokens via a Server Action; non-React clients use a rate-limited API. Both paths call the same server-only DB layer so behavior and security stay consistent everywhere. How modes differ (Postgres-primary vs full Firebase, DB_HYBRID_MODE): Backend modes and databases.

    Overview: Ring-Powered FCM Logic

    "Ring-powered" FCM means a single, backend-agnostic design:

    • Token store as source of truth — The fcm_tokens table (or collection) holds all registration tokens. Stored payload lives in a JSONB data column where applicable (PostgreSQL). No secondary cache; the database is the registry.
    • One row per device per user — A composite unique constraint on (user_id, device_fingerprint) ensures one record per device. The token value is not unique, so FCM token rotation updates the same row instead of creating duplicates.
    • React app → Server Action — The primary path for browser and React Native web is the upsertFcmToken Server Action. The server derives user_id from auth() only; the client never sends it.
    • Non-React clients → API route — Mobile apps or external services call POST /api/notifications/fcm/register with the same payload. This endpoint is rate-limited per user (for example, 10 requests per minute).
    • Lifecycle in data — Each row carries status (active | stale | invalid) and invalidatedAt. Reactive cleanup runs when FCM returns errors for a token; scheduled jobs mark stale tokens and optionally hard-delete after a retention window.
    • Backend mode — The token store is backend-agnostic. BackendSelector routes by DB_BACKEND_MODE to PostgreSQL (e.g. k8s-postgres-fcm, ) or Firestore (). One code path; no branching in the Server Action or API route.

    Push Notifications with FCM (Ring-Powered)

    Ring Platform stores FCM tokens in your primary database (PostgreSQL or Firestore by backend mode), one row per user per device. React apps register tokens via a Server Action; non-React clients use a rate-limited API. Both paths call the same server-only DB layer so behavior and security stay consistent everywhere. How modes differ (Postgres-primary vs full Firebase, DB_HYBRID_MODE): Backend modes and databases.

    Overview: Ring-Powered FCM Logic

    "Ring-powered" FCM means a single, backend-agnostic design:

    • Token store as source of truth — The fcm_tokens table (or collection) holds all registration tokens. Stored payload lives in a JSONB data column where applicable (PostgreSQL). No secondary cache; the database is the registry.
    • One row per device per user — A composite unique constraint on (user_id, device_fingerprint) ensures one record per device. The token value is not unique, so FCM token rotation updates the same row instead of creating duplicates.
    • React app → Server Action — The primary path for browser and React Native web is the upsertFcmToken Server Action. The server derives user_id from auth() only; the client never sends it.
    • Non-React clients → API route — Mobile apps or external services call POST /api/notifications/fcm/register with the same payload. This endpoint is rate-limited per user (for example, 10 requests per minute).
    • Lifecycle in data — Each row carries status (active | stale | invalid) and invalidatedAt. Reactive cleanup runs when FCM returns errors for a token; scheduled jobs mark stale tokens and optionally hard-delete after a retention window.
    • Backend mode — The token store is backend-agnostic. BackendSelector routes by DB_BACKEND_MODE to PostgreSQL (e.g. k8s-postgres-fcm, ) or Firestore (). One code path; no branching in the Server Action or API route.
    supabase-fcm
    firebase-full
    Ring-powered FCM registration and delivery

    Prerequisites

    • Authentication — A signed-in user (Auth.js session). Token registration is always tied to the authenticated user; the server never trusts a client-supplied user id.
    • Web push (browser) — HTTPS (or localhost for development), browser support for Web Push, a registered service worker, and the Firebase client SDK. The service worker file is typically served at /firebase-messaging-sw.js.
    • API clients — Valid session (cookie or Bearer) and the same request body contract as below (token, deviceFingerprint, deviceInfo).

    React App: Server Action Path

    Use the Server Action as the primary way to register and refresh FCM tokens from any React or Next.js client. This path is not rate-limited like the API route and keeps user id server-derived only.

    Primary path

    React apps should use the Server Action as the primary path. The API route is for non-React clients and is rate-limited.

    supabase-fcm
    firebase-full
    Ring-powered FCM registration and delivery

    Prerequisites

    • Authentication — A signed-in user (Auth.js session). Token registration is always tied to the authenticated user; the server never trusts a client-supplied user id.
    • Web push (browser) — HTTPS (or localhost for development), browser support for Web Push, a registered service worker, and the Firebase client SDK. The service worker file is typically served at /firebase-messaging-sw.js.
    • API clients — Valid session (cookie or Bearer) and the same request body contract as below (token, deviceFingerprint, deviceInfo).

    React App: Server Action Path

    Use the Server Action as the primary way to register and refresh FCM tokens from any React or Next.js client. This path is not rate-limited like the API route and keeps user id server-derived only.

    Primary path

    React apps should use the Server Action as the primary path. The API route is for non-React clients and is rate-limited.

    supabase-fcm
    firebase-full
    Ring-powered FCM registration and delivery

    Prerequisites

    • Authentication — A signed-in user (Auth.js session). Token registration is always tied to the authenticated user; the server never trusts a client-supplied user id.
    • Web push (browser) — HTTPS (or localhost for development), browser support for Web Push, a registered service worker, and the Firebase client SDK. The service worker file is typically served at /firebase-messaging-sw.js.
    • API clients — Valid session (cookie or Bearer) and the same request body contract as below (token, deviceFingerprint, deviceInfo).

    React App: Server Action Path

    Use the Server Action as the primary way to register and refresh FCM tokens from any React or Next.js client. This path is not rate-limited like the API route and keeps user id server-derived only.

    Primary path

    React apps should use the Server Action as the primary path. The API route is for non-React clients and is rate-limited.

    1

    Obtain a stable device fingerprint

    Generate or load a stable value (for example, crypto.randomUUID() stored in localStorage) and reuse it on every load and on token refresh. The server uses (user_id, device_fingerprint) to upsert one row per device.

    2

    Request permission and get the FCM token

    In a 'use client' component (for example inside a notification provider), call Notification.requestPermission(). When granted, call getToken(messaging, { vapidKey }) from the Firebase Messaging SDK. Do not call getToken() in Server Components; they have no browser context.

    3

    Call the Server Action to register the token

    Invoke upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Do not pass userId; the server derives it from auth().

    4

    Handle token refresh

    When the Firebase SDK emits a new token (for example via onTokenRefresh), call the same Server Action again with the new token and the same deviceFingerprint. The shared DB layer updates the existing row for that user and device.

    1

    Obtain a stable device fingerprint

    Generate or load a stable value (for example, crypto.randomUUID() stored in localStorage) and reuse it on every load and on token refresh. The server uses (user_id, device_fingerprint) to upsert one row per device.

    2

    Request permission and get the FCM token

    In a 'use client' component (for example inside a notification provider), call Notification.requestPermission(). When granted, call getToken(messaging, { vapidKey }) from the Firebase Messaging SDK. Do not call getToken() in Server Components; they have no browser context.

    3

    Call the Server Action to register the token

    Invoke upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Do not pass userId; the server derives it from auth().

    4

    Handle token refresh

    When the Firebase SDK emits a new token (for example via onTokenRefresh), call the same Server Action again with the new token and the same deviceFingerprint. The shared DB layer updates the existing row for that user and device.

    1

    Obtain a stable device fingerprint

    Generate or load a stable value (for example, crypto.randomUUID() stored in localStorage) and reuse it on every load and on token refresh. The server uses (user_id, device_fingerprint) to upsert one row per device.

    2

    Request permission and get the FCM token

    In a 'use client' component (for example inside a notification provider), call Notification.requestPermission(). When granted, call getToken(messaging, { vapidKey }) from the Firebase Messaging SDK. Do not call getToken() in Server Components; they have no browser context.

    3

    Call the Server Action to register the token

    Invoke upsertFcmToken({ token, deviceFingerprint, deviceInfo, platform: 'web' }). Do not pass userId; the server derives it from auth().

    4

    Handle token refresh

    When the Firebase SDK emits a new token (for example via onTokenRefresh), call the same Server Action again with the new token and the same deviceFingerprint. The shared DB layer updates the existing row for that user and device.

    Example: registering and refreshing the token from a client component.

    Example: register FCM token from a client component
    typescript

    Non-React Clients: API Route

    Mobile apps or other non-React clients register tokens by calling the same contract over HTTP.

    Endpoint: POST /api/notifications/fcm/register

    Request body:

    • token (string, required) — FCM registration token from the client SDK.
    • deviceFingerprint (string, required) — Stable device identifier (e.g. UUID in local storage). Maximum 128 characters; alphanumeric, hyphens, and underscores only.
    • deviceInfo (object, optional) — Arbitrary device metadata (e.g. platform, userAgent).

    Authentication: Required (session cookie or Bearer token). The server uses the authenticated user id; do not send userId in the body.

    Responses:

    • 200 — { "success": true }
    • 400 — Validation error (e.g. missing or invalid deviceFingerprint)
    • 401 — Not authenticated
    • 429 — Rate limit exceeded (see Retry-After header)
    • 500 — Server error
    Rate limit

    This endpoint is rate-limited per user (e.g. 10 requests per minute). Use the Server Action from React apps to avoid consuming the API rate limit.

    Example with cURL (replace session cookie or use Bearer token as required by your auth setup):

    Example: register token via API
    bash

    Example: registering and refreshing the token from a client component.

    Example: register FCM token from a client component
    typescript

    Non-React Clients: API Route

    Mobile apps or other non-React clients register tokens by calling the same contract over HTTP.

    Endpoint: POST /api/notifications/fcm/register

    Request body:

    • token (string, required) — FCM registration token from the client SDK.
    • deviceFingerprint (string, required) — Stable device identifier (e.g. UUID in local storage). Maximum 128 characters; alphanumeric, hyphens, and underscores only.
    • deviceInfo (object, optional) — Arbitrary device metadata (e.g. platform, userAgent).

    Authentication: Required (session cookie or Bearer token). The server uses the authenticated user id; do not send userId in the body.

    Responses:

    • 200 — { "success": true }
    • 400 — Validation error (e.g. missing or invalid deviceFingerprint)
    • 401 — Not authenticated
    • 429 — Rate limit exceeded (see Retry-After header)
    • 500 — Server error
    Rate limit

    This endpoint is rate-limited per user (e.g. 10 requests per minute). Use the Server Action from React apps to avoid consuming the API rate limit.

    Example with cURL (replace session cookie or use Bearer token as required by your auth setup):

    Example: register token via API
    bash

    Example: registering and refreshing the token from a client component.

    Example: register FCM token from a client component
    typescript

    Non-React Clients: API Route

    Mobile apps or other non-React clients register tokens by calling the same contract over HTTP.

    Endpoint: POST /api/notifications/fcm/register

    Request body:

    • token (string, required) — FCM registration token from the client SDK.
    • deviceFingerprint (string, required) — Stable device identifier (e.g. UUID in local storage). Maximum 128 characters; alphanumeric, hyphens, and underscores only.
    • deviceInfo (object, optional) — Arbitrary device metadata (e.g. platform, userAgent).

    Authentication: Required (session cookie or Bearer token). The server uses the authenticated user id; do not send userId in the body.

    Responses:

    • 200 — { "success": true }
    • 400 — Validation error (e.g. missing or invalid deviceFingerprint)
    • 401 — Not authenticated
    • 429 — Rate limit exceeded (see Retry-After header)
    • 500 — Server error
    Rate limit

    This endpoint is rate-limited per user (e.g. 10 requests per minute). Use the Server Action from React apps to avoid consuming the API rate limit.

    Example with cURL (replace session cookie or use Bearer token as required by your auth setup):

    Example: register token via API
    bash

    Environment Variables

    Split configuration so that only public, safe values are exposed to the client.

    Security

    VAPID private key and Firebase service account credentials must never be exposed to the client. Keep them server-only.

    Environment Variables

    Split configuration so that only public, safe values are exposed to the client.

    Security

    VAPID private key and Firebase service account credentials must never be exposed to the client. Keep them server-only.

    Environment Variables

    Split configuration so that only public, safe values are exposed to the client.

    Security

    VAPID private key and Firebase service account credentials must never be exposed to the client. Keep them server-only.

    PurposeVariablesWhere
    Client (browser / app)NEXT_PUBLIC_FIREBASE_API_KEY, NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, NEXT_PUBLIC_FIREBASE_PROJECT_ID, NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, NEXT_PUBLIC_FIREBASE_APP_ID, NEXT_PUBLIC_FIREBASE_VAPID_KEYClient-safe; used by Firebase client SDK and service worker
    Server (token store, FCM send)FIREBASE_SERVICE_ACCOUNT_* or equivalent service account JSON path; DB_BACKEND_MODE (e.g. k8s-postgres-fcm, firebase-full, supabase-fcm)Server-only; used by BackendSelector and Firebase Admin SDK
    PurposeVariablesWhere
    Client (browser / app)NEXT_PUBLIC_FIREBASE_API_KEY, NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, NEXT_PUBLIC_FIREBASE_PROJECT_ID, NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, NEXT_PUBLIC_FIREBASE_APP_ID, NEXT_PUBLIC_FIREBASE_VAPID_KEYClient-safe; used by Firebase client SDK and service worker
    Server (token store, FCM send)FIREBASE_SERVICE_ACCOUNT_* or equivalent service account JSON path; DB_BACKEND_MODE (e.g. k8s-postgres-fcm, firebase-full, supabase-fcm)Server-only; used by BackendSelector and Firebase Admin SDK
    PurposeVariablesWhere
    Client (browser / app)NEXT_PUBLIC_FIREBASE_API_KEY, NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, NEXT_PUBLIC_FIREBASE_PROJECT_ID, NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, NEXT_PUBLIC_FIREBASE_APP_ID, NEXT_PUBLIC_FIREBASE_VAPID_KEYClient-safe; used by Firebase client SDK and service worker
    Server (token store, FCM send)FIREBASE_SERVICE_ACCOUNT_* or equivalent service account JSON path; DB_BACKEND_MODE (e.g. k8s-postgres-fcm, firebase-full, supabase-fcm)Server-only; used by BackendSelector and Firebase Admin SDK

    Unregister and Logout

    On logout or when the user disables push:

    • Browser / React — Call deleteToken(messaging) from the Firebase client SDK, then unregister on the server. Send DELETE /api/notifications/fcm/register with body { "deviceFingerprint": "same-uuid-as-register" }. Idempotent; safe to call even if the row is already removed or invalidated.
    • Non-React — Same DELETE request with the same deviceFingerprint used at registration.

    The server marks the row as status: 'invalid' and sets invalidatedAt; delivery to that token is stopped.

    Troubleshooting

    Unregister and Logout

    On logout or when the user disables push:

    • Browser / React — Call deleteToken(messaging) from the Firebase client SDK, then unregister on the server. Send DELETE /api/notifications/fcm/register with body { "deviceFingerprint": "same-uuid-as-register" }. Idempotent; safe to call even if the row is already removed or invalidated.
    • Non-React — Same DELETE request with the same deviceFingerprint used at registration.

    The server marks the row as status: 'invalid' and sets invalidatedAt; delivery to that token is stopped.

    Troubleshooting

    Unregister and Logout

    On logout or when the user disables push:

    • Browser / React — Call deleteToken(messaging) from the Firebase client SDK, then unregister on the server. Send DELETE /api/notifications/fcm/register with body { "deviceFingerprint": "same-uuid-as-register" }. Idempotent; safe to call even if the row is already removed or invalidated.
    • Non-React — Same DELETE request with the same deviceFingerprint used at registration.

    The server marks the row as status: 'invalid' and sets invalidatedAt; delivery to that token is stopped.

    Troubleshooting

    IssueCauseWhat to do
    Permission denied or token not receivedUser denied notification permission or permission not yet requestedRequest permission before calling getToken(); handle permission === 'denied' in the UI
    429 on registerRate limit exceededUse the Server Action from React apps; for API clients, respect Retry-After and reduce register frequency
    Invalid deviceFingerprintValidation failureUse a string of length 1–128 with only letters, numbers, hyphens, and underscores
    401 on registerNot authenticatedEnsure a valid session (cookie or Bearer) is sent; do not send userId in the body
    IssueCauseWhat to do
    Permission denied or token not receivedUser denied notification permission or permission not yet requestedRequest permission before calling getToken(); handle permission === 'denied' in the UI
    429 on registerRate limit exceededUse the Server Action from React apps; for API clients, respect Retry-After and reduce register frequency
    Invalid deviceFingerprintValidation failureUse a string of length 1–128 with only letters, numbers, hyphens, and underscores
    401 on registerNot authenticatedEnsure a valid session (cookie or Bearer) is sent; do not send userId in the body
    IssueCauseWhat to do
    Permission denied or token not receivedUser denied notification permission or permission not yet requestedRequest permission before calling getToken(); handle permission === 'denied' in the UI
    429 on registerRate limit exceededUse the Server Action from React apps; for API clients, respect Retry-After and reduce register frequency
    Invalid deviceFingerprintValidation failureUse a string of length 1–128 with only letters, numbers, hyphens, and underscores
    401 on registerNot authenticatedEnsure a valid session (cookie or Bearer) is sent; do not send userId in the body

    See Also

    • Notifications — Overview of notification types, channels, and preferences
    • Schema and migration for fcm_tokens (e.g. data/schema.sql, data/migrations/fcm_jsonb_schema.sql) in your Ring clone
    • FCM specialist truth lens (AI-LEGIOX/legiox-truth-lens/fcm-specialist.json) for token lifecycle, reactive cleanup, and send path details

    See Also

    • Notifications — Overview of notification types, channels, and preferences
    • Schema and migration for fcm_tokens (e.g. data/schema.sql, data/migrations/fcm_jsonb_schema.sql) in your Ring clone
    • FCM specialist truth lens (AI-LEGIOX/legiox-truth-lens/fcm-specialist.json) for token lifecycle, reactive cleanup, and send path details

    See Also

    • Notifications — Overview of notification types, channels, and preferences
    • Schema and migration for fcm_tokens (e.g. data/schema.sql, data/migrations/fcm_jsonb_schema.sql) in your Ring clone
    • FCM specialist truth lens (AI-LEGIOX/legiox-truth-lens/fcm-specialist.json) for token lifecycle, reactive cleanup, and send path details