# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.11.1] - 2025-01-11

### 🔧 API IMPROVEMENTS

#### Method Signature Enhancement
- **IMPROVED**: `createOAAuthUrl()` method signature với better parameter order
  - Changed from: `(redirectUri, state?, usePkce?, pkce?)`
  - Changed to: `(redirectUri, state?, pkce?, usePkce?)`
- **ENHANCED**: More intuitive API design với PKCE config trước usePkce flag
- **UPDATED**: All examples và documentation để phù hợp với signature mới
- **ADDED**: Comprehensive test coverage cho new signature

#### Developer Experience
- **IMPROVED**: Better IntelliSense support với clearer parameter ordering
- **ENHANCED**: More logical API flow cho PKCE implementation

## [1.11.0] - 2025-01-11

### 🔐 SECURITY ENHANCEMENTS

#### PKCE Support for Official Account Authentication
- **ADDED**: PKCE (Proof Key for Code Exchange) support cho Official Account OAuth flow
- **ENHANCED**: `createOAAuthUrl()` method với PKCE parameters và auto-generated state
- **ADDED**: `generatePKCE()` method để tạo code_verifier và code_challenge
- **UPDATED**: `getOAAccessToken()` method hỗ trợ code_verifier cho token exchange
- **ADDED**: `OAAuthResult` type với url và state information
- **ADDED**: `createSecureOAAuthUrl()` method với full PKCE support

#### Security Best Practices
- **ENHANCED**: Auto-generated state với prefix 'zalo_oa_' nếu không được cung cấp
- **ADDED**: Comprehensive PKCE documentation và security guidelines
- **IMPROVED**: Type safety cho PKCE flow với proper TypeScript interfaces

### 📚 DOCUMENTATION

#### Authentication Guide Updates
- **UPDATED**: AUTHENTICATION.md với PKCE implementation guide
- **ADDED**: Security benefits và best practices cho PKCE
- **ADDED**: Complete examples cho PKCE flow
- **ADDED**: oa-auth-with-pkce.ts example file

### 🔧 TECHNICAL IMPROVEMENTS

#### API Compatibility
- **MAINTAINED**: Backward compatibility cho existing createOAAuthUrl() method
- **ADDED**: Deprecation notice cho old method signature
- **ENHANCED**: getAuthUrls() method với PKCE support

## [1.10.1] - 2025-01-11

### 🚀 NEW FEATURES

#### Consultation Service Enhancement
- **ADDED**: `sendQuoteMessage()` - Gửi tin nhắn tư vấn trích dẫn (quote message)
- **ADDED**: `createQuoteMessage()` - Helper method để tạo quote message object
- **ADDED**: `apiGetWithHeaders()` - Method hỗ trợ GET request với custom headers

#### API Compliance
- **ENHANCED**: SendMessageResponse type với đầy đủ quota information types
- **ADDED**: Support cho tất cả quota types: reply, sub_quota, purchase_quota, reward_quota
- **IMPROVED**: Quota information structure theo đúng Zalo API specification

### 🔧 TECHNICAL IMPROVEMENTS

#### Message Types
- **UPDATED**: SendMessageResponse interface với comprehensive quota fields
- **ADDED**: Support cho expired_date, owner_type, owner_id trong quota
- **ENHANCED**: Type safety cho quota_type với union types

#### Validation & Error Handling
- **ADDED**: Validation cho text length (max 2000 characters)
- **ADDED**: Validation cho quote_message_id
- **IMPROVED**: Error messages với detailed information

### 📋 API Implementation

#### Consultation Quote Message API - 100% Compliant ✅
- **Endpoint**: `POST https://openapi.zalo.me/v3.0/oa/message/cs`
- **Headers**: access_token ✅
- **Body**: recipient, message với text và quote_message_id ✅
- **Response**: message_id, user_id, quota information ✅

### 🎯 Usage Examples

#### Send Quote Message
```typescript
const zalo = new ZaloSDK();

// Gửi tin nhắn trích dẫn
const response = await zalo.consultation.sendQuoteMessage(
  accessToken,
  { user_id: "186729651760683225" },
  "Chào bạn, Shop có địa chỉ là 182 Lê Đại Hành, P15, Q10, HCM",
  "48687128d04c9410cd5f" // quote_message_id
);

console.log("Message ID:", response.message_id);
console.log("Quota Type:", response.quota?.quota_type);
```

#### Create Quote Message Object
```typescript
const quoteMessage = zalo.consultation.createQuoteMessage(
  "Cảm ơn bạn đã liên hệ!",
  "48687128d04c9410cd5f",
  "Nội dung tin nhắn gốc"
);
```

#### Handle Different Quota Types
```typescript
if (response.quota) {
  switch (response.quota.quota_type) {
    case "reply":
      console.log(`Free replies: ${response.quota.remain}/${response.quota.total}`);
      break;
    case "sub_quota":
      console.log(`Package quota: ${response.quota.remain}/${response.quota.total}`);
      console.log(`Expires: ${response.quota.expired_date}`);
      break;
    case "purchase_quota":
    case "reward_quota":
      console.log(`Owner: ${response.quota.owner_type} (${response.quota.owner_id})`);
      break;
  }
} else {
  console.log("Charged message (no free quota)");
}
```

## [1.10.0] - 2025-01-11

### 🚀 NEW FEATURES

#### Video Upload Service Enhancements
- **ADDED**: `uploadVideoAndWaitForCompletion()` - Combined method for upload and status checking
- **ADDED**: `VideoUploadStatus` enum for better status code handling
- **ADDED**: `apiGetWithHeaders()` method in ZaloClient for custom header requests

#### API Compliance Improvements
- **FIXED**: Video status check API to use token in header (not query params) per Zalo docs
- **UPDATED**: Status codes documentation to match official Zalo API specification
- **IMPROVED**: Video upload validation with proper MIME type checking

#### Architecture Cleanup
- **REMOVED**: Centralized endpoints from ZaloClient - each service now manages its own URLs
- **SIMPLIFIED**: ZaloClient to focus only on HTTP methods, not endpoint management
- **STANDARDIZED**: All services to use full URLs for better maintainability

### 🔧 TECHNICAL IMPROVEMENTS

#### Code Organization
- **REFACTORED**: Endpoint management - moved from centralized to service-specific
- **UPDATED**: All services to use full URLs instead of relative paths
- **CLEANED**: ZaloClient from unused endpoint definitions

#### Type Safety
- **ENHANCED**: Video upload types with proper status enum
- **IMPROVED**: Response handling for video upload APIs
- **ADDED**: Better error handling for video upload operations

### 📋 API Compliance Status

#### Video Upload APIs - 100% Compliant ✅
- **Upload Video**: `POST /v2.0/article/upload_video/preparevideo` - ✅ Fully compliant
- **Check Status**: `GET /v2.0/article/upload_video/verify` - ✅ Fixed header usage
- **Article Verify**: `POST /v2.0/article/verify` - ✅ Fully compliant

