Abrova
☰ Docs menu · Notification settings
Coming soon. Abrova Chat is coming soon. This page describes how it will work; it can’t be used yet.

Notification Settings

Let each user choose which chat push notifications they get — turn chat pushes off, only on mentions, mute a room for a while, or turn off single event types. Node.js and REST.

Last updated: 27 Oct 2026

AbrovaChat sends a push to participants who are offline when something happens in their rooms (see Push Setup). Some users want every one of them, others want none. Notification settings let each user decide, and you expose the choice in your own app's settings screen.

Nothing changes until you set something.

A user without settings gets every push, exactly as before. Your project-wide push configuration still applies on top: a push the project doesn't send is never sent, whatever the user chooses.

What a user can choose#

Settings exist at two levels. A push is sent only if both allow it.

LevelUse it for
App-wide"Chat notifications" switch in your app settings
Per room"Mute this conversation", "Only notify me when mentioned"

Each level has the same three fields:

OptionTypeRequiredDescription
pushLevel'all' | 'mentions' | 'none''all'`all` — every chat push. `mentions` — only when the user is @mentioned. `none` — no chat pushes.
mutedUntilISO date | nullnullNo chat pushes until this time, then back to normal. Send `null` to unmute early.
disabledEventsstring[][]Event types to turn off, e.g. `["reaction", "message_pinned"]`.

Event types you can turn off:

OptionTypeRequiredDescription
new_message--New text message
file_shared--Image or file message
mention--The user was @mentioned
reaction--Someone reacted to the user's message
message_pinned--A message was pinned
room_created--The user was put in a new room
participant_joined--Someone joined the room
participant_removed--Someone left or was removed

Settings only affect push notifications. Messages, realtime events and unread counts are unchanged.

Keep your server secret on your server, and let your app talk to your backend:

Your app  ──(your login)──▶  Your backend  ──(API key + server secret)──▶  AbrovaChat

Your backend already knows who the signed-in user is, so it passes that user's id to AbrovaChat. The app never chooses whose settings it changes, and never holds the secret.

Your backend (Node.js)#

Install the server SDK from Abrova Center (the .npmrc line points the @abrova scope there):

bash
# .npmrc
@abrova:registry=https://center.abrova.ir/api/packages/abrova/npm/
bash
npm install @abrova/chat@^0.2.0
typescript
import express from 'express';
import { AbrovaChat, AbrovaChatError } from '@abrova/chat';

const chat = new AbrovaChat({
  apiKey: process.env.ABROVA_API_KEY!,
  serverSecret: process.env.ABROVA_SERVER_SECRET!, // server-side only
});

const router = express.Router();
// requireLogin is YOUR auth middleware; req.user.id is YOUR user id,
// the same id you use as externalUserId in chat rooms.

// App-wide settings
router.get('/chat/notification-settings', requireLogin, async (req, res) => {
  res.json(await chat.users.getNotificationSettings(req.user.id));
});

router.put('/chat/notification-settings', requireLogin, async (req, res) => {
  const { pushLevel, mutedUntil, disabledEvents } = req.body;
  res.json(
    await chat.users.updateNotificationSettings(req.user.id, { pushLevel, mutedUntil, disabledEvents }),
  );
});

// One room
router.put('/chat/rooms/:roomId/notification-settings', requireLogin, async (req, res) => {
  const { pushLevel, mutedUntil, disabledEvents } = req.body;
  try {
    res.json(
      await chat.rooms.updateNotificationSettings(req.params.roomId, req.user.id, {
        pushLevel,
        mutedUntil,
        disabledEvents,
      }),
    );
  } catch (e) {
    if (e instanceof AbrovaChatError) return res.status(e.statusCode).json({ message: e.message });
    throw e;
  }
});

Only pass on the three fields shown. Never take the user id from the request body — use the id from your own session.

Common calls:

typescript
// Chat notifications off
await chat.users.updateNotificationSettings(userId, { pushLevel: 'none' });

// Back on
await chat.users.updateNotificationSettings(userId, { pushLevel: 'all' });

// Only when mentioned, and never for reactions
await chat.users.updateNotificationSettings(userId, {
  pushLevel: 'mentions',
  disabledEvents: ['reaction'],
});

// Mute one room for 8 hours, or unmute it
await chat.rooms.updateNotificationSettings(roomId, userId, {
  mutedUntil: new Date(Date.now() + 8 * 60 * 60 * 1000),
});
await chat.rooms.updateNotificationSettings(roomId, userId, { mutedUntil: null });

Updates are partial: fields you leave out keep their current value.

Your app#

The app calls your backend like any other request of yours. For example, a settings switch:

typescript
async function setChatNotifications(enabled: boolean) {
  await fetch('https://api.example.com/chat/notification-settings', {
    method: 'PUT',
    headers: { Authorization: `Bearer ${sessionToken}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ pushLevel: enabled ? 'all' : 'none' }),
  });
}
dart
// Flutter
Future<void> muteRoom(String roomId, Duration duration) => dio.put(
  '/chat/rooms/$roomId/notification-settings',
  data: {'mutedUntil': DateTime.now().add(duration).toUtc().toIso8601String()},
);

REST reference#

All endpoints take x-api-key, plus either x-server-secret (your server, acting for any user) or x-user-token (a user token, acting only for that user).

MethodPathPurpose
GET/api/v1/users/notification-settings?userId=…App-wide settings
PUT/api/v1/users/notification-settingsUpdate app-wide settings
GET/api/v1/rooms/{roomId}/notification-settings?userId=…Settings for one room
PUT/api/v1/rooms/{roomId}/notification-settingsUpdate settings for one room
bash
curl -X PUT https://chat.abrova.ir/api/v1/rooms/$ROOM_ID/notification-settings \
  -H "x-api-key: $ABROVA_API_KEY" \
  -H "x-server-secret: $ABROVA_SERVER_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"userId": "user-123", "pushLevel": "mentions"}'

With a user token, leave userId out; the token decides the user.

Response:

json
{
  "userId": "user-123",
  "scope": "room",
  "roomId": "5b1f…",
  "pushLevel": "mentions",
  "mutedUntil": null,
  "disabledEvents": [],
  "updatedAt": "2026-09-16T10:00:00.000Z"
}

App-wide settings return "scope": "app" and no roomId.

StatusWhen
400Missing userId (server secret), or an invalid value
403 user_mismatchA user token tried to change another user
404The room doesn't exist in your project, or the user isn't in it

Best Practices#

Go through your backend

Your server knows who is signed in; the app should never pick the user id or hold the server secret

Mute for a while, not forever

Offer "1 hour", "8 hours", "Until I turn it back on" — timed mutes end on their own

Mentions only for busy groups

pushLevel 'mentions' keeps large rooms quiet without missing what matters

Show the current state

Read the settings when the screen opens instead of keeping a local copy

Was this page helpful?
Report a problem