@warriorteam/redai-zalo-sdk 1.18.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,276 @@
1
+ # RedAI Zalo SDK - Broadcast Service Guide
2
+
3
+ ## Tổng quan
4
+
5
+ BroadcastService cho phép gửi tin truyền thông broadcast đến nhiều người dùng cùng lúc dựa trên các tiêu chí targeting như tuổi, giới tính, địa điểm, và platform.
6
+
7
+ ## API Endpoint
8
+
9
+ - **URL**: `https://openapi.zalo.me/v2.0/oa/message`
10
+ - **Method**: POST
11
+ - **Content-Type**: application/json
12
+ - **Header**: `access_token: <your_access_token>`
13
+
14
+ ## Khởi tạo Service
15
+
16
+ ```typescript
17
+ import { ZaloSDK } from "@warriorteam/redai-zalo-sdk";
18
+
19
+ const zalo = new ZaloSDK({
20
+ appId: "your-app-id",
21
+ appSecret: "your-app-secret"
22
+ });
23
+
24
+ // Access broadcast service
25
+ const broadcastService = zalo.broadcast;
26
+ ```
27
+
28
+ ## Các Phương Thức Chính
29
+
30
+ ### 1. Gửi Broadcast Message
31
+
32
+ ```typescript
33
+ // Gửi broadcast đến người dùng ở Hồ Chí Minh
34
+ const target = zalo.broadcast.createBroadcastTarget({
35
+ cities: ["Hồ Chí Minh"]
36
+ });
37
+
38
+ const result = await zalo.broadcast.sendBroadcastMessage(
39
+ accessToken,
40
+ { target },
41
+ "article-attachment-id"
42
+ );
43
+
44
+ console.log("Message ID:", result.data.message_id);
45
+ ```
46
+
47
+ ### 2. Tạo Targeting Criteria
48
+
49
+ ```typescript
50
+ // Targeting phức tạp
51
+ const complexTarget = zalo.broadcast.createBroadcastTarget({
52
+ gender: "FEMALE", // Nữ giới
53
+ ages: ["18-24", "25-34"], // Tuổi 18-34
54
+ cities: ["Hà Nội", "Đà Nẵng"], // Hà Nội và Đà Nẵng
55
+ platform: ["ANDROID", "IOS"] // Android và iOS
56
+ });
57
+ ```
58
+
59
+ ## Targeting Criteria
60
+
61
+ ### 1. Nhóm Tuổi (Ages)
62
+
63
+ | Nhóm tuổi | Mã | Mô tả |
64
+ |-----------|----|----|
65
+ | `"0-12"` | `"0"` | Tuổi từ 0-12 |
66
+ | `"13-17"` | `"1"` | Tuổi từ 13-17 |
67
+ | `"18-24"` | `"2"` | Tuổi từ 18-24 |
68
+ | `"25-34"` | `"3"` | Tuổi từ 25-34 |
69
+ | `"35-44"` | `"4"` | Tuổi từ 35-44 |
70
+ | `"45-54"` | `"5"` | Tuổi từ 45-54 |
71
+ | `"55-64"` | `"6"` | Tuổi từ 55-64 |
72
+ | `"65+"` | `"7"` | Tuổi từ 65 trở lên |
73
+
74
+ ```typescript
75
+ const target = zalo.broadcast.createBroadcastTarget({
76
+ ages: ["18-24", "25-34"] // Targeting 18-34 tuổi
77
+ });
78
+ ```
79
+
80
+ ### 2. Giới Tính (Gender)
81
+
82
+ | Giới tính | Mã | Mô tả |
83
+ |-----------|----|----|
84
+ | `"ALL"` | `"0"` | Tất cả giới tính |
85
+ | `"MALE"` | `"1"` | Nam |
86
+ | `"FEMALE"` | `"2"` | Nữ |
87
+
88
+ ```typescript
89
+ const target = zalo.broadcast.createBroadcastTarget({
90
+ gender: "MALE" // Chỉ targeting nam giới
91
+ });
92
+ ```
93
+
94
+ ### 3. Tỉnh Thành (Cities)
95
+
96
+ Hỗ trợ 63 tỉnh thành Việt Nam:
97
+
98
+ ```typescript
99
+ const target = zalo.broadcast.createBroadcastTarget({
100
+ cities: ["Hồ Chí Minh", "Hà Nội", "Đà Nẵng"]
101
+ });
102
+
103
+ // Xem tất cả mã tỉnh thành
104
+ const cityCodes = zalo.broadcast.getCityCodes();
105
+ console.log(cityCodes);
106
+ ```
107
+
108
+ ### 4. Miền (Locations)
109
+
110
+ | Miền | Mã | Mô tả |
111
+ |------|----|----|
112
+ | `"NORTH"` | `"0"` | Miền Bắc |
113
+ | `"CENTRAL"` | `"1"` | Miền Trung |
114
+ | `"SOUTH"` | `"2"` | Miền Nam |
115
+
116
+ ```typescript
117
+ const target = zalo.broadcast.createBroadcastTarget({
118
+ locations: ["SOUTH"] // Chỉ miền Nam
119
+ });
120
+ ```
121
+
122
+ ### 5. Platform
123
+
124
+ | Platform | Mã | Mô tả |
125
+ |----------|----|----|
126
+ | `"IOS"` | `"1"` | iOS |
127
+ | `"ANDROID"` | `"2"` | Android |
128
+ | `"WINDOWS_PHONE"` | `"3"` | Windows Phone |
129
+
130
+ ```typescript
131
+ const target = zalo.broadcast.createBroadcastTarget({
132
+ platforms: ["IOS", "ANDROID"] // iOS và Android
133
+ });
134
+ ```
135
+
136
+ ## Ví Dụ Sử Dụng
137
+
138
+ ### 1. Broadcast Đơn Giản
139
+
140
+ ```typescript
141
+ // Gửi đến tất cả người dùng ở Hồ Chí Minh
142
+ const target = zalo.broadcast.createBroadcastTarget({
143
+ cities: ["Hồ Chí Minh"]
144
+ });
145
+
146
+ const result = await zalo.broadcast.sendBroadcastMessage(
147
+ accessToken,
148
+ { target },
149
+ "bd5ea46bb32e5a0033f"
150
+ );
151
+ ```
152
+
153
+ ### 2. Targeting Theo Nhân Khẩu Học
154
+
155
+ ```typescript
156
+ // Nữ giới 25-34 tuổi
157
+ const target = zalo.broadcast.createBroadcastTarget({
158
+ gender: "FEMALE",
159
+ ages: ["25-34"]
160
+ });
161
+
162
+ const result = await zalo.broadcast.sendBroadcastMessage(
163
+ accessToken,
164
+ { target },
165
+ "article-id"
166
+ );
167
+ ```
168
+
169
+ ### 3. Targeting Phức Tạp
170
+
171
+ ```typescript
172
+ // Nam giới 18-34 tuổi, dùng iOS, ở miền Nam
173
+ const target = zalo.broadcast.createBroadcastTarget({
174
+ gender: "MALE",
175
+ ages: ["18-24", "25-34"],
176
+ platforms: ["IOS"],
177
+ locations: ["SOUTH"]
178
+ });
179
+
180
+ const result = await zalo.broadcast.sendBroadcastMessage(
181
+ accessToken,
182
+ { target },
183
+ "article-id"
184
+ );
185
+ ```
186
+
187
+ ## Error Handling
188
+
189
+ ### Các Lỗi Thường Gặp
190
+
191
+ | Mã lỗi | Mô tả | Giải pháp |
192
+ |--------|-------|-----------|
193
+ | `3001` | Không có quyền broadcast | Liên hệ Zalo để được cấp quyền |
194
+ | `3002` | Article không tồn tại | Kiểm tra attachment_id |
195
+ | `3003` | Targeting không hợp lệ | Kiểm tra các tham số targeting |
196
+ | `3004` | Vượt quota broadcast | Chờ reset quota hoặc nâng cấp |
197
+ | `3005` | Vi phạm chính sách | Kiểm tra nội dung article |
198
+
199
+ ```typescript
200
+ try {
201
+ const result = await zalo.broadcast.sendBroadcastMessage(
202
+ accessToken,
203
+ { target },
204
+ articleId
205
+ );
206
+ console.log("Success:", result.data.message_id);
207
+ } catch (error) {
208
+ switch (error.code) {
209
+ case 3001:
210
+ console.error("Không có quyền broadcast");
211
+ break;
212
+ case 3002:
213
+ console.error("Article không tồn tại");
214
+ break;
215
+ default:
216
+ console.error("Lỗi khác:", error.message);
217
+ }
218
+ }
219
+ ```
220
+
221
+ ## Yêu Cầu và Giới Hạn
222
+
223
+ ### 1. Quyền Broadcast
224
+ - OA phải được Zalo cấp quyền gửi broadcast
225
+ - Cần tuân thủ chính sách về spam và nội dung
226
+
227
+ ### 2. Article Attachment
228
+ - Chỉ hỗ trợ template type `"media"` với `media_type: "article"`
229
+ - Article phải được tạo trước và có attachment_id hợp lệ
230
+
231
+ ### 3. Targeting
232
+ - Phải có ít nhất 1 tiêu chí targeting
233
+ - Có thể kết hợp nhiều tiêu chí cùng lúc
234
+
235
+ ### 4. Rate Limiting
236
+ - Tuân thủ giới hạn số lượng broadcast theo gói dịch vụ
237
+ - Tránh gửi quá nhiều broadcast trong thời gian ngắn
238
+
239
+ ## Best Practices
240
+
241
+ ### 1. Targeting Hiệu Quả
242
+ ```typescript
243
+ // Tốt: Targeting cụ thể
244
+ const target = zalo.broadcast.createBroadcastTarget({
245
+ gender: "FEMALE",
246
+ ages: ["25-34"],
247
+ cities: ["Hồ Chí Minh"]
248
+ });
249
+
250
+ // Tránh: Targeting quá rộng
251
+ const broadTarget = zalo.broadcast.createBroadcastTarget({
252
+ gender: "ALL" // Quá rộng, có thể bị spam
253
+ });
254
+ ```
255
+
256
+ ### 2. Nội Dung Chất Lượng
257
+ - Sử dụng article có nội dung hữu ích
258
+ - Tránh nội dung spam hoặc quảng cáo quá mức
259
+ - Tuân thủ chính sách của Zalo
260
+
261
+ ### 3. Monitoring và Analytics
262
+ ```typescript
263
+ // Lưu message_id để tracking
264
+ const result = await zalo.broadcast.sendBroadcastMessage(
265
+ accessToken,
266
+ { target },
267
+ articleId
268
+ );
269
+
270
+ // Lưu vào database để theo dõi
271
+ await saveBroadcastLog({
272
+ messageId: result.data.message_id,
273
+ targetCriteria: target,
274
+ sentAt: new Date()
275
+ });
276
+ ```
@@ -0,0 +1,332 @@
1
+ # API Gửi Danh Sách Tin Nhắn Group
2
+
3
+ API mở rộng cho phép gửi danh sách tin nhắn tới groups với callback tracking real-time.
4
+
5
+ ## Tính năng
6
+
7
+ - ✅ Gửi danh sách tin nhắn tới 1 group
8
+ - ✅ Gửi danh sách tin nhắn tới nhiều groups cùng lúc
9
+ - ✅ Hỗ trợ đầy đủ 5 loại tin nhắn: text, image, file, sticker, mention
10
+ - ✅ Callback tracking real-time cho từng tin nhắn/group
11
+ - ✅ Delay tùy chỉnh giữa tin nhắn và giữa groups
12
+ - ✅ Thống kê chi tiết thành công/thất bại
13
+ - ✅ Error isolation - lỗi 1 tin nhắn/group không ảnh hưởng phần còn lại
14
+
15
+ ## Cách sử dụng
16
+
17
+ ### 1. Import các interface và service
18
+
19
+ ```typescript
20
+ import {
21
+ GroupMessageService,
22
+ GroupMessageItem,
23
+ SendMessageListToGroupRequest,
24
+ SendMessageListToMultipleGroupsRequest
25
+ } from "../src/services/group-message.service";
26
+ import { ZaloClient } from "../src/clients/zalo-client";
27
+ ```
28
+
29
+ ### 2. Khởi tạo service
30
+
31
+ ```typescript
32
+ const zaloClient = new ZaloClient();
33
+ const groupMessageService = new GroupMessageService(zaloClient);
34
+ ```
35
+
36
+ ### 3. Định nghĩa danh sách tin nhắn
37
+
38
+ ```typescript
39
+ const messages: GroupMessageItem[] = [
40
+ {
41
+ type: "text",
42
+ text: "📢 Thông báo quan trọng!",
43
+ delay: 2000, // Delay 2 giây sau tin nhắn này
44
+ },
45
+ {
46
+ type: "image",
47
+ imageUrl: "https://example.com/image.jpg",
48
+ caption: "Hình ảnh minh họa",
49
+ delay: 1500,
50
+ },
51
+ {
52
+ type: "mention",
53
+ text: "@Admin Vui lòng xem thông báo",
54
+ mentions: [
55
+ { user_id: "ADMIN_ID", offset: 0, length: 6 }
56
+ ],
57
+ },
58
+ ];
59
+ ```
60
+
61
+ ### 4. Gửi tới 1 group
62
+
63
+ ```typescript
64
+ const result = await groupMessageService.sendMessageListToGroup({
65
+ accessToken: "YOUR_ACCESS_TOKEN",
66
+ groupId: "GROUP_ID",
67
+ messages,
68
+ defaultDelay: 1000,
69
+ onProgress: (progress) => {
70
+ console.log(`${progress.status}: Message ${progress.messageIndex + 1}/${progress.totalMessages}`);
71
+ }
72
+ });
73
+
74
+ console.log(`Thành công: ${result.successfulMessages}/${result.totalMessages} tin nhắn`);
75
+ ```
76
+
77
+ ### 5. Gửi tới nhiều groups
78
+
79
+ ```typescript
80
+ const result = await groupMessageService.sendMessageListToMultipleGroups({
81
+ accessToken: "YOUR_ACCESS_TOKEN",
82
+ groupIds: ["GROUP_1", "GROUP_2", "GROUP_3"],
83
+ messages,
84
+ defaultDelay: 1000,
85
+ delayBetweenGroups: 3000, // Delay 3s giữa các groups
86
+ onProgress: (progress) => {
87
+ console.log(`${progress.status}: Group ${progress.groupIndex + 1}/${progress.totalGroups}`);
88
+ }
89
+ });
90
+
91
+ console.log(`Thành công: ${result.successfulGroups}/${result.totalGroups} groups`);
92
+ ```
93
+
94
+ ## Các loại tin nhắn được hỗ trợ
95
+
96
+ ### 1. Text Message
97
+ ```typescript
98
+ {
99
+ type: "text",
100
+ text: "Nội dung tin nhắn",
101
+ delay: 1000, // Optional
102
+ }
103
+ ```
104
+
105
+ ### 2. Image Message
106
+ ```typescript
107
+ // Sử dụng URL
108
+ {
109
+ type: "image",
110
+ imageUrl: "https://example.com/image.jpg",
111
+ caption: "Caption cho ảnh", // Optional, max 2000 ký tự
112
+ delay: 1500,
113
+ }
114
+
115
+ // Hoặc sử dụng attachment ID
116
+ {
117
+ type: "image",
118
+ attachmentId: "ATTACHMENT_ID",
119
+ caption: "Caption cho ảnh",
120
+ delay: 1500,
121
+ }
122
+ ```
123
+
124
+ ### 3. File Message
125
+ ```typescript
126
+ {
127
+ type: "file",
128
+ fileToken: "FILE_TOKEN_FROM_UPLOAD_API", // Bắt buộc
129
+ fileName: "document.pdf", // Optional
130
+ delay: 1000,
131
+ }
132
+ ```
133
+
134
+ ### 4. Sticker Message
135
+ ```typescript
136
+ {
137
+ type: "sticker",
138
+ stickerId: "STICKER_ID", // Bắt buộc
139
+ delay: 500,
140
+ }
141
+ ```
142
+
143
+ ### 5. Mention Message
144
+ ```typescript
145
+ {
146
+ type: "mention",
147
+ text: "@Admin @User Vui lòng xem thông báo", // Bắt buộc
148
+ mentions: [ // Bắt buộc
149
+ { user_id: "ADMIN_ID", offset: 0, length: 6 },
150
+ { user_id: "USER_ID", offset: 7, length: 5 }
151
+ ],
152
+ delay: 2000,
153
+ }
154
+ ```
155
+
156
+ ## Interface chi tiết
157
+
158
+ ### GroupMessageItem
159
+ ```typescript
160
+ interface GroupMessageItem {
161
+ type: "text" | "image" | "file" | "sticker" | "mention";
162
+ text?: string;
163
+ imageUrl?: string;
164
+ attachmentId?: string;
165
+ caption?: string;
166
+ fileToken?: string;
167
+ fileName?: string;
168
+ stickerId?: string;
169
+ mentions?: Array<{
170
+ user_id: string;
171
+ offset: number;
172
+ length: number;
173
+ }>;
174
+ delay?: number; // milliseconds
175
+ }
176
+ ```
177
+
178
+ ### SendMessageListToGroupRequest
179
+ ```typescript
180
+ interface SendMessageListToGroupRequest {
181
+ accessToken: string;
182
+ groupId: string;
183
+ messages: GroupMessageItem[];
184
+ defaultDelay?: number; // milliseconds
185
+ onProgress?: (progress: GroupMessageProgressInfo) => void;
186
+ }
187
+ ```
188
+
189
+ ### SendMessageListToMultipleGroupsRequest
190
+ ```typescript
191
+ interface SendMessageListToMultipleGroupsRequest {
192
+ accessToken: string;
193
+ groupIds: string[];
194
+ messages: GroupMessageItem[];
195
+ defaultDelay?: number; // milliseconds
196
+ delayBetweenGroups?: number; // milliseconds
197
+ onProgress?: (progress: MultipleGroupsProgressInfo) => void;
198
+ }
199
+ ```
200
+
201
+ ## Ví dụ thực tế
202
+
203
+ ### Thông báo bảo trì hệ thống
204
+ ```typescript
205
+ const maintenanceMessages: GroupMessageItem[] = [
206
+ {
207
+ type: "text",
208
+ text: "🔧 THÔNG BÁO BẢO TRÌ HỆ THỐNG",
209
+ delay: 2000,
210
+ },
211
+ {
212
+ type: "text",
213
+ text: "⏰ Thời gian: 2:00 - 4:00 sáng ngày mai\n⚠️ Các dịch vụ sẽ tạm ngưng",
214
+ delay: 1500,
215
+ },
216
+ {
217
+ type: "image",
218
+ imageUrl: "https://company.com/maintenance-schedule.jpg",
219
+ caption: "Lịch trình bảo trì chi tiết",
220
+ delay: 2000,
221
+ },
222
+ {
223
+ type: "text",
224
+ text: "📞 Hotline hỗ trợ: 1900-xxxx",
225
+ },
226
+ ];
227
+
228
+ const result = await groupMessageService.sendMessageListToMultipleGroups({
229
+ accessToken: "TOKEN",
230
+ groupIds: ["TECH_GROUP", "SUPPORT_GROUP", "ADMIN_GROUP"],
231
+ messages: maintenanceMessages,
232
+ delayBetweenGroups: 2000,
233
+ onProgress: (progress) => {
234
+ if (progress.status === 'completed') {
235
+ console.log(`✅ Đã thông báo tới group ${progress.groupIndex + 1}`);
236
+ }
237
+ }
238
+ });
239
+ ```
240
+
241
+ ### Marketing Campaign
242
+ ```typescript
243
+ const campaignMessages: GroupMessageItem[] = [
244
+ {
245
+ type: "text",
246
+ text: "🎉 FLASH SALE 24H - GIẢM GIÁ SỐC!",
247
+ delay: 2000,
248
+ },
249
+ {
250
+ type: "image",
251
+ imageUrl: "https://shop.com/flash-sale-banner.jpg",
252
+ caption: "🔥 Giảm tới 70% + Freeship",
253
+ delay: 3000,
254
+ },
255
+ {
256
+ type: "text",
257
+ text: "⏰ Chỉ còn 12 giờ!\n🛒 Mua ngay: https://shop.com/sale",
258
+ delay: 1500,
259
+ },
260
+ {
261
+ type: "sticker",
262
+ stickerId: "SALE_STICKER_ID",
263
+ },
264
+ ];
265
+
266
+ const customerGroups = ["VIP_CUSTOMERS", "REGULAR_CUSTOMERS", "NEW_CUSTOMERS"];
267
+
268
+ const result = await groupMessageService.sendMessageListToMultipleGroups({
269
+ accessToken: "TOKEN",
270
+ groupIds: customerGroups,
271
+ messages: campaignMessages,
272
+ defaultDelay: 1000,
273
+ delayBetweenGroups: 5000, // 5s delay để tránh spam
274
+ onProgress: (progress) => {
275
+ console.log(`📤 Campaign progress: ${progress.groupIndex + 1}/${progress.totalGroups}`);
276
+ }
277
+ });
278
+
279
+ console.log(`🎯 Campaign hoàn thành: ${result.successfulGroups} groups nhận được tin nhắn`);
280
+ ```
281
+
282
+ ### Meeting Notification với Mention
283
+ ```typescript
284
+ const meetingMessages: GroupMessageItem[] = [
285
+ {
286
+ type: "text",
287
+ text: "📅 THÔNG BÁO CUỘC HỌP",
288
+ delay: 1000,
289
+ },
290
+ {
291
+ type: "mention",
292
+ text: "@TeamLead @Developer @Designer Cuộc họp dự án lúc 14:00 hôm nay",
293
+ mentions: [
294
+ { user_id: "LEAD_ID", offset: 0, length: 9 },
295
+ { user_id: "DEV_ID", offset: 10, length: 10 },
296
+ { user_id: "DESIGN_ID", offset: 21, length: 9 }
297
+ ],
298
+ delay: 2000,
299
+ },
300
+ {
301
+ type: "text",
302
+ text: "📋 Agenda:\n1. Sprint review\n2. Planning\n3. Q&A",
303
+ },
304
+ ];
305
+
306
+ const result = await groupMessageService.sendMessageListToGroup({
307
+ accessToken: "TOKEN",
308
+ groupId: "PROJECT_TEAM_GROUP",
309
+ messages: meetingMessages,
310
+ defaultDelay: 1500,
311
+ });
312
+ ```
313
+
314
+ ## So sánh với API cũ
315
+
316
+ | Tính năng | API cũ | API mới |
317
+ |-----------|--------|---------|
318
+ | Số lượng tin nhắn | 1 tin nhắn | Nhiều tin nhắn |
319
+ | Số lượng groups | 1 group | 1 hoặc nhiều groups |
320
+ | Callback tracking | ❌ | ✅ Real-time |
321
+ | Delay control | ❌ | ✅ Tùy chỉnh |
322
+ | Error handling | Dừng khi lỗi | Tiếp tục với tin nhắn/group khác |
323
+ | Statistics | ❌ | ✅ Chi tiết |
324
+ | Use case | Tin nhắn đơn lẻ | Campaigns, notifications |
325
+
326
+ ## Lưu ý quan trọng
327
+
328
+ 1. **Rate Limiting**: Sử dụng `delayBetweenGroups` để tránh hit rate limit
329
+ 2. **Group Permissions**: OA phải có quyền gửi tin nhắn trong group
330
+ 3. **Message Limits**: Tuân thủ giới hạn của từng loại tin nhắn (text: 2000 ký tự, etc.)
331
+ 4. **Error Isolation**: Lỗi của 1 tin nhắn/group không ảnh hưởng phần còn lại
332
+ 5. **Callback Performance**: Callback không nên thực hiện operations nặng