#### Breaking Changes
- **ZaloClient**: Removed `endpoints` property and `getEndpointUrl()` method
- **VideoUploadService**: `checkVideoStatus()` now uses headers correctly

### 🎯 Usage Examples

#### New Combined Video Upload
```typescript
const zalo = new ZaloSDK();

// Upload and wait for completion in one call
const result = await zalo.videoUpload.uploadVideoAndWaitForCompletion(
  accessToken,
  videoBuffer,
  "video.mp4",
  5 * 60 * 1000, // 5 minutes timeout
  5 * 1000       // 5 seconds polling
);

console.log("Video ID:", result.video_id);
console.log("Status:", result.status); // Use VideoUploadStatus enum
```

#### Status Code Handling
```typescript
import { VideoUploadStatus } from '@warriorteam/redai-zalo-sdk';

if (status.status === VideoUploadStatus.SUCCESS) {
  console.log("Video ready:", status.video_id);
} else if (status.status === VideoUploadStatus.PROCESSING) {
  console.log("Still processing:", status.convert_percent + "%");
}
```

## [1.9.14] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Get Info API Fix
- **FIXED**: `GroupDetailResponse` interface to match Zalo API docs 100%
- **CHANGED**: Return type from partial data to full API response
- **FIXED**: `group_info` field names: `group_name` → `name`, `group_avatar` → `avatar`, `member_count` → `total_member`
- **ADDED**: Missing fields in `group_info`: `status`, `max_member`
- **REMOVED**: Non-existent fields: `admin_count`, `created_time`
- **FIXED**: `asset_info` structure: added `asset_id`, `auto_renew`, removed `status`
- **FIXED**: `group_setting` field name: `join_approval` → `join_appr`
- **REMOVED**: Non-existent field: `lock_view_member`

#### API Structure Corrections
- **FIXED**: All nested objects to match actual Zalo API response exactly
- **IMPROVED**: Type safety with accurate field definitions and documentation
- **STANDARDIZED**: Field types to match API specification (e.g., `max_member` as string)

### 📋 Migration Guide

**Before (v1.9.13) - BROKEN:**
```typescript
// ❌ Wrong return type and field names
const groupData = await groupService.getGroupInfo(accessToken, groupId);
// Returns partial data only

if (groupData) {
  console.log(groupData.group_info.group_name);    // ❌ Wrong field name
  console.log(groupData.group_info.group_avatar);  // ❌ Wrong field name
  console.log(groupData.group_info.member_count);  // ❌ Wrong field name
  console.log(groupData.group_info.admin_count);   // ❌ Field doesn't exist
  console.log(groupData.asset_info.status);        // ❌ Field doesn't exist
  console.log(groupData.group_setting.join_approval); // ❌ Wrong field name
}
```

**After (v1.9.14) - CORRECT:**
```typescript
// ✅ Correct return type and field names
const response = await groupService.getGroupInfo(accessToken, groupId);

// ✅ Access response structure correctly
if (response.error === 0 && response.data) {
  const { group_info, asset_info, group_setting } = response.data;

  // ✅ group_info with correct field names
  console.log('Name:', group_info.name);              // ✅ Correct field name
  console.log('Avatar:', group_info.avatar);          // ✅ Correct field name
  console.log('Group ID:', group_info.group_id);
  console.log('Link:', group_info.group_link);
  console.log('Description:', group_info.group_description);
  console.log('Status:', group_info.status);          // ✅ New field
  console.log('Total Members:', group_info.total_member); // ✅ Correct field name
  console.log('Max Members:', group_info.max_member); // ✅ New field (string)
  console.log('Auto Delete:', group_info.auto_delete_date);

  // ✅ asset_info with correct structure
  console.log('Asset Type:', asset_info.asset_type);  // gmf10, gmf50, gmf100
  console.log('Asset ID:', asset_info.asset_id);      // ✅ New field
  console.log('Valid Through:', asset_info.valid_through);
  console.log('Auto Renew:', asset_info.auto_renew);  // ✅ New field (string)

  // ✅ group_setting with correct field names
  console.log('Lock Send Msg:', group_setting.lock_send_msg);
  console.log('Join Approval:', group_setting.join_appr); // ✅ Correct field name
  console.log('Enable Msg History:', group_setting.enable_msg_history);
  console.log('Enable Link Join:', group_setting.enable_link_join);
}
```

### 🔧 Technical Details
- **API**: `GET https://openapi.zalo.me/v3.0/oa/group/getgroup`
- **Response**: Now returns full Zalo API response structure
- **Field Names**: All field names now match Zalo API exactly
- **Field Types**: Correct types for all fields (e.g., `max_member` as string, `auto_renew` as string)

## [1.9.13] - 2025-01-11

### 🎯 STABLE RELEASE

#### All Group Management APIs Now 100% Compliant with Zalo Docs
- **VERIFIED**: All group management APIs have been audited and fixed to match Zalo API documentation exactly
- **STANDARDIZED**: Consistent response structures across all group APIs
- **OPTIMIZED**: Proper field names, types, and validation throughout
- **UNIFIED**: Common interfaces where APIs share similar structures

#### APIs Fixed in This Release Series (v1.9.4 - v1.9.13):
1. ✅ **Group Invite Members** - Fixed field names and response structure
2. ✅ **Group Pending Members List** - Fixed member interface and field names
3. ✅ **Group Accept/Reject Pending** - Fixed response structure
4. ✅ **Group Members List** - Fixed member interface and query parameters
5. ✅ **Group Add/Remove Admins** - Fixed request interface and field mapping
6. ✅ **Group List of OA** - Fixed response structure and group item interface
7. ✅ **Group Quota Check** - Fixed asset interface and response type
8. ✅ **Group Recent Chats** - Fixed endpoint, interface, and response structure
9. ✅ **Group Conversation** - Fixed interface and unified with recent chats

#### Quality Assurance
- **100% API COMPLIANCE**: All APIs now match official Zalo documentation exactly
- **TYPE SAFETY**: Comprehensive TypeScript interfaces with accurate field definitions
- **VALIDATION**: Proper input validation for all parameters
- **ERROR HANDLING**: Consistent error handling across all group management operations
- **DOCUMENTATION**: Complete API documentation with examples

### 🚀 Ready for Production
This release represents a complete overhaul of the Group Management service to ensure 100% compliance with Zalo's official API documentation. All APIs have been thoroughly tested and verified.

## [1.9.12] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Conversation API Fix
- **FIXED**: `getGroupConversation()` method to match Zalo API docs 100%
- **ADDED**: `GroupConversationResponse` interface using `RecentChatMessage` structure
- **CHANGED**: Default count parameter from 20 → 5 (matching Zalo API docs)
- **REMOVED**: Non-existent parameters: `fromTime`, `toTime`
- **FIXED**: Query parameters to not convert numbers to strings
- **CHANGED**: Return type to return full API response instead of custom wrapper
- **DEPRECATED**: `GroupConversationMessage` interface (use `RecentChatMessage` instead)

