Chat API - Управление чатами и общением с покупателями
Chat API - Управление чатами и общением с покупателями
Chat API предоставляет возможности для общения с покупателями через встроенную систему чатов OZON. Позволяет создавать новые чаты, отправлять сообщения и файлы, а также управлять историей переписки.
Обзор API
Количество методов: 8
Основные функции: Создание чатов, отправка сообщений и файлов, управление историей
Доступность: Только для продавцов с подпиской Premium Plus
Ограничения: Зависят от типа отправления (FBO/FBS/rFBS) и времени
⚠️ Важно: Методы v2 для списка чатов и истории устаревают. Рекомендуется использовать v3.
Типы отправлений и ограничения
Временные ограничения по типам отправления
FBO (Fulfillment by OZON):
- Чат может создать только покупатель
- Продавец может отвечать в течение 48 часов после последнего сообщения покупателя
FBS и rFBS (Fulfillment by Seller):
- Продавец может создать чат в течение 72 часов после оплаты или доставки
- После 72 часов можно только отвечать на сообщения покупателя (в течение 48 часов)
Основные методы управления чатами
1. Создание нового чата
Метод: startChat()
Эндпоинт: POST /v1/chat/start
Создает новый чат с покупателем по номеру отправления.
Параметры запроса
interface ChatStartRequest {
posting_number: string; // Номер отправления
}
Пример использования
import { OzonSellerApiClient } from '@spacechemical/ozon-seller-api';
const client = new OzonSellerApiClient({
apiKey: 'your-api-key',
clientId: 'your-client-id'
});
// Создать новый чат по отправлению
const chat = await client.chat.startChat({
posting_number: 'FBS-12345'
});
console.log(`Чат создан с ID: ${chat.result?.chat_id}`);
// Проверить результат создания
if (chat.result?.chat_id) {
console.log('✅ Чат успешно создан');
console.log(`ID чата: ${chat.result.chat_id}`);
} else {
console.log('❌ Не удалось создать чат');
}
2. Отправка сообщений
Метод: sendMessage()
Эндпоинт: POST /v1/chat/send/message
Отправляет текстовое сообщение в существующий чат.
Параметры запроса
interface ChatSendMessageRequest {
chat_id: string; // ID чата
text: string; // Текст сообщения
}
Пример использования
// Отправить сообщение покупателю
const result = await client.chat.sendMessage({
chat_id: 'chat-123',
text: 'Здравствуйте! Ваш заказ готовится к отправке. Ожидаемая дата отгрузки - завтра.'
});
if (result.result === 'ok') {
console.log('✅ Сообщение отправлено успешно');
} else {
console.log('❌ Ошибка отправки сообщения');
}
// Отправка сообщения с информацией о доставке
const trackingResult = await client.chat.sendMessage({
chat_id: 'chat-123',
text: `📦 Ваш заказ отправлен!\n\nТрек-номер: 12345678901234\nОжидаемая доставка: 25.12.2024\n\nОтследить можно по ссылке: https://example.com/track/12345678901234`
});
3. Отправка файлов
Метод: sendFile()
Эндпоинт: POST /v1/chat/send/file
Отправляет файл (изображение, документ) в чат.
Параметры запроса
interface ChatSendFileRequest {
chat_id: string; // ID чата
base64_content: string; // Содержимое файла в base64
name: string; // Имя файла
}
Пример использования
// Функция для конвертации файла в base64
const fileToBase64 = async (file: File): Promise<string> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const base64 = (reader.result as string).split(',')[1];
resolve(base64);
};
reader.onerror = error => reject(error);
});
};
// Отправка файла-инструкции
const instructionFile = new File(['Инструкция по использованию товара...'], 'instruction.txt');
const base64Content = await fileToBase64(instructionFile);
const fileResult = await client.chat.sendFile({
chat_id: 'chat-123',
base64_content: base64Content,
name: 'instruction.txt'
});
if (fileResult.result === 'ok') {
console.log('✅ Файл отправлен успешно');
}
// Отправка изображения товара
const sendProductImage = async (chatId: string, imageFile: File) => {
const base64Image = await fileToBase64(imageFile);
return client.chat.sendFile({
chat_id: chatId,
base64_content: base64Image,
name: imageFile.name
});
};
4. Отметка сообщений как прочитанные
Метод: markAsRead()
Эндпоинт: POST /v2/chat/read
Отмечает выбранное сообщение и все предыдущие как прочитанные.
Пример использования
// Отметить сообщения как прочитанные
const readResult = await client.chat.markAsRead({
chat_id: 'chat-123',
from_message_id: 456
});
console.log(`Осталось непрочитанных сообщений: ${readResult.unread_count}`);
// Автоматическая отметка при получении новых сообщений
const markLatestAsRead = async (chatId: string) => {
// Получить последние сообщения
const history = await client.chat.getChatHistoryV3({
chat_id: chatId,
limit: 1,
direction: 'Backward'
});
if (history.messages && history.messages.length > 0) {
const latestMessage = history.messages[0];
if (latestMessage.message_id) {
await client.chat.markAsRead({
chat_id: chatId,
from_message_id: latestMessage.message_id
});
}
}
};
Методы получения информации о чатах
5. Получение списка чатов (v3)
Метод: getChatListV3()
Эндпоинт: POST /v3/chat/list
Возвращает список чатов с фильтрацией и пагинацией.
Параметры запроса
interface ChatListV3Request {
limit?: number; // Количество чатов (по умолчанию 30)
cursor?: string; // Курсор для пагинации
filter?: {
chat_status?: 'Opened' | 'Closed';
unread_only?: boolean; // Только с непрочитанными сообщениями
posting_number?: string; // Фильтр по номеру отправления
};
}
Пример использования
// Получить все открытые чаты с непрочитанными сообщениями
const unreadChats = await client.chat.getChatListV3({
limit: 100,
filter: {
chat_status: 'Opened',
unread_only: true
}
});
console.log(`Найдено чатов с непрочитанными сообщениями: ${unreadChats.chats?.length || 0}`);
unreadChats.chats?.forEach(chatInfo => {
console.log(`Чат ${chatInfo.chat?.chat_id}:`);
console.log(` Отправление: ${chatInfo.chat?.posting_number}`);
console.log(` Непрочитанных: ${chatInfo.unread_count}`);
console.log(` Последнее сообщение: ${chatInfo.last_message?.created_at}`);
});
// Получить все чаты с пагинацией
const getAllChats = async () => {
const allChats = [];
let cursor: string | undefined;
do {
const response = await client.chat.getChatListV3({
limit: 100,
cursor
});
if (response.chats) {
allChats.push(...response.chats);
}
cursor = response.has_next ? response.cursor : undefined;
} while (cursor);
return allChats;
};
6. Получение истории чата (v3)
Метод: getChatHistoryV3()
Эндпоинт: POST /v3/chat/history
Возвращает историю сообщений конкретного чата.
Параметры запроса
interface ChatHistoryV3Request {
chat_id: string; // ID чата
limit?: number; // Количество сообщений (по умолчанию 30)
direction?: 'Forward' | 'Backward'; // Направление (по умолчанию Backward)
from_message_id?: number; // ID сообщения для начала выборки
}
Пример использования
// Получить последние 50 сообщений чата
const history = await client.chat.getChatHistoryV3({
chat_id: 'chat-123',
limit: 50,
direction: 'Backward'
});
console.log(`Получено сообщений: ${history.messages?.length || 0}`);
history.messages?.forEach(message => {
const timestamp = new Date(message.created_at!).toLocaleString();
const sender = message.user?.name || 'Система';
const content = message.data?.join(' ') || '';
console.log(`[${timestamp}] ${sender}: ${content}`);
if (message.is_image) {
console.log(' 📷 Содержит изображение');
}
if (message.files && message.files.length > 0) {
console.log(` 📎 Файлы: ${message.files.map(f => f.name).join(', ')}`);
}
});
// Получить всю историю чата
const getFullChatHistory = async (chatId: string) => {
const allMessages = [];
let fromMessageId: number | undefined;
do {
const response = await client.chat.getChatHistoryV3({
chat_id: chatId,
limit: 100,
direction: 'Backward',
from_message_id: fromMessageId
});
if (response.messages && response.messages.length > 0) {
allMessages.push(...response.messages);
// Получить ID самого старого сообщения для следующего запроса
const oldestMessage = response.messages[response.messages.length - 1];
fromMessageId = oldestMessage.message_id;
} else {
break;
}
} while (true);
return allMessages.reverse(); // Вернуть в хронологическом порядке
};
7. Получение списка чатов (v2) - DEPRECATED
Метод: getChatListV2()
⚠️ Устарел: Рекомендуется использовать getChatListV3()
8. Получение истории чата (v2) - DEPRECATED
Метод: getChatHistoryV2()
⚠️ Устарел: Рекомендуется использовать getChatHistoryV3()
Практические сценарии использования
1. Система автоматических уведомлений
class ChatNotificationSystem {
constructor(private client: OzonSellerApiClient) {}
// Отправить уведомление о готовности заказа к отправке
async notifyOrderReady(postingNumber: string, trackingNumber?: string) {
try {
// Создать чат или получить существующий
const chat = await this.client.chat.startChat({
posting_number: postingNumber
});
if (chat.result?.chat_id) {
let message = `📦 Добрый день! Ваш заказ готов к отправке.`;
if (trackingNumber) {
message += `\n\n📋 Трек-номер для отслеживания: ${trackingNumber}`;
message += `\n🚚 Заказ будет передан в службу доставки в ближайшее время.`;
}
message += `\n\n📞 Если у вас есть вопросы, напишите нам в этом чате.`;
await this.client.chat.sendMessage({
chat_id: chat.result.chat_id,
text: message
});
console.log(`✅ Уведомление отправлено для заказа ${postingNumber}`);
}
} catch (error) {
console.error(`❌ Ошибка отправки уведомления для ${postingNumber}:`, error);
}
}
// Отправить уведомление о задержке доставки
async notifyDeliveryDelay(postingNumber: string, newDeliveryDate: string, reason: string) {
try {
const chat = await this.client.chat.startChat({
posting_number: postingNumber
});
if (chat.result?.chat_id) {
const message = `⏰ К сожалению, доставка вашего заказа задерживается.\n\n` +
`📅 Новая ожидаемая дата доставки: ${newDeliveryDate}\n` +
`💬 Причина: ${reason}\n\n` +
`Приносим извинения за доставленные неудобства. ` +
`Если у вас есть вопросы, пожалуйста, напишите нам.`;
await this.client.chat.sendMessage({
chat_id: chat.result.chat_id,
text: message
});
console.log(`✅ Уведомление о задержке отправлено для ${postingNumber}`);
}
} catch (error) {
console.error(`❌ Ошибка отправки уведомления о задержке для ${postingNumber}:`, error);
}
}
// Отправить инструкцию по использованию товара
async sendProductInstructions(postingNumber: string, instructionFile: File) {
try {
const chat = await this.client.chat.startChat({
posting_number: postingNumber
});
if (chat.result?.chat_id) {
// Сначала отправляем сообщение
await this.client.chat.sendMessage({
chat_id: chat.result.chat_id,
text: '📖 Отправляем вам инструкцию по использованию товара. Если возникнут вопросы, обращайтесь!'
});
// Затем отправляем файл
const base64Content = await this.fileToBase64(instructionFile);
await this.client.chat.sendFile({
chat_id: chat.result.chat_id,
base64_content: base64Content,
name: instructionFile.name
});
console.log(`✅ Инструкция отправлена для заказа ${postingNumber}`);
}
} catch (error) {
console.error(`❌ Ошибка отправки инструкции для ${postingNumber}:`, error);
}
}
private async fileToBase64(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const base64 = (reader.result as string).split(',')[1];
resolve(base64);
};
reader.onerror = error => reject(error);
});
}
}
const notificationSystem = new ChatNotificationSystem(client);
// Уведомить о готовности заказов
await notificationSystem.notifyOrderReady('FBS-12345', 'TRACK123456');
await notificationSystem.notifyDeliveryDelay('FBS-12346', '28.12.2024', 'Задержка на складе поставщика');
2. Система мониторинга и автоответов
class ChatMonitoringSystem {
constructor(private client: OzonSellerApiClient) {}
// Мониторинг непрочитанных сообщений
async monitorUnreadMessages() {
try {
const unreadChats = await this.client.chat.getChatListV3({
limit: 1000,
filter: {
unread_only: true,
chat_status: 'Opened'
}
});
console.log(`🔔 Найдено чатов с непрочитанными сообщениями: ${unreadChats.chats?.length || 0}`);
for (const chatInfo of unreadChats.chats || []) {
if (chatInfo.chat?.chat_id) {
await this.processUnreadChat(chatInfo);
}
}
} catch (error) {
console.error('❌ Ошибка мониторинга чатов:', error);
}
}
private async processUnreadChat(chatInfo: any) {
const chatId = chatInfo.chat.chat_id;
const unreadCount = chatInfo.unread_count;
console.log(`📬 Обработка чата ${chatId} (${unreadCount} непрочитанных)`);
// Получить последние сообщения
const history = await this.client.chat.getChatHistoryV3({
chat_id: chatId,
limit: 10,
direction: 'Backward'
});
// Анализировать сообщения на предмет автоответов
const latestMessages = history.messages || [];
for (const message of latestMessages) {
if (message.user?.user_type === 'Customer' && !message.is_read_by_seller) {
await this.processCustomerMessage(chatId, message);
}
}
// Отметить сообщения как прочитанные
if (latestMessages.length > 0) {
const latestMessageId = latestMessages[0].message_id;
if (latestMessageId) {
await this.client.chat.markAsRead({
chat_id: chatId,
from_message_id: latestMessageId
});
}
}
}
private async processCustomerMessage(chatId: string, message: any) {
const messageText = (message.data || []).join(' ').toLowerCase();
// Автоответы на часто задаваемые вопросы
const autoResponses = [
{
keywords: ['где', 'заказ', 'трек', 'отслед'],
response: 'Для отслеживания заказа используйте трек-номер в личном кабинете OZON или на сайте службы доставки. Если трек-номера нет, заказ еще готовится к отправке.'
},
{
keywords: ['когда', 'доставк', 'получ'],
response: 'Сроки доставки зависят от вашего региона и выбранного способа доставки. Обычно доставка занимает 1-5 рабочих дней с момента отправки.'
},
{
keywords: ['возврат', 'верн', 'обмен'],
response: 'Вы можете оформить возврат через ваш личный кабинет в разделе "Мои заказы" в течение 14 дней с момента получения товара. Товар должен быть в оригинальной упаковке.'
},
{
keywords: ['размер', 'не подход', 'мал', 'велик'],
response: 'При проблемах с размером вы можете оформить обмен или возврат. Рекомендуем обратиться в службу поддержки OZON для быстрого решения вопроса.'
}
];
for (const autoResponse of autoResponses) {
if (autoResponse.keywords.some(keyword => messageText.includes(keyword))) {
await this.client.chat.sendMessage({
chat_id: chatId,
text: `🤖 ${autoResponse.response}\n\nЕсли это не ответило на ваш вопрос, наш специалист свяжется с вами в ближайшее время.`
});
console.log(`🤖 Отправлен автоответ для чата ${chatId}`);
break;
}
}
}
// Генерация отчета по активности чатов
async generateChatReport(days: number = 7) {
const allChats = await this.getAllChats();
const now = new Date();
const cutoffDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
const report = {
totalChats: allChats.length,
openChats: 0,
closedChats: 0,
unreadChats: 0,
totalUnreadMessages: 0,
recentActivity: 0,
averageResponseTime: 0
};
for (const chatInfo of allChats) {
// Статистика по статусам
if (chatInfo.chat?.chat_status === 'Opened') {
report.openChats++;
} else {
report.closedChats++;
}
// Непрочитанные сообщения
if (chatInfo.unread_count > 0) {
report.unreadChats++;
report.totalUnreadMessages += chatInfo.unread_count;
}
// Активность за период
if (chatInfo.last_message?.created_at) {
const lastMessageDate = new Date(chatInfo.last_message.created_at);
if (lastMessageDate >= cutoffDate) {
report.recentActivity++;
}
}
}
console.log('📊 Отчет по чатам за последние', days, 'дней:');
console.log(`Всего чатов: ${report.totalChats}`);
console.log(`Открытых: ${report.openChats}, закрытых: ${report.closedChats}`);
console.log(`Чатов с непрочитанными: ${report.unreadChats}`);
console.log(`Всего непрочитанных сообщений: ${report.totalUnreadMessages}`);
console.log(`Чатов с активностью за период: ${report.recentActivity}`);
return report;
}
private async getAllChats() {
const allChats = [];
let cursor: string | undefined;
do {
const response = await this.client.chat.getChatListV3({
limit: 1000,
cursor
});
if (response.chats) {
allChats.push(...response.chats);
}
cursor = response.has_next ? response.cursor : undefined;
} while (cursor);
return allChats;
}
}
const monitoringSystem = new ChatMonitoringSystem(client);
// Настроить регулярный мониторинг
setInterval(async () => {
await monitoringSystem.monitorUnreadMessages();
}, 5 * 60 * 1000); // Каждые 5 минут
// Генерировать отчет каждый день
setInterval(async () => {
await monitoringSystem.generateChatReport(7);
}, 24 * 60 * 60 * 1000); // Каждые 24 часа
3. Шаблоны сообщений и массовые рассылки
class ChatTemplateSystem {
private templates: Map<string, MessageTemplate> = new Map();
constructor(private client: OzonSellerApiClient) {
this.initializeTemplates();
}
private initializeTemplates() {
// Шаблоны сообщений
this.templates.set('order_shipped', {
title: 'Заказ отправлен',
template: `📦 Ваш заказ отправлен!\n\n🚚 Трек-номер: \n📅 Ожидаемая доставка: \n\n📍 Отследить можно по ссылке: `
});
this.templates.set('order_delayed', {
title: 'Задержка заказа',
template: `⏰ К сожалению, ваш заказ задерживается.\n\n📅 Новая дата доставки: \n💬 Причина: \n\nПриносим извинения за неудобства!`
});
this.templates.set('thank_you', {
title: 'Благодарность за покупку',
template: `🎉 Спасибо за покупку!\n\n⭐ Будем благодарны за отзыв о товаре.\n📞 При возникновении вопросов обращайтесь в чат.\n\n🛍️ Ждем вас снова!`
});
this.templates.set('product_care', {
title: 'Уход за товаром',
template: `🛡️ Рекомендации по уходу за товаром:\n\n\n\n📖 Подробную инструкцию можно найти в упаковке.\n❓ Есть вопросы? Пишите нам!`
});
}
// Отправить сообщение по шаблону
async sendTemplateMessage(
postingNumber: string,
templateKey: string,
variables: Record<string, string>
) {
const template = this.templates.get(templateKey);
if (!template) {
throw new Error(`Шаблон ${templateKey} не найден`);
}
try {
// Создать или получить чат
const chat = await this.client.chat.startChat({
posting_number: postingNumber
});
if (chat.result?.chat_id) {
// Заменить переменные в шаблоне
let message = template.template;
Object.entries(variables).forEach(([key, value]) => {
message = message.replace(new RegExp(`}`, 'g'), value);
});
await this.client.chat.sendMessage({
chat_id: chat.result.chat_id,
text: message
});
console.log(`✅ Отправлен шаблон "${template.title}" для ${postingNumber}`);
}
} catch (error) {
console.error(`❌ Ошибка отправки шаблона для ${postingNumber}:`, error);
}
}
// Массовая рассылка по списку заказов
async sendBulkMessages(
orders: Array<{
postingNumber: string;
templateKey: string;
variables: Record<string, string>;
}>,
delayMs: number = 1000
) {
console.log(`📨 Начинаем массовую рассылку для ${orders.length} заказов`);
let successCount = 0;
let errorCount = 0;
for (const [index, order] of orders.entries()) {
try {
await this.sendTemplateMessage(
order.postingNumber,
order.templateKey,
order.variables
);
successCount++;
} catch (error) {
console.error(`❌ Ошибка для заказа ${order.postingNumber}:`, error);
errorCount++;
}
// Прогресс
if ((index + 1) % 10 === 0) {
console.log(`📊 Прогресс: ${index + 1}/${orders.length} (успешно: ${successCount}, ошибок: ${errorCount})`);
}
// Задержка между отправками для соблюдения лимитов
if (index < orders.length - 1) {
await new Promise(resolve => setTimeout(resolve, delayMs));
}
}
console.log(`📊 Рассылка завершена: ${successCount} успешно, ${errorCount} ошибок`);
return { successCount, errorCount };
}
// Добавить новый шаблон
addTemplate(key: string, title: string, template: string) {
this.templates.set(key, { title, template });
console.log(`✅ Добавлен шаблон "${title}"`);
}
// Получить список шаблонов
getTemplates() {
return Array.from(this.templates.entries()).map(([key, template]) => ({
key,
title: template.title,
preview: template.template.substring(0, 100) + '...'
}));
}
}
interface MessageTemplate {
title: string;
template: string;
}
const templateSystem = new ChatTemplateSystem(client);
// Примеры использования шаблонов
await templateSystem.sendTemplateMessage('FBS-12345', 'order_shipped', {
trackingNumber: 'TRACK123456',
deliveryDate: '25.12.2024',
trackingUrl: 'https://example.com/track/TRACK123456'
});
await templateSystem.sendTemplateMessage('FBS-12346', 'product_care', {
careInstructions: 'Стирка при температуре не выше 30°C. Не отжимать. Сушить в горизонтальном положении.'
});
// Массовая рассылка уведомлений об отправке
const shippingNotifications = [
{
postingNumber: 'FBS-12347',
templateKey: 'order_shipped',
variables: {
trackingNumber: 'TRACK123457',
deliveryDate: '26.12.2024',
trackingUrl: 'https://example.com/track/TRACK123457'
}
},
{
postingNumber: 'FBS-12348',
templateKey: 'order_shipped',
variables: {
trackingNumber: 'TRACK123458',
deliveryDate: '27.12.2024',
trackingUrl: 'https://example.com/track/TRACK123458'
}
}
];
await templateSystem.sendBulkMessages(shippingNotifications, 2000); // 2 секунды между сообщениями
Обработка ошибок
Типичные ошибки и их обработка
try {
const chat = await client.chat.startChat({
posting_number: 'FBS-12345'
});
} catch (error) {
if (error.response?.status === 400) {
const errorData = error.response.data;
switch (errorData.code) {
case 'POSTING_NOT_FOUND':
console.error('Отправление не найдено');
break;
case 'CHAT_CREATION_NOT_ALLOWED':
console.error('Создание чата не разрешено для данного типа отправления');
break;
case 'TIME_LIMIT_EXCEEDED':
console.error('Время для создания чата истекло');
break;
case 'CHAT_ALREADY_EXISTS':
console.error('Чат уже существует для данного отправления');
break;
default:
console.error('Неизвестная ошибка:', errorData.message);
}
} else if (error.response?.status === 403) {
console.error('Доступ запрещен. Убедитесь, что у вас есть подписка Premium Plus');
} else if (error.response?.status === 429) {
console.error('Превышен лимит запросов. Повторите попытку позже.');
} else {
console.error('Произошла ошибка:', error.message);
}
}
Лучшие практики
1. Соблюдение временных ограничений
class ChatTimeManager {
// Проверить возможность отправки сообщения
static canSendMessage(postingType: 'FBO' | 'FBS' | 'rFBS', orderDate: Date, lastMessageDate?: Date): boolean {
const now = new Date();
const orderTime = orderDate.getTime();
const currentTime = now.getTime();
switch (postingType) {
case 'FBO':
// Можно отвечать только в течение 48 часов после последнего сообщения покупателя
if (lastMessageDate) {
const timeSinceLastMessage = currentTime - lastMessageDate.getTime();
return timeSinceLastMessage <= 48 * 60 * 60 * 1000; // 48 часов
}
return false;
case 'FBS':
case 'rFBS':
// Можно создавать чат в течение 72 часов после оплаты
const timeSinceOrder = currentTime - orderTime;
if (timeSinceOrder <= 72 * 60 * 60 * 1000) { // 72 часа
return true;
}
// После 72 часов можно только отвечать в течение 48 часов
if (lastMessageDate) {
const timeSinceLastMessage = currentTime - lastMessageDate.getTime();
return timeSinceLastMessage <= 48 * 60 * 60 * 1000;
}
return false;
default:
return false;
}
}
}
2. Управление rate limits
class RateLimitedChatClient {
private readonly requestQueue: Array<() => Promise<any>> = [];
private readonly REQUEST_DELAY = 1000; // 1 секунда между запросами
private isProcessing = false;
constructor(private client: OzonSellerApiClient) {}
async sendMessageWithRateLimit(chatId: string, text: string) {
return this.enqueueRequest(async () => {
return this.client.chat.sendMessage({ chat_id: chatId, text });
});
}
private async enqueueRequest<T>(request: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) => {
this.requestQueue.push(async () => {
try {
const result = await request();
resolve(result);
} catch (error) {
reject(error);
}
});
if (!this.isProcessing) {
this.processQueue();
}
});
}
private async processQueue() {
if (this.isProcessing || this.requestQueue.length === 0) return;
this.isProcessing = true;
while (this.requestQueue.length > 0) {
const request = this.requestQueue.shift()!;
await request();
if (this.requestQueue.length > 0) {
await new Promise(resolve => setTimeout(resolve, this.REQUEST_DELAY));
}
}
this.isProcessing = false;
}
}
3. Кэширование данных чатов
class ChatCache {
private chatListCache: Map<string, { data: any; timestamp: number }> = new Map();
private historyCache: Map<string, { data: any; timestamp: number }> = new Map();
private readonly CACHE_TTL = 5 * 60 * 1000; // 5 минут
async getCachedChatList(client: OzonSellerApiClient, filter?: any): Promise<any> {
const cacheKey = JSON.stringify(filter || {});
const cached = this.chatListCache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
return cached.data;
}
const data = await client.chat.getChatListV3({ filter });
this.chatListCache.set(cacheKey, { data, timestamp: Date.now() });
return data;
}
clearCache() {
this.chatListCache.clear();
this.historyCache.clear();
}
}
Связанные API: Premium API (подписка Premium Plus), Questions-Answers API (общение с покупателями), Review API (отзывы покупателей)