Notifications Endpoints¶
Аудитория: разработчики, frontend-инженеры Последнее обновление: 2025-11-17 Краткое содержание: Детальная документация Notification endpoints — получение уведомлений пользователя, пометка прочитанных, счетчик непрочитанных. Real-time notification system integration.
Обзор Endpoints¶
| Метод | Endpoint | Описание | Auth требуется |
|---|---|---|---|
| GET | /api/user/notifications |
Получить список уведомлений | ✅ Да |
| PUT | /api/user/notifications/{id}/read |
Пометить уведомление прочитанным | ✅ Да |
| PUT | /api/user/notifications/mark-all-read |
Пометить все уведомления прочитанными | ✅ Да |
| GET | /api/user/notifications/unread/count |
Получить количество непрочитанных | ✅ Да |
🔔 GET /api/user/notifications¶
Получить постраничный список уведомлений для аутентифицированного пользователя.
Запрос¶
GET /api/user/notifications?page=1&limit=20&unread=true&type=investment&sortBy=createdAt&orderBy=desc
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Заголовки:
| Заголовок | Значение | Обязательно | Описание |
|---|---|---|---|
Authorization |
Bearer <token> |
✅ Да | User JWT токен |
Query параметры:
| Параметр | Тип | Обязательно | Описание | По умолчанию |
|---|---|---|---|---|
page |
number | ❌ Нет | Номер страницы (с 1) | 1 |
limit |
number | ❌ Нет | Элементов на странице (макс: 100) | 20 |
unread |
boolean | ❌ Нет | Фильтр по непрочитанным: true, false |
Все |
type |
string | ❌ Нет | Фильтр по типу: investment, withdrawal, earning, security, system |
Все типы |
sortBy |
string | ❌ Нет | Поле сортировки: createdAt, priority |
createdAt |
orderBy |
string | ❌ Нет | Порядок сортировки: asc, desc |
desc |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": [
{
"id": "notif_abc123",
"type": "investment",
"title": "Инвестиция успешно создана",
"message": "Ваша инвестиция в стратегию Balanced (10% APY) на сумму $500.00 успешно создана",
"priority": "normal",
"isRead": false,
"category": "investment",
"actionUrl": "/investments/inv_xyz789",
"metadata": {
"investmentId": "inv_xyz789",
"strategyName": "Balanced 10% APY",
"amount": "500.00",
"currency": "USDC"
},
"createdAt": "2025-10-06T12:00:00Z",
"readAt": null
},
{
"id": "notif_def456",
"type": "earning",
"title": "Получена доходность",
"message": "Вы получили $5.50 доходности от стратегии Balanced (10% APY)",
"priority": "low",
"isRead": true,
"category": "earning",
"actionUrl": "/transactions/txn_earning123",
"metadata": {
"amount": "5.50",
"currency": "USDC",
"strategyName": "Balanced 10% APY",
"period": "2025-10-05 to 2025-10-06"
},
"createdAt": "2025-10-06T00:00:05Z",
"readAt": "2025-10-06T08:30:00Z"
},
{
"id": "notif_ghi789",
"type": "security",
"title": "Вход в аккаунт",
"message": "Обнаружен вход в аккаунт с нового устройства: Chrome на Windows",
"priority": "high",
"isRead": false,
"category": "security",
"actionUrl": "/security/sessions",
"metadata": {
"device": "Chrome on Windows",
"ip": "192.168.1.100",
"location": "Moscow, Russia"
},
"createdAt": "2025-10-05T18:30:00Z",
"readAt": null
},
{
"id": "notif_jkl012",
"type": "withdrawal",
"title": "Вывод одобрен",
"message": "Ваш запрос на вывод $1,000.00 USDC одобрен администратором",
"priority": "high",
"isRead": false,
"category": "withdrawal",
"actionUrl": "/withdrawals/wd_approved456",
"metadata": {
"withdrawalId": "wd_approved456",
"amount": "1000.00",
"currency": "USDC",
"approvedBy": "admin@saga.surf"
},
"createdAt": "2025-10-05T15:00:00Z",
"readAt": null
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 47,
"totalPages": 3,
"hasNext": true,
"hasPrevious": false,
"unreadCount": 12
},
"timestamp": "2025-10-06T12:34:56Z"
}
Типы уведомлений:
| Тип | Описание | Priority |
|---|---|---|
investment |
Создание/изменение инвестиций | normal |
earning |
Получение доходности | low |
withdrawal |
Операции вывода средств | high |
deposit |
Операции депозита | normal |
security |
Безопасность аккаунта (логины, изменения) | high |
system |
Системные уведомления | normal |
promotion |
Маркетинговые предложения | low |
Приоритеты уведомлений:
| Priority | Описание | Поведение UI |
|---|---|---|
critical |
Критические уведомления (безопасность) | Красный badge, звук |
high |
Важные уведомления (выводы, безопасность) | Оранжевый badge |
normal |
Стандартные уведомления | Синий badge |
low |
Информационные уведомления | Серый badge |
Поля ответа:
| Поле | Тип | Описание |
|---|---|---|
data[].id |
string | Уникальный ID уведомления |
data[].type |
string | Тип уведомления (см. таблицу выше) |
data[].title |
string | Заголовок уведомления |
data[].message |
string | Текст уведомления |
data[].priority |
string | Приоритет (critical, high, normal, low) |
data[].isRead |
boolean | Прочитано ли уведомление |
data[].actionUrl |
string | URL для перехода при клике |
data[].metadata |
object | Дополнительные данные |
data[].createdAt |
string | Timestamp создания |
data[].readAt |
string | Timestamp прочтения (null если непрочитано) |
pagination.unreadCount |
number | Общее количество непрочитанных |
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 400 | INVALID_PAGINATION |
page < 1 или limit > 100 |
| 401 | TOKEN_EXPIRED |
JWT токен истёк |
| 401 | TOKEN_INVALID |
Некорректная JWT подпись |
Пример cURL¶
TOKEN="eyJhbGciOiJIUzI1NiIs..."
# Получить все уведомления
curl -X GET "https://app.saga.surf/api/user/notifications?page=1&limit=20" \
-H "Authorization: Bearer $TOKEN"
# Получить только непрочитанные
curl -X GET "https://app.saga.surf/api/user/notifications?unread=true" \
-H "Authorization: Bearer $TOKEN"
# Получить уведомления по типу
curl -X GET "https://app.saga.surf/api/user/notifications?type=investment&type=earning" \
-H "Authorization: Bearer $TOKEN"
Пример TypeScript¶
// Получить уведомления с фильтрацией
const response = await fetch('/api/user/notifications?page=1&limit=20&unread=true&sortBy=createdAt&orderBy=desc', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const { data: notifications, pagination } = await response.json();
console.log(`Показано ${notifications.length} из ${pagination.total} уведомлений`);
console.log(`Непрочитанных: ${pagination.unreadCount}`);
notifications.forEach(notif => {
const badge = notif.isRead ? '' : '🔴';
const priorityIcon = {
critical: '🚨',
high: '⚠️',
normal: 'ℹ️',
low: '💡'
}[notif.priority];
console.log(`${badge} ${priorityIcon} ${notif.title}: ${notif.message}`);
});
PUT /api/user/notifications/{id}/read¶
Пометить конкретное уведомление как прочитанное.
Запрос¶
Заголовки:
| Заголовок | Значение | Обязательно | Описание |
|---|---|---|---|
Authorization |
Bearer <token> |
✅ Да | User JWT токен |
Path параметры:
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
id |
string | ✅ Да | Notification ID (например, notif_abc123) |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"id": "notif_abc123",
"type": "investment",
"title": "Инвестиция успешно создана",
"message": "Ваша инвестиция в стратегию Balanced (10% APY) на сумму $500.00 успешно создана",
"priority": "normal",
"isRead": true,
"category": "investment",
"actionUrl": "/investments/inv_xyz789",
"metadata": {
"investmentId": "inv_xyz789",
"strategyName": "Balanced 10% APY",
"amount": "500.00",
"currency": "USDC"
},
"createdAt": "2025-10-06T12:00:00Z",
"readAt": "2025-10-06T12:35:00Z"
},
"timestamp": "2025-10-06T12:35:00Z"
}
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 401 | TOKEN_EXPIRED |
JWT токен истёк |
| 403 | PERMISSION_DENIED |
Уведомление принадлежит другому пользователю |
| 404 | NOTIFICATION_NOT_FOUND |
Notification ID не существует |
| 400 | ALREADY_READ |
Уведомление уже помечено прочитанным |
Пример cURL¶
TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl -X PUT https://app.saga.surf/api/user/notifications/notif_abc123/read \
-H "Authorization: Bearer $TOKEN"
Пример TypeScript¶
// Пометить уведомление прочитанным
async function markNotificationRead(notificationId: string) {
const response = await fetch(`/api/user/notifications/${notificationId}/read`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`
}
});
const { data } = await response.json();
console.log(`Уведомление ${data.id} помечено прочитанным в ${data.readAt}`);
return data;
}
// Пометить при клике
notificationElement.addEventListener('click', () => {
markNotificationRead(notification.id);
// Обновить UI
updateNotificationBadge();
});
PUT /api/user/notifications/mark-all-read¶
Пометить все уведомления пользователя как прочитанные (массовая операция).
Запрос¶
Заголовки:
| Заголовок | Значение | Обязательно | Описание |
|---|---|---|---|
Authorization |
Bearer <token> |
✅ Да | User JWT токен |
Body параметры (опциональные):
{
"type": "investment", // Пометить только уведомления данного типа
"beforeDate": "2025-10-01" // Пометить только уведомления до этой даты
}
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"markedCount": 15,
"remainingUnread": 3,
"details": {
"investment": 7,
"earning": 5,
"system": 3
}
},
"timestamp": "2025-10-06T12:35:00Z"
}
Поля ответа:
| Поле | Тип | Описание |
|---|---|---|
data.markedCount |
number | Количество помеченных уведомлений |
data.remainingUnread |
number | Осталось непрочитанных после операции |
data.details |
object | Разбивка по типам помеченных уведомлений |
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 401 | TOKEN_EXPIRED |
JWT токен истёк |
| 400 | NO_UNREAD_NOTIFICATIONS |
У пользователя нет непрочитанных уведомлений |
Пример cURL¶
TOKEN="eyJhbGciOiJIUzI1NiIs..."
# Пометить все уведомления
curl -X PUT https://app.saga.surf/api/user/notifications/mark-all-read \
-H "Authorization: Bearer $TOKEN"
# Пометить только уведомления определенного типа
curl -X PUT https://app.saga.surf/api/user/notifications/mark-all-read \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": "earning"}'
Пример TypeScript¶
// Пометить все уведомления прочитанными
async function markAllNotificationsRead(type?: string) {
const body = type ? JSON.stringify({ type }) : undefined;
const response = await fetch('/api/user/notifications/mark-all-read', {
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
...(body && { 'Content-Type': 'application/json' })
},
...(body && { body })
});
const { data } = await response.json();
console.log(`Помечено ${data.markedCount} уведомлений, осталось ${data.remainingUnread}`);
return data;
}
// UI кнопка "Пометить все прочитанными"
markAllButton.addEventListener('click', async () => {
await markAllNotificationsRead();
refreshNotifications();
updateNotificationBadge();
});
🔢 GET /api/user/notifications/unread/count¶
Получить количество непрочитанных уведомлений (легковесный endpoint для badge).
Запрос¶
Заголовки:
| Заголовок | Значение | Обязательно | Описание |
|---|---|---|---|
Authorization |
Bearer <token> |
✅ Да | User JWT токен |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"total": 15,
"byType": {
"investment": 3,
"earning": 5,
"withdrawal": 2,
"security": 1,
"system": 4
},
"byPriority": {
"critical": 0,
"high": 3,
"normal": 9,
"low": 3
}
},
"timestamp": "2025-10-06T12:34:56Z"
}
Поля ответа:
| Поле | Тип | Описание |
|---|---|---|
data.total |
number | Общее количество непрочитанных |
data.byType |
object | Разбивка по типам уведомлений |
data.byPriority |
object | Разбивка по приоритетам |
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 401 | TOKEN_EXPIRED |
JWT токен истёк |
Пример cURL¶
TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl -X GET https://app.saga.surf/api/user/notifications/unread/count \
-H "Authorization: Bearer $TOKEN"
Пример TypeScript¶
// Получить количество непрочитанных
async function getUnreadCount(): Promise<number> {
const response = await fetch('/api/user/notifications/unread/count', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const { data } = await response.json();
return data.total;
}
// Обновление badge каждые 30 секунд
setInterval(async () => {
const count = await getUnreadCount();
updateNotificationBadge(count);
}, 30000);
// Функция обновления UI badge
function updateNotificationBadge(count: number) {
const badge = document.querySelector('.notification-badge');
if (count > 0) {
badge.textContent = count > 99 ? '99+' : count.toString();
badge.classList.remove('hidden');
} else {
badge.classList.add('hidden');
}
}
Распространённые сценарии использования¶
Отображение списка уведомлений¶
// Компонент списка уведомлений
async function NotificationsList() {
const { data: notifications, pagination } = await fetch('/api/user/notifications?limit=20', {
headers: { 'Authorization': `Bearer ${token}` }
}).then(r => r.json());
return (
<div className="notifications-list">
<h2>Уведомления ({pagination.total})</h2>
{notifications.map(notif => (
<div
key={notif.id}
className={`notification-item ${notif.isRead ? 'read' : 'unread'}`}
onClick={() => handleNotificationClick(notif)}
>
<div className="notification-header">
<span className={`priority-badge ${notif.priority}`}>
{notif.priority}
</span>
<span className="notification-time">
{formatRelativeTime(notif.createdAt)}
</span>
</div>
<h3>{notif.title}</h3>
<p>{notif.message}</p>
</div>
))}
{pagination.hasNext && (
<button onClick={() => loadMoreNotifications(pagination.page + 1)}>
Загрузить ещё
</button>
)}
</div>
);
}
Real-time notification badge¶
// Реактивный notification badge
function NotificationBadge() {
const [unreadCount, setUnreadCount] = useState(0);
useEffect(() => {
// Начальная загрузка
fetchUnreadCount();
// Периодическое обновление
const interval = setInterval(fetchUnreadCount, 30000);
return () => clearInterval(interval);
}, []);
async function fetchUnreadCount() {
const response = await fetch('/api/user/notifications/unread/count', {
headers: { 'Authorization': `Bearer ${token}` }
});
const { data } = await response.json();
setUnreadCount(data.total);
}
return (
<button className="notification-button" onClick={openNotifications}>
<BellIcon />
{unreadCount > 0 && (
<span className="notification-badge">
{unreadCount > 99 ? '99+' : unreadCount}
</span>
)}
</button>
);
}
Автоматическая пометка прочитанных¶
// Автоматическая пометка при просмотре
function handleNotificationClick(notification) {
// Перейти по actionUrl
router.push(notification.actionUrl);
// Пометить прочитанным если ещё не помечено
if (!notification.isRead) {
fetch(`/api/user/notifications/${notification.id}/read`, {
method: 'PUT',
headers: { 'Authorization': `Bearer ${token}` }
});
// Обновить локальное состояние
markLocalNotificationRead(notification.id);
updateUnreadCount(-1);
}
}
Фильтрация уведомлений по типу¶
// UI фильтры для уведомлений
function NotificationFilters({ onFilterChange }) {
const [selectedType, setSelectedType] = useState('all');
const [showUnreadOnly, setShowUnreadOnly] = useState(false);
const notificationTypes = [
{ value: 'all', label: 'Все уведомления' },
{ value: 'investment', label: 'Инвестиции' },
{ value: 'earning', label: 'Доходность' },
{ value: 'withdrawal', label: 'Выводы' },
{ value: 'security', label: 'Безопасность' },
{ value: 'system', label: 'Системные' },
];
const handleFilterChange = () => {
const params = new URLSearchParams();
if (selectedType !== 'all') params.append('type', selectedType);
if (showUnreadOnly) params.append('unread', 'true');
onFilterChange(params.toString());
};
return (
<div className="notification-filters">
<select value={selectedType} onChange={e => {
setSelectedType(e.target.value);
handleFilterChange();
}}>
{notificationTypes.map(type => (
<option key={type.value} value={type.value}>{type.label}</option>
))}
</select>
<label>
<input
type="checkbox"
checked={showUnreadOnly}
onChange={e => {
setShowUnreadOnly(e.target.checked);
handleFilterChange();
}}
/>
Только непрочитанные
</label>
</div>
);
}
Связанная документация¶
Другие User Endpoints:
- Authentication - User auth endpoints
- Investments - Управление инвестициями
- Withdrawals - Операции вывода
- Balance & Transactions - Баланс и транзакции
📋 Метаданные¶
Версия: 2.6.268
Обновлено: 2025-10-21
Статус: Published