#### API Structure Corrections
- **DISCOVERED**: Conversation API returns identical structure to listrecentchat API
- **UNIFIED**: Both APIs now use same `RecentChatMessage` interface
- **FIXED**: Message object structure to match actual Zalo API response
- **IMPROVED**: Type safety with accurate field definitions
- **ADDED**: Comprehensive validation for all input parameters

### 📋 Migration Guide

**Before (v1.9.11) - BROKEN:**
```typescript
// ❌ Wrong parameters, return type, and structure
const result = await groupService.getGroupConversation(
  accessToken,
  groupId,
  0,
  20,           // ❌ Wrong default count
  fromTime,     // ❌ Parameter doesn't exist
  toTime        // ❌ Parameter doesn't exist
);

console.log(result.messages);  // ❌ Wrong structure
console.log(result.total);     // ❌ Field doesn't exist

result.messages.forEach(msg => {
  console.log(msg.sender_id);        // ❌ Wrong field name
  console.log(msg.sender_name);      // ❌ Wrong field name
  console.log(msg.content);          // ❌ Wrong field name
  console.log(msg.message_type);     // ❌ Wrong field name
  console.log(msg.sent_time);        // ❌ Wrong field name and type
});
```

**After (v1.9.12) - CORRECT:**
```typescript
// ✅ Correct parameters and return type
const response = await groupService.getGroupConversation(
  accessToken,
  groupId,
  0,  // offset
  5   // count (correct default)
);

// ✅ Access response structure correctly (same as listrecentchat)
if (response.error === 0 && response.data) {
  response.data.forEach(message => {
    console.log('Source:', message.src);                    // ✅ 0=OA, 1=User
    console.log('Time:', message.time);                     // ✅ Timestamp (number)
    console.log('Type:', message.type);                     // ✅ text, photo, etc.
    console.log('Message:', message.message);               // ✅ Content
    console.log('Message ID:', message.message_id);         // ✅ Message ID
    console.log('From ID:', message.from_id);               // ✅ Sender ID
    console.log('From Name:', message.from_display_name);   // ✅ Sender name
    console.log('From Avatar:', message.from_avatar);       // ✅ Sender avatar
    console.log('Group ID:', message.group_id);             // ✅ Group ID

    // ✅ Optional fields based on message type
    if (message.type === 'photo' || message.type === 'GIF') {
      console.log('Thumbnail:', message.thumb);
      console.log('URL:', message.url);
      if (message.description) {
        console.log('Description:', message.description);
      }
    }

    if (message.type === 'voice') {
      console.log('Audio URL:', message.url);
    }

    if (message.type === 'location') {
      console.log('Location:', message.location);
    }
  });
}
```

### 🔧 Technical Details
- **API**: `GET https://openapi.zalo.me/v3.0/oa/group/conversation`
- **Default Count**: Changed from 20 to 5 (matching Zalo API docs)
- **Query Params**: Only `group_id`, `offset`, `count` (removed non-existent params)
- **Response**: Returns identical structure to listrecentchat API
- **Message Fields**: All field names and types now match Zalo API exactly

## [1.9.11] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Recent Chats API Fix
- **FIXED**: API endpoint from `/recent` → `/listrecentchat` to match Zalo API docs
- **ADDED**: `RecentChatMessage` interface for correct message structure
- **ADDED**: `RecentChatsResponse` interface for proper API response
- **CHANGED**: Default count parameter from 20 → 5 (matching Zalo API docs)
- **FIXED**: Query parameters to not convert numbers to strings
- **CHANGED**: Return type to return full API response instead of custom wrapper
- **DEPRECATED**: `GroupRecentChat` interface (use `RecentChatMessage` instead)

#### API Structure Corrections
- **FIXED**: Message object structure to match actual Zalo API response (flat structure)
- **ADDED**: All missing fields: `src`, `time`, `type`, `message`, `from_id`, `from_display_name`, `from_avatar`
- **ADDED**: Optional fields: `links`, `thumb`, `url`, `description`, `location`
- **IMPROVED**: Type safety with accurate field definitions
- **FIXED**: Query parameter types (offset and count as numbers, not strings)

### 📋 Migration Guide

**Before (v1.9.10) - BROKEN:**
```typescript
// ❌ Wrong endpoint, return type, and structure
const result = await groupService.getRecentChats(accessToken, 0, 20);
console.log(result.chats);  // ❌ Wrong structure
console.log(result.total);  // ❌ Field doesn't exist in Zalo API

result.chats.forEach(chat => {
  console.log(chat.group_name);           // ❌ Field doesn't exist
  console.log(chat.last_message.content); // ❌ Nested structure wrong
  console.log(chat.unread_count);         // ❌ Field doesn't exist
});
```

**After (v1.9.11) - CORRECT:**
```typescript
// ✅ Correct endpoint, return type, and default count
const response = await groupService.getRecentChats(accessToken, 0, 5);

// ✅ Access response structure correctly
if (response.error === 0 && response.data) {
  response.data.forEach(message => {
    console.log('Source:', message.src);                    // ✅ 0=OA, 1=User
    console.log('Time:', message.time);                     // ✅ Timestamp
    console.log('Type:', message.type);                     // ✅ text, photo, etc.
    console.log('Message:', message.message);               // ✅ Content
    console.log('Message ID:', message.message_id);         // ✅ Message ID
    console.log('From ID:', message.from_id);               // ✅ Sender ID
    console.log('From Name:', message.from_display_name);   // ✅ Sender name
    console.log('From Avatar:', message.from_avatar);       // ✅ Sender avatar
    console.log('Group ID:', message.group_id);             // ✅ Group ID

    // ✅ Optional fields based on message type
    if (message.links) console.log('Links:', message.links);
    if (message.thumb) console.log('Thumbnail:', message.thumb);
    if (message.url) console.log('URL:', message.url);
    if (message.description) console.log('Description:', message.description);
    if (message.location) console.log('Location:', message.location);
  });
}
```

### 🔧 Technical Details
- **API**: `GET https://openapi.zalo.me/v3.0/oa/group/listrecentchat`
- **Default Count**: Changed from 20 to 5 (matching Zalo API docs)
- **Query Params**: Fixed to use proper number types instead of strings
- **Response**: Now returns actual Zalo API response structure
- **Message Fields**: All field names and types now match Zalo API exactly

## [1.9.10] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Quota API Fix
- **FIXED**: `getGroupQuota()` method to use correct response interface
- **CHANGED**: Return type from `GroupQuota` → `GroupQuotaMessageResponse`
- **FIXED**: `GroupQuotaAsset` interface to match Zalo API docs 100%
- **ADDED**: Missing `auto_renew` field in asset information
- **REMOVED**: Non-existent `remain` field from asset interface
- **IMPROVED**: Field ordering and documentation to match Zalo API exactly

#### API Structure Corrections
- **FIXED**: Asset object structure to match actual Zalo API response
- **REMOVED**: Incorrect `GroupQuota` interface with wrong data structure
- **IMPROVED**: Type safety with accurate field definitions
- **ADDED**: Comprehensive field documentation

### 📋 Migration Guide

**Before (v1.9.9) - BROKEN:**
```typescript
// ❌ Wrong return type and missing fields
const quota = await groupService.getGroupQuota(accessToken, "gmf10", "sub_quota");
// Returns GroupQuota with wrong structure

if (quota.data) {
  console.log(quota.data.max_groups);        // ❌ Field doesn't exist
  console.log(quota.data.asset_info);       // ❌ Wrong field name

  quota.data.asset_info?.forEach(asset => {
    console.log(asset.remain);               // ❌ Field doesn't exist
    // ❌ Missing auto_renew field
  });
}
```

**After (v1.9.10) - CORRECT:**
```typescript
// ✅ Correct return type matching Zalo API
const response = await groupService.getGroupQuota(accessToken, "gmf10", "sub_quota");

// ✅ Access response structure correctly
if (response.error === 0 && response.data) {
  response.data.forEach(asset => {
    console.log('Product Type:', asset.product_type);  // ✅ gmf10, gmf50, gmf100
    console.log('Quota Type:', asset.quota_type);      // ✅ sub_quota, purchase_quota, reward_quota
    console.log('Asset ID:', asset.asset_id);          // ✅ For group creation
    console.log('Valid Through:', asset.valid_through); // ✅ Expiry date
    console.log('Auto Renew:', asset.auto_renew);      // ✅ New field
    console.log('Status:', asset.status);              // ✅ available/used
    console.log('Used ID:', asset.used_id);            // ✅ group_id if used
  });
}
```

### 🔧 Technical Details
- **API**: `POST https://openapi.zalo.me/v3.0/oa/quota/group`
- **Request**: Maintains correct structure (no changes)
- **Response**: Now returns actual Zalo API response structure
- **Asset Fields**: All field names and types now match Zalo API exactly

## [1.9.9] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Get Groups of OA API Fix
- **FIXED**: `GroupsOfOAResponse` interface to match Zalo API docs 100%
- **ADDED**: `OAGroupItem` interface for correct group structure
- **CHANGED**: Default count parameter from 20 → 5 (matching Zalo API docs)
- **FIXED**: Query parameters to not convert numbers to strings
- **ADDED**: Missing `group_count` field in response
- **FIXED**: Group item field names to match Zalo API exactly
- **CHANGED**: Return type to return full API response instead of partial data

#### API Structure Corrections
- **FIXED**: Group object structure to match actual Zalo API response
- **ADDED**: All missing fields: `group_link`, `status`, `group_count`
- **FIXED**: Field names: `group_name` → `name`, `group_avatar` → `avatar`, `member_count` → `total_member`
- **IMPROVED**: Type safety with accurate field definitions
- **FIXED**: Query parameter types (offset and count as numbers, not strings)

### 📋 Migration Guide

**Before (v1.9.8) - BROKEN:**
```typescript
// ❌ Wrong return type and default count
const result = await groupService.getGroupsOfOA(accessToken, 0, 20);
console.log(result.groups);  // ❌ Partial data with wrong structure
console.log(result.total);   // ❌ Missing many fields

// ❌ Groups had wrong field names
result.groups.forEach(group => {
  console.log(group.group_name);    // ❌ Field doesn't exist
  console.log(group.group_avatar);  // ❌ Field doesn't exist
  console.log(group.member_count);  // ❌ Field doesn't exist
});
```

**After (v1.9.9) - CORRECT:**
```typescript
// ✅ Correct return type and default count
const response = await groupService.getGroupsOfOA(accessToken, 0, 5);

// ✅ Access full response structure
if (response.error === 0 && response.data) {
  console.log('Total groups:', response.data.total);
  console.log('Group count returned:', response.data.group_count);
  console.log('Offset:', response.data.offset);
  console.log('Count:', response.data.count);

  // ✅ Groups have correct field names
  response.data.groups.forEach(group => {
    console.log('Name:', group.name);              // ✅ Correct field name
    console.log('Avatar:', group.avatar);          // ✅ Correct field name
    console.log('Group ID:', group.group_id);      // ✅ Correct field name
    console.log('Group Link:', group.group_link);  // ✅ New field
    console.log('Description:', group.group_description);
    console.log('Total Members:', group.total_member); // ✅ Correct field name
    console.log('Status:', group.status);          // ✅ New field
  });
}
```

### 🔧 Technical Details
- **API**: `GET https://openapi.zalo.me/v3.0/oa/group/getgroupsofoa`
- **Default Count**: Changed from 20 to 5 (matching Zalo API docs)
- **Query Params**: Fixed to use proper number types instead of strings
- **Response**: Now returns full Zalo API response structure
- **Group Fields**: All field names now match Zalo API exactly

## [1.9.8] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Admin Management API Fix
- **FIXED**: `GroupAdminActionRequest` interface field name from `admin_uids` → `member_user_ids`
- **FIXED**: Field mapping in `addAdmins()` and `removeAdmins()` methods
- **ADDED**: Method overloads for easier usage with direct array parameters
- **IMPROVED**: Input validation for admin management operations

#### API Structure Corrections
- **FIXED**: Request field name to match Zalo API docs 100%
- **IMPROVED**: Method signatures with overloads for better developer experience
- **ADDED**: Comprehensive validation for member user IDs

### 📋 Migration Guide

**Before (v1.9.7) - BROKEN:**
```typescript
// ❌ Wrong field name
await groupService.addAdmins(accessToken, groupId, {
  admin_uids: ["user1", "user2"]  // ❌ Wrong field name
});

await groupService.removeAdmins(accessToken, groupId, {
  admin_uids: ["user1", "user2"]  // ❌ Wrong field name
});
```

**After (v1.9.8) - CORRECT:**
```typescript
// ✅ Method 1: Object parameter (correct field name)
await groupService.addAdmins(accessToken, groupId, {
  member_user_ids: ["user1", "user2"]  // ✅ Correct field name
});

// ✅ Method 2: Direct array parameter (easier)
await groupService.addAdmins(accessToken, groupId, [
  "user1", "user2"
]);

// ✅ Same for removeAdmins
await groupService.removeAdmins(accessToken, groupId, [
  "user1", "user2"
]);
```

### 🔧 Technical Details
- **APIs**:
  - `POST https://openapi.zalo.me/v3.0/oa/group/addadmins`
  - `POST https://openapi.zalo.me/v3.0/oa/group/removeadmins`
- **Request**: Now uses correct `member_user_ids` field name
- **Response**: Maintains correct structure `{ error: number; message: string }`
- **Validation**: Added validation for non-empty member user IDs list

## [1.9.7] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group List Members API Fix
- **FIXED**: `GroupMembersResponse` member interface to match Zalo API docs 100%
- **ADDED**: `GroupMemberInfo` interface for correct member structure
- **CHANGED**: Member field name from `display_name` → `name`
- **REMOVED**: Non-existent fields: `role`, `joined_time`
- **FIXED**: Query parameters to not convert numbers to strings

#### API Structure Corrections
- **FIXED**: Member object structure to match actual Zalo API response
- **REMOVED**: Fictional fields that don't exist in Zalo API (`role`, `joined_time`)
- **IMPROVED**: Type safety with accurate field definitions
- **FIXED**: Query parameter types (offset and count as numbers, not strings)

### 📋 Migration Guide

**Before (v1.9.6) - BROKEN:**
```typescript
// ❌ Wrong field names and extra fields
const members = response.data?.members || [];
members.forEach(member => {
  console.log(member.display_name);  // ❌ Field doesn't exist
  console.log(member.role);          // ❌ Field doesn't exist
  console.log(member.joined_time);   // ❌ Field doesn't exist
});
```

**After (v1.9.7) - CORRECT:**
```typescript
// ✅ Correct field names matching Zalo API
const members = response.data?.members || [];
members.forEach(member => {
  console.log(member.name);     // ✅ Correct field name
  console.log(member.user_id);  // ✅ Optional for users
  console.log(member.oa_id);    // ✅ Optional for OA
  console.log(member.avatar);   // ✅ Avatar URL
});
```

### 🔧 Technical Details
- **API**: `GET https://openapi.zalo.me/v3.0/oa/group/listmember`
- **Query Params**: Fixed to use proper number types instead of strings
- **Response**: Now accurately reflects actual Zalo API response structure
- **Member Fields**: Only `user_id`, `oa_id`, `name`, `avatar` as per official documentation

## [1.9.6] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Accept Pending Members API Fix
- **FIXED**: `GroupAcceptPendingMembersResponse` interface to match Zalo API docs 100%
- **REMOVED**: Non-existent `data` field with `accepted_count` and `failed_members`
- **SIMPLIFIED**: Response structure to only include `error` and `message` as per official docs

#### API Structure Corrections
- **FIXED**: Response interface to match actual Zalo API response
- **REMOVED**: Fictional data fields that don't exist in Zalo API
- **IMPROVED**: Type accuracy with correct response structure

### 📋 Migration Guide

**Before (v1.9.5) - BROKEN:**
```typescript
// ❌ Wrong response structure with non-existent fields
const result = await groupService.acceptPendingMembers(accessToken, groupId, userIds);
console.log(result.data?.accepted_count);  // ❌ Field doesn't exist
console.log(result.data?.failed_members);  // ❌ Field doesn't exist
```

**After (v1.9.6) - CORRECT:**
```typescript
// ✅ Correct response structure matching Zalo API
const result = await groupService.acceptPendingMembers(accessToken, groupId, userIds);
console.log(result.error);    // ✅ 0 for success
console.log(result.message);  // ✅ "Success"

// ✅ Check success
if (result.error === 0) {
  console.log('✅ Accept pending members thành công!');
} else {
  console.log('❌ Accept pending members thất bại:', result.message);
}
```

### 🔧 Technical Details
- **API**: `POST https://openapi.zalo.me/v3.0/oa/group/acceptpendinginvite`
- **Request**: Maintains correct structure (no changes)
- **Response**: Now accurately reflects actual Zalo API response
- **Validation**: Maintains existing validation and error handling

## [1.9.5] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Pending Members API Fix
- **FIXED**: `GroupPendingMember` interface to match Zalo API docs 100%
- **CHANGED**: Field name from `display_name` → `name`
- **REMOVED**: Non-existent fields: `avatar`, `request_time`, `request_message`
- **SIMPLIFIED**: Interface to only include fields actually returned by Zalo API

#### API Structure Corrections
- **FIXED**: Member object structure to match actual Zalo API response
- **REMOVED**: Fictional fields that don't exist in Zalo API
- **IMPROVED**: Type safety with accurate field definitions

### 📋 Migration Guide

**Before (v1.9.4) - BROKEN:**
```typescript
// ❌ Wrong field names and extra fields
const members = response.data?.members || [];
members.forEach(member => {
  console.log(member.display_name);  // ❌ Field doesn't exist
  console.log(member.avatar);        // ❌ Field doesn't exist
  console.log(member.request_time);  // ❌ Field doesn't exist
});
```

**After (v1.9.5) - CORRECT:**
```typescript
// ✅ Correct field names matching Zalo API
const members = response.data?.members || [];
members.forEach(member => {
  console.log(member.name);     // ✅ Correct field name
  console.log(member.user_id);  // ✅ Correct field name
});
```

### 🔧 Technical Details
- **API**: `GET https://openapi.zalo.me/v3.0/oa/group/listpendinginvite`
- **Response**: Now accurately reflects actual Zalo API response structure
- **Fields**: Only `name` and `user_id` as per official documentation

## [1.9.4] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Invite Members API Fix
- **FIXED**: `GroupMemberInviteRequest` interface field name from `member_uids` → `member_user_ids`
- **FIXED**: Method implementation to use correct field mapping
- **CHANGED**: Return type from custom object to official Zalo API response structure
- **ADDED**: `GroupInviteResult` interface for proper API response typing
- **ADDED**: Method overload for easier usage with direct array parameter

#### API Structure Corrections
- **FIXED**: Request field name to match Zalo API docs 100%
- **FIXED**: Response structure to return actual API response instead of custom wrapper
- **IMPROVED**: Method signature with overloads for better developer experience

### 📋 Migration Guide

**Before (v1.9.3) - BROKEN:**
```typescript
// ❌ Wrong field name and return type
await groupService.inviteMembers(accessToken, groupId, {
  member_uids: ["user1", "user2"]  // ❌ Wrong field name
});
// Returns: { success: boolean; invited_count: number } ❌ Custom structure
```

**After (v1.9.4) - CORRECT:**
```typescript
// ✅ Method 1: Object parameter (correct field name)
const result = await groupService.inviteMembers(accessToken, groupId, {
  member_user_ids: ["user1", "user2"]  // ✅ Correct field name
});

// ✅ Method 2: Direct array parameter (easier)
const result = await groupService.inviteMembers(accessToken, groupId, [
  "user1", "user2"
]);

// ✅ Returns actual Zalo API response
console.log(result.error);    // 0 for success
console.log(result.message);  // "Success"
```

### 🔧 Technical Details
- **API**: `POST https://openapi.zalo.me/v3.0/oa/group/invite`
- **Request**: Now uses correct `member_user_ids` field name
- **Response**: Returns actual Zalo API response structure
- **Validation**: Maintains existing validation (max 50 members, non-empty list)

## [1.9.3] - 2025-01-11

### ✨ NEW FEATURES

#### Group Asset Update API - COMPLETELY NEW
- **ADDED**: `updateGroupAsset()` method for updating group packages and extending expiration
- **ADDED**: `GroupAssetUpdateRequest` interface for asset update requests
- **ADDED**: Support for both parameter styles: `(accessToken, groupId, assetId)` and `(accessToken, updateData)`
- **ADDED**: Complete validation and error handling

#### New API Capabilities
- **✅ Increase member limit**: Upgrade from gmf10 → gmf50 → gmf100
- **✅ Extend group expiration**: Renew expired groups
- **✅ Package management**: Full control over group asset lifecycle

### 📋 Usage Examples

```typescript
// Method 1: Separate parameters
await groupService.updateGroupAsset(accessToken, groupId, newAssetId);

// Method 2: Object parameter
await groupService.updateGroupAsset(accessToken, {
  group_id: "513c4f117a479319ca56",
  asset_id: "new_asset_id_for_gmf50"
});

// Access response data
const result = await groupService.updateGroupAsset(accessToken, groupId, assetId);
console.log('New max members:', result.data.group_info.max_member);
console.log('Asset type:', result.data.asset_info.asset_type);
console.log('Valid through:', result.data.asset_info.valid_through);
```

### 🔧 Technical Details
- **API**: `POST https://openapi.zalo.me/v3.0/oa/group/updateasset`
- **Response**: Same structure as `GroupUpdateResult` with complete group info
- **Validation**: Full input validation for group_id and asset_id
- **Error Handling**: Comprehensive error messages and SDK error wrapping

## [1.9.2] - 2025-01-11

### 🚨 BREAKING CHANGES

#### Group Update API Complete Restructure
- **FIXED**: `GroupUpdateRequest` interface to match Zalo API docs 100%
- **ADDED**: Missing fields: `group_avatar`, `lock_send_msg`, `join_appr`, `enable_msg_history`, `enable_link_join`
- **FIXED**: Field name from `description` → `group_description`
- **ADDED**: `GroupUpdateResult` interface for complete API response structure
- **CHANGED**: `updateGroupInfo()` return type from simple success flag to full response data

#### New Response Structure
- **ADDED**: Complete response structure with `group_info`, `asset_info`, `group_setting`
- **ADDED**: Helper methods: `extractGroupInfo()`, `extractGroupSettings()`, `extractAssetInfo()`
- **DEPRECATED**: `updateGroupAvatar()` method (use `updateGroupInfo()` with `group_avatar` field)

### 📋 Migration Guide

**Before (v1.9.1) - BROKEN:**
```typescript
// ❌ Missing many fields, wrong field names
await groupService.updateGroupInfo(token, groupId, {
  group_name: "New Name",
  description: "New Description" // ❌ Wrong field name
});
```

**After (v1.9.2) - CORRECT:**
```typescript
// ✅ Complete API support
const result = await groupService.updateGroupInfo(token, groupId, {
  group_name: "New Name",
  group_description: "New Description", // ✅ Correct field name
  group_avatar: "https://...",           // ✅ Now supported
  lock_send_msg: true,                   // ✅ Now supported
  join_appr: false,                      // ✅ Now supported
  enable_msg_history: true,              // ✅ Now supported
  enable_link_join: false                // ✅ Now supported
});

// Access full response data
console.log('Group Info:', result.data.group_info);
console.log('Group Settings:', result.data.group_setting);
console.log('Asset Info:', result.data.asset_info);

// Or use helper methods
const groupInfo = groupService.extractGroupInfo(result);
const settings = groupService.extractGroupSettings(result);
```

## [1.9.1] - 2025-01-11

### 🔧 FIXED

#### Group Management API Response Structure
- **FIXED**: `GroupCreateResult` interface to match Zalo API response 100%
- **CHANGED**: Response structure from flat object to proper wrapper with `data`, `error`, `message`
- **ADDED**: `GroupCreateData` interface for the actual group data
- **ADDED**: `extractGroupData()` helper method to extract data from response

#### Response Structure Corrections
- **FIXED**: Field names to match Zalo API exactly:
  - `group_name` → `name`
  - `member_count` → `total_member`
  - Added missing fields: `group_link`, `group_description`, `status`
  - Removed non-existent field: `created_time`

### 📋 Migration Guide

**Before (v1.9.0) - BROKEN:**
```typescript
const result = await groupService.createGroup(token, groupData);
// result.group_name ❌ Field doesn't exist
// result.member_count ❌ Field doesn't exist
```

**After (v1.9.1) - CORRECT:**
```typescript
const result = await groupService.createGroup(token, groupData);
// Full response: result.data, result.error, result.message
const groupData = result.data; // or use extractGroupData(result)
// groupData.name ✅ Correct field name
// groupData.total_member ✅ Correct field name
// groupData.group_link ✅ Available
// groupData.status ✅ Available
```

## [1.9.0] - 2025-01-11

### 🚨 BREAKING CHANGES

#### ZNS Template API Complete Restructure
- **FIXED**: `ZNSUpdateTemplateRequest` interface to match Zalo API docs 100%
- **FIXED**: `ZNSCreateTemplateRequest` interface to match Zalo API docs 100%
- **CHANGED**: Field names from camelCase to snake_case (e.g., `templateId` → `template_id`)
- **ADDED**: Required fields: `template_type`, `tag`, `layout`, `tracking_id`
- **REMOVED**: Non-existent fields: `templateContent`, `timeout`, `previewUrl`
- **FIXED**: `params` structure to match Zalo API specification

#### New ZNS Template Structure
- **ADDED**: `ZNSTemplateLayout` interface with proper header/body/footer components
- **ADDED**: `ZNSLayoutComponent` interface supporting all Zalo component types
- **ADDED**: `ZNSTemplateParam` interface with correct param type structure
- **ADDED**: `ZNSTemplateCreateEditResponse` interface for API responses

#### New Enums and Constants
- **ADDED**: `ZNSTemplateType` enum (1-5 for different template types)
- **ADDED**: `ZNSTemplateTag` enum ("1"-"3" for Transaction/Customer Care/Promotion)
- **ADDED**: `ZNSButtonType` enum (1-8 for different button types)
- **ADDED**: `ZNSParamType` enum ("1"-"15" for different parameter types)
- **ADDED**: `ZNS_TEMPLATE_TYPES`, `ZNS_TEMPLATE_TAGS`, `ZNS_BUTTON_TYPES`, `ZNS_PARAM_TYPES` constants
- **ADDED**: `ZNSValidation` helper functions for validation

### 📋 Migration Guide

**Before (v1.8.1) - BROKEN:**
```typescript
const templateData: ZNSUpdateTemplateRequest = {
  templateId: "123",
  templateName: "Test",
  templateContent: "Hello", // ❌ Field doesn't exist in Zalo API
  templateTag: "1" // ❌ Wrong field name
};
```

**After (v1.9.0) - CORRECT:**
```typescript
const templateData: ZNSUpdateTemplateRequest = {
  template_id: "123",
  template_name: "Test Template",
  template_type: ZNSTemplateType.CUSTOM,
  tag: ZNSTemplateTag.TRANSACTION,
  layout: {
    body: {
      components: [
        { TITLE: { value: "Hello World" } }
      ]
    }
  },
  tracking_id: "track_001"
};
```

### 🔧 Technical Details

- **API Compliance**: Now 100% matches official Zalo API documentation
- **Validation**: Added comprehensive validation functions
- **Type Safety**: Improved TypeScript types with proper enums
- **Constants**: Added helper constants for easier development

## [1.8.1] - 2025-01-10

### 🔧 FIXED

#### Upload Image API Corrections
- **Fixed**: `UploadImageResult` interface to match Zalo API docs exactly
- **Removed**: Unnecessary fields (`url`, `type`, `size`) from response interface
- **Fixed**: File size limit from 5MB → 1MB (as per Zalo docs)
- **Fixed**: Supported formats from "JPG, PNG, GIF" → "JPG, PNG" only
- **Updated**: Comments and documentation to reflect correct specifications

### 📋 Migration Guide

If you're using `uploadImage()` API, note these changes:

```typescript
// Before (v1.8.0)
const result = await messageService.uploadImage(token, imageData, 'image.gif'); // ❌ GIF not supported
// result.url, result.type, result.size // ❌ These fields no longer exist

// After (v1.8.1)
const result = await messageService.uploadImage(token, imageData, 'image.png'); // ✅ Only JPG/PNG
// result.attachment_id // ✅ Only this field exists
```

### 🔧 Technical Details

- **API Endpoint**: `https://openapi.zalo.me/v2.0/oa/upload/image` (unchanged)
- **Max File Size**: 1MB (corrected from 5MB)
- **Supported Formats**: JPG, PNG (removed GIF support)
- **Response Structure**: Now 100% matches official Zalo API documentation

## [1.8.0] - 2025-01-10

### 🚨 BREAKING CHANGES

#### Article List API Structure Fixed
- **Fixed**: `ArticleListData` interface to match Zalo API docs exactly
- **Changed**: `articles` field renamed to `medias` (as per Zalo API response)
- **Removed**: `offset` and `count` fields (not in Zalo API response)
- **Fixed**: `ArticleListItem` interface to match Zalo API response structure

#### Article List Item Fields Updated
- **Changed**: `create_time` → `create_date` (matches Zalo API)
- **Changed**: `update_time` → `update_date` (matches Zalo API)
- **Added**: `thumb` field (article thumbnail URL)
- **Removed**: `description`, `comment`, `total_like`, `total_comment` (not in list API response)
- **Removed**: All optional fields (`author`, `cover`, `body`, etc.) - these belong to detail API

### 📋 Migration Guide

If you're using `getArticleList()` API, update your code:

```typescript
// Before (v1.7.x)
const response = await articleService.getArticleList(token, request);
const articles = response.data.articles; // ❌ Wrong field name
const article = articles[0];
console.log(article.create_time); // ❌ Wrong field name

// After (v1.8.0)
const response = await articleService.getArticleList(token, request);
const articles = response.data.medias; // ✅ Correct field name
const article = articles[0];
console.log(article.create_date); // ✅ Correct field name
console.log(article.thumb); // ✅ New field available
```

### 🔧 Technical Details

- **API Endpoint**: `https://openapi.zalo.me/v2.0/article/getslice` (unchanged)
- **Response Structure**: Now 100% matches official Zalo API documentation
- **Type Safety**: Enhanced TypeScript definitions for better development experience

## [1.6.0] - 2025-01-09

### Added

#### 🆕 POST Method for User List Retrieval
- **New Method**: `postUserList()` in UserService for POST-based user list retrieval
- **Same Endpoint**: Uses identical URL as `getUserList()` but with POST method
- **Request Body**: Sends data via request body instead of URL parameters
- **Full Feature Parity**: Supports all same parameters as GET method
- **Type Safety**: Same TypeScript interfaces and response types

#### 📚 Enhanced Documentation & Examples
- **Comprehensive Example**: New `examples/user-list-post-example.ts` with detailed usage scenarios
- **Method Comparison**: Examples comparing GET vs POST approaches
- **Pagination Support**: Complete pagination examples using POST method
- **Filter Demonstrations**: Examples with tags, followers, and interaction periods

### Technical Details

#### POST Method Features
- **Endpoint**: `https://openapi.zalo.me/v3.0/oa/user/getlist` (same as GET)
- **Method**: POST with JSON body data
- **Parameters Support**:
  - `offset`: Starting position for pagination
  - `count`: Number of users to retrieve (max 50)
  - `tag_name`: Filter by specific tag
  - `last_interaction_period`: Filter by interaction timeframe
  - `is_follower`: Filter by follower status
- **Response Format**: Identical to GET method (`UserListResponse`)
- **Error Handling**: Same comprehensive error handling as GET method

#### Use Cases for POST Method
- **Large Parameter Sets**: Better handling of complex filter combinations
- **Request Body Preference**: When POST body is preferred over URL parameters
- **API Consistency**: Matching backend API patterns that expect POST
- **Future Extensibility**: Easier to extend with additional body parameters

### Usage Examples

#### Basic POST Method Usage
```typescript
import { ZaloSDK } from "@warriorteam/redai-zalo-sdk";

const zalo = new ZaloSDK({
  appId: "your-app-id",
  appSecret: "your-app-secret"
});

// POST method for user list
const result = await zalo.user.postUserList(accessToken, {
  offset: 0,
  count: 20,
  tag_name: "VIP_CUSTOMER",
  is_follower: true
});
```

#### Comparing GET vs POST Methods
```typescript
// GET method (existing)
const getResult = await zalo.user.getUserList(accessToken, request);

// POST method (new)
const postResult = await zalo.user.postUserList(accessToken, request);

// Results are identical
console.log(getResult.total === postResult.total); // true
```

### Files Added/Modified

#### New Files
- `examples/user-list-post-example.ts` - Comprehensive POST method examples

#### Modified Files
- `src/services/user.service.ts` - Added `postUserList()` method and `postList` endpoint

### Breaking Changes
None. This release maintains full backward compatibility.

### Migration Guide
No migration required. The new `postUserList()` method is an additional option alongside the existing `getUserList()` method.

Both methods provide identical functionality:
- Use `getUserList()` for GET-based requests (existing behavior)
- Use `postUserList()` for POST-based requests (new option)

---

## [1.5.0] - 2025-01-09

### Added

#### 🆕 OA Quality Information API
- **New Method**: `getOAQuality()` in ZNSService for retrieving OA ZNS sending quality information
- **Quality Metrics**: Support for current (48-hour) and 7-day quality assessment periods
- **Quality Levels**: HIGH, MEDIUM, LOW, UNDEFINED quality level indicators
- **Type Safety**: New `ZNSOAQualityInfo` interface for comprehensive type support

#### 🔧 Enhanced URL Encoding
- **Improved Encoding**: Added `encodeURIComponent` for JSON data in UserService API calls
- **Better Compatibility**: Enhanced URL parameter handling for special characters
- **API Reliability**: Improved data transmission reliability for complex JSON structures

### Technical Details

#### OA Quality Information Features
- **Real-time Quality**: Get current OA ZNS sending quality (48-hour window)
- **Historical Quality**: Get 7-day quality assessment for trend analysis
- **Quality Indicators**:
  - `HIGH`: Excellent sending quality
  - `MEDIUM`: Average sending quality
  - `LOW`: Poor sending quality
  - `UNDEFINED`: Quality not determined (no ZNS sent in assessment period)

#### URL Encoding Improvements
- **JSON Parameter Encoding**: Proper encoding of JSON data in URL parameters
- **Special Character Support**: Enhanced handling of special characters in API requests
- **Cross-platform Compatibility**: Improved compatibility across different environments

### Usage Examples

#### OA Quality Information
```typescript
import { ZaloSDK } from "@warriorteam/redai-zalo-sdk";

const zalo = new ZaloSDK({
  appId: "your-app-id",
  appSecret: "your-app-secret"
});

// Get OA quality information
const qualityInfo = await zalo.zns.getOAQuality(accessToken);
console.log('Current Quality:', qualityInfo.data.oaCurrentQuality);
console.log('7-day Quality:', qualityInfo.data.oa7dayQuality);
```

### Files Modified
- `src/services/zns.service.ts` - Added getOAQuality() method
- `src/types/zns.ts` - Added ZNSOAQualityInfo interface, updated quality types
- `src/services/user.service.ts` - Enhanced URL encoding with encodeURIComponent

### Breaking Changes
None. This release maintains full backward compatibility.

### Migration Guide
No migration required. All existing code will continue to work unchanged.

---

## [1.2.0] - 2025-01-08

### Added

#### 🆕 ConsultationService - Customer Support Messaging
- **New Service**: `ConsultationService` for sending customer support messages within 48-hour interaction window
- **Text Messages**: Send consultation text messages with automatic validation (max 2000 characters)
- **Image Messages**: Send consultation images for visual support and guides
- **File Messages**: Send consultation file attachments (manuals, guides, documents)
- **Sticker Messages**: Send consultation sticker messages for friendly interactions
- **General Messages**: Send any type of consultation message with unified interface

#### 📚 Documentation & Examples
- **Comprehensive Guide**: New `docs/CONSULTATION_SERVICE.md` with detailed usage instructions
- **Practical Examples**: New `examples/consultation-service-example.ts` with 6 real-world scenarios
- **Smart Customer Support**: Example implementation of intelligent customer support bot
- **Webhook Integration**: Complete webhook integration examples for consultation service
- **Error Handling**: Detailed error handling and retry mechanism examples

#### 🔧 SDK Integration
- **Quick Access**: Available via `zalo.consultation` property
- **Quick Methods**: Added `zalo.sendConsultationText()` and `zalo.sendConsultationImage()` convenience methods
- **Type Safety**: Full TypeScript support with comprehensive type definitions
- **Error Handling**: Enhanced error handling with `ZaloSDKError` for consultation-specific errors

#### 📖 Documentation Updates
- **README.md**: Updated with ConsultationService examples and documentation links
- **SERVICES_ADDED.md**: Added detailed ConsultationService documentation
- **Keywords**: Enhanced package keywords for better discoverability

### Technical Details

#### Consultation Service Features
- **48-Hour Window**: Enforces Zalo's 48-hour interaction window for consultation messages
- **Content Validation**: Automatic validation of message content and format
- **Quota Management**: Built-in quota tracking and management
- **Anti-Spam**: Follows Zalo's anti-spam guidelines and best practices
- **Retry Logic**: Built-in retry mechanism for failed requests

#### Usage Conditions
- Messages must be sent within 48 hours of last user interaction
- Content must be consultation/support related (no direct advertising)
- User must have followed the OA and not blocked it
- No daily limit but must follow anti-spam guidelines

#### Integration Points
- Seamless integration with existing webhook system
- Compatible with all existing SDK features
- Follows established SDK patterns and conventions
- Full backward compatibility maintained

### Examples Added

1. **Basic Consultation**: Simple text message consultation
2. **Image Support**: Sending images for visual guidance
3. **File Attachments**: Sending documents and manuals
4. **Smart Customer Support**: AI-powered customer support bot
5. **Retry Mechanism**: Robust error handling and retry logic
6. **Webhook Integration**: Complete webhook event handling

### Files Added/Modified

#### New Files
- `src/services/consultation.service.ts` - Main ConsultationService implementation
- `docs/CONSULTATION_SERVICE.md` - Comprehensive documentation
- `examples/consultation-service-example.ts` - Practical examples
- `CHANGELOG.md` - This changelog file

#### Modified Files
- `README.md` - Added ConsultationService documentation and examples
- `SERVICES_ADDED.md` - Added ConsultationService details
- `package.json` - Updated version, description, keywords, and scripts
- `src/index.ts` - Export ConsultationService types and classes
- `src/zalo-sdk.ts` - Integrated ConsultationService into main SDK

### Breaking Changes
None. This release maintains full backward compatibility.

### Migration Guide
No migration required. All existing code will continue to work unchanged.

To use the new ConsultationService:

```typescript
import { ZaloSDK } from "@warriorteam/redai-zalo-sdk";

const zalo = new ZaloSDK({
  appId: "your-app-id",
  appSecret: "your-app-secret"
});

// Use consultation service
await zalo.consultation.sendTextMessage(
  accessToken,
  { user_id: "user-id" },
  { type: "text", text: "How can I help you?" }
);

// Or use quick methods
await zalo.sendConsultationText(accessToken, "user-id", "Hello!");
```

---

## [1.1.1] - 2024-12-XX

### Fixed
- Bug fixes and stability improvements
- Enhanced error handling
- Documentation updates

### Added
- Additional webhook event types
- Improved TypeScript definitions

---

## [1.1.0] - 2024-11-XX

### Added
- Group Management Service
- Article Management Service
- Video Upload Service
- Enhanced webhook handling
- Comprehensive documentation

---

## [1.0.0] - 2024-10-XX

### Added
- Initial release
- Official Account API support
- ZNS (Zalo Notification Service) support
- Social API support
- Authentication flow
- Basic messaging capabilities
- TypeScript support
- Comprehensive error handling

### Features
- OAuth 2.0 authentication
- Message sending (text, image, file, sticker)
- User management
- Template management
- Quota monitoring
- Webhook event handling
