UNPKG

@warriorteam/redai-zalo-sdk

Version:

Comprehensive TypeScript/JavaScript SDK for Zalo APIs - Official Account v3.0, ZNS with Full Type Safety, Consultation Service, Broadcast Service, Group Messaging with List APIs, Social APIs, Enhanced Article Management, Promotion Service v3.0 with Multip

2,373 lines (2,366 loc) 377 kB
import { AxiosInstance } from 'axios'; /** * Common types and interfaces for Zalo SDK */ /** * Standard Zalo API response wrapper */ interface ZaloResponse<T = any> { /** * Error code (0 = success) */ error: number; /** * Response message */ message: string; /** * Response data */ data?: T; } /** * Zalo API error response */ interface ZaloErrorResponse { /** * Error code */ error: number; /** * Error name */ error_name?: string; /** * Error reason */ error_reason?: string; /** * Error description */ error_description?: string; /** * Reference documentation link */ ref_doc?: string; } /** * Union type for Zalo API responses */ type ZaloApiResponse<T> = ZaloResponse<T> | (ZaloErrorResponse & Partial<T>); /** * SDK Configuration */ interface ZaloSDKConfig { /** * Application ID */ appId: string; /** * Application Secret */ appSecret: string; /** * API timeout in milliseconds (default: 30000) */ timeout?: number; /** * Enable debug logging (default: false) */ debug?: boolean; /** * Custom API base URL (optional) */ apiBaseUrl?: string; /** * Retry configuration */ retry?: { /** * Number of retry attempts (default: 3) */ attempts?: number; /** * Delay between retries in milliseconds (default: 1000) */ delay?: number; }; } /** * HTTP method types */ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; /** * Request configuration */ interface RequestConfig { /** * HTTP method */ method: HttpMethod; /** * Request URL */ url: string; /** * Request headers */ headers?: Record<string, string>; /** * Query parameters */ params?: Record<string, any>; /** * Request body data */ data?: any; /** * Request timeout */ timeout?: number; } /** * Pagination parameters */ interface PaginationParams { /** * Offset for pagination */ offset?: number; /** * Number of items per page */ count?: number; /** * Maximum items per page (default: 50) */ limit?: number; } /** * Paginated response */ interface PaginatedResponse<T> { /** * Array of items */ items: T[]; /** * Total number of items */ total: number; /** * Current offset */ offset: number; /** * Number of items in current page */ count: number; /** * Whether there are more items */ hasMore: boolean; /** * Next offset for pagination */ nextOffset?: number; } /** * File upload information */ interface FileUpload { /** * File buffer or stream */ file: Buffer | NodeJS.ReadableStream; /** * Original filename */ filename: string; /** * MIME type */ mimetype: string; /** * File size in bytes */ size?: number; } /** * Attachment information */ interface Attachment { /** * Attachment ID from Zalo */ attachment_id: string; /** * File URL */ url: string; /** * File type */ type?: string; /** * File size in bytes */ size?: number; } /** * SDK Error class */ declare class ZaloSDKError extends Error { readonly code: number; readonly details?: any; constructor(message: string, code?: number, details?: any); } /** * Logger interface */ interface Logger { debug(message: string, ...args: any[]): void; info(message: string, ...args: any[]): void; warn(message: string, ...args: any[]): void; error(message: string, ...args: any[]): void; } /** * Default console logger implementation */ declare class ConsoleLogger implements Logger { private readonly enableDebug; constructor(enableDebug?: boolean); debug(message: string, ...args: any[]): void; info(message: string, ...args: any[]): void; warn(message: string, ...args: any[]): void; error(message: string, ...args: any[]): void; } /** * Authentication related types and interfaces */ /** * Access token information */ interface AccessToken { /** * Access token string */ access_token: string; /** * Token expiration time in seconds */ expires_in: number; /** * Refresh token (if available) */ refresh_token?: string; } /** * Refresh token response */ interface RefreshTokenResponse { /** * New access token */ access_token: string; /** * Token expiration time in seconds */ expires_in: number; /** * New refresh token (if available) */ refresh_token?: string; } /** * OAuth authorization parameters */ interface OAuthParams { /** * Application ID */ app_id: string; /** * Redirect URI */ redirect_uri: string; /** * OAuth state parameter */ state?: string; /** * Code verifier for PKCE (Social API) */ code_verifier?: string; /** * Code challenge for PKCE (Social API) */ code_challenge?: string; /** * Code challenge method for PKCE (Social API) */ code_challenge_method?: 'S256' | 'plain'; } /** * Authorization code exchange parameters */ interface AuthCodeParams { /** * Application ID */ app_id: string; /** * Application secret */ app_secret: string; /** * Authorization code */ code: string; /** * Redirect URI (must match the one used in authorization) */ redirect_uri: string; /** * Code verifier for PKCE (supports both Social API and Official Account API) */ code_verifier?: string; } /** * Refresh token parameters */ interface RefreshTokenParams { /** * Application ID */ app_id: string; /** * Application secret */ app_secret: string; /** * Refresh token */ refresh_token: string; } /** * Social user information from Zalo */ interface SocialUserInfo$1 { /** * User ID */ id: string; /** * Display name */ name: string; /** * Profile picture */ picture?: { data: { url: string; }; }; /** * Gender */ gender?: string; /** * Birthday */ birthday?: string; /** * Location */ location?: { name: string; }; /** * Whether the account is sensitive (under 18) */ is_sensitive?: boolean; } /** * Token validation result */ interface TokenValidation { /** * Whether the token is valid */ valid: boolean; /** * Token expiration timestamp */ expires_at?: number; /** * Associated user information (if available) */ user_info?: SocialUserInfo$1; } /** * Authentication scope for different APIs */ declare enum AuthScope { /** * Official Account API scope */ OA = "oa", /** * Social API scope */ SOCIAL = "social", /** * ZNS (Zalo Notification Service) scope */ ZNS = "zns" } /** * Authentication method */ declare enum AuthMethod { /** * OAuth 2.0 Authorization Code flow */ AUTHORIZATION_CODE = "authorization_code", /** * Refresh token flow */ REFRESH_TOKEN = "refresh_token" } /** * PKCE (Proof Key for Code Exchange) configuration */ interface PKCEConfig { /** * Code verifier */ code_verifier: string; /** * Code challenge */ code_challenge: string; /** * Code challenge method */ code_challenge_method: 'S256' | 'plain'; } /** * Authentication URLs */ interface AuthUrls { /** * Official Account authorization URL */ oa_auth_url: string; /** * Social API authorization URL */ social_auth_url: string; /** * Token exchange URL */ token_url: string; /** * Token refresh URL */ refresh_url: string; } /** * Official Account authorization result */ interface OAAuthResult { /** * Authorization URL */ url: string; /** * State parameter used (auto-generated if not provided) */ state: string; /** * PKCE configuration used (if PKCE was enabled) */ pkce?: PKCEConfig; } /** * Official Account (OA) related types and interfaces */ /** * Official Account information */ interface OAInfo { /** * Official Account ID */ oa_id: string; /** * OA name */ name: string; /** * OA description */ description: string; /** * OA alias */ oa_alias: string; /** * Verification status */ is_verified: boolean; /** * OA type (number) */ oa_type: number; /** * Category name */ cate_name: string; /** * Number of followers */ num_follower: number; /** * Avatar URL */ avatar: string; /** * Cover image URL */ cover: string; /** * Package name */ package_name: string; /** * Package expiration date */ package_valid_through_date: string; /** * Package auto-renewal date */ package_auto_renew_date: string; /** * Linked Zalo Cloud Account */ linked_ZCA: string; } /** * Message quota information */ interface MessageQuota { /** * Daily quota limit */ daily_quota: number; /** * Remaining quota for today */ remaining_quota: number; /** * Quota type (e.g., "free", "paid") */ quota_type: string; /** * Quota reset time (Unix timestamp) */ reset_time: number; } /** * Detailed quota information request */ interface QuotaMessageRequest { /** * Quota owner (OA or APP) */ quota_owner: string; /** * Product type */ product_type?: 'cs' | 'transaction' | 'gmf10' | 'gmf50' | 'gmf100'; /** * Quota type */ quota_type?: 'sub_quota' | 'purchase_quota' | 'reward_quota'; } /** * Quota asset information */ interface QuotaAsset { /** * Asset ID */ asset_id: string; /** * Product type */ product_type: string; /** * Quota type */ quota_type: string; /** * Expiration date */ valid_through: string; /** * Auto-renewal status */ auto_renew: boolean; /** * Asset status */ status: 'available' | 'used'; /** * Used ID (for GMF, this is group_id) */ used_id: string | null; /** * Total quota (legacy) */ total?: number; /** * Remaining quota (legacy) */ remain?: number; } /** * Quota message response */ interface QuotaMessageResponse { /** * List of quota assets */ data: QuotaAsset[]; /** * Error code */ error: number; /** * Response message */ message: string; } /** * GMF product types */ declare enum GMFProductType { GMF10 = "gmf10", GMF50 = "gmf50", GMF100 = "gmf100" } /** * Quota types */ declare enum QuotaType { SUB_QUOTA = "sub_quota", PURCHASE_QUOTA = "purchase_quota", REWARD_QUOTA = "reward_quota" } /** * OA settings */ interface OASettings { /** * Auto-reply settings */ auto_reply?: { enabled: boolean; message?: string; }; /** * Welcome message settings */ welcome_message?: { enabled: boolean; message?: string; }; /** * Business hours */ business_hours?: { enabled: boolean; schedule?: Array<{ day: number; start_time: string; end_time: string; }>; }; } /** * OA statistics */ interface OAStatistics { /** * Total followers */ total_followers: number; /** * New followers today */ new_followers_today: number; /** * Messages sent today */ messages_sent_today: number; /** * Messages received today */ messages_received_today: number; /** * Engagement rate */ engagement_rate?: number; } /** * OA profile update request */ interface UpdateOAProfileRequest { /** * OA name */ name?: string; /** * OA description */ description?: string; /** * Avatar image (base64 or URL) */ avatar?: string; /** * Cover image (base64 or URL) */ cover?: string; } /** * OA verification request */ interface OAVerificationRequest { /** * Business license number */ business_license: string; /** * Business name */ business_name: string; /** * Contact person name */ contact_name: string; /** * Contact phone number */ contact_phone: string; /** * Contact email */ contact_email: string; /** * Additional documents */ documents?: Array<{ type: string; url: string; }>; } /** * User management related types and interfaces */ /** * User information from Zalo API v3.0 */ interface UserInfo { /** * User ID */ user_id: string; /** * User ID by app */ user_id_by_app: string; /** * External user ID in business system */ user_external_id: string; /** * Display name */ display_name: string; /** * User alias */ user_alias: string; /** * Whether user is under 18 */ is_sensitive: boolean; /** * Last interaction date (dd/MM/yyyy) */ user_last_interaction_date: string; /** * Whether user is following OA */ user_is_follower: boolean; /** * Avatar URL */ avatar: string; /** * Avatar URLs with different sizes */ avatars: { "120": string; "240": string; }; /** * Dynamic param from last access */ dynamic_param?: string; /** * Tags and notes information */ tags_and_notes_info: { notes: string[]; tag_names: string[]; }; /** * Shared information from user */ shared_info?: { address?: string; city?: string; district?: string; phone?: string; name?: string; user_dob?: string; }; } /** * User list request parameters */ interface UserListRequest { /** * Offset for pagination */ offset: number; /** * Number of users to fetch (max 50) */ count: number; /** * Filter by tag name */ tag_name?: string; /** * Filter by last interaction period */ last_interaction_period?: "TODAY" | "YESTERDAY" | "L7D" | "L30D" | string; /** * Filter by follower status */ is_follower?: boolean; } /** * User list response */ interface UserListResponse { /** * Total number of users */ total: number; /** * Number of users returned */ count: number; /** * Current offset */ offset: number; /** * List of user IDs */ users: Array<{ user_id: string; }>; } /** * User label/tag information */ interface UserLabel { /** * Label ID */ label_id: string; /** * Label name */ label_name: string; /** * Label description */ description?: string; /** * Label color (hex) */ color?: string; /** * Creation time (Unix timestamp) */ created_time?: number; /** * Number of users with this label */ user_count?: number; } /** * Create label request */ interface CreateLabelRequest { /** * Label name */ label_name: string; /** * Label description */ description?: string; /** * Label color (hex) */ color?: string; } /** * User label operation request (legacy - for label_id based operations) */ interface UserLabelRequest { /** * User ID */ user_id: string; /** * Label ID */ label_id: string; } /** * Tag user request - for Zalo API v2.0/oa/tag/tagfollower */ interface TagUserRequest { /** * User ID (long in API spec, but sent as string) */ user_id: string; /** * Tag name to assign to user * Note: If tag doesn't exist, API will create it automatically */ tag_name: string; } /** * Remove tag from user request - for Zalo API v2.0/oa/tag/rmfollowerfromtag */ interface RemoveTagFromUserRequest { /** * User ID */ user_id: string; /** * Tag name to remove from user */ tag_name: string; } /** * Get tags list response - for Zalo API v2.0/oa/tag/gettagsofoa */ interface GetTagsResponse { /** * Error code (0 = success) */ error: number; /** * Response message */ message: string; /** * Array of tag names */ data: string[]; } /** * Delete tag request - for Zalo API v2.0/oa/tag/rmtag */ interface DeleteTagRequest { /** * Tag name to delete */ tag_name: string; } /** * Update user request - for Zalo API v3.0/oa/user/update */ interface UpdateUserRequest { /** * User ID (required) */ user_id: string; /** * Shared information to update */ shared_info?: { /** * Display name */ name?: string; /** * Phone number */ phone?: string; /** * Address */ address?: string; /** * City ID (see Zalo documentation for city codes) */ city_id?: number; /** * District ID (see Zalo documentation for district codes) */ district_id?: number; /** * Date of birth (dd/MM/yyyy format, from 1/1/1970) */ user_dob?: string; }; /** * User alias name */ user_alias?: string; /** * External user ID in business system (unique per customer) */ user_external_id?: string; } /** * Delete user info request - for Zalo API v2.0/oa/deletefollowerinfo */ interface DeleteUserInfoRequest { /** * User ID to delete info for */ user_id: string; } /** * Get user custom info request - for Zalo API v3.0/oa/user/detail/custominfo */ interface GetUserCustomInfoRequest { /** * User ID to get custom info for */ user_id: string; /** * List of custom fields to export (optional) * If not specified, API returns all available custom info * For table type fields, only parent field is accepted */ fields_to_export?: string[]; } /** * User custom info response - for Zalo API v3.0/oa/user/detail/custominfo */ interface UserCustomInfoResponse { /** * Error code (0 = success) */ error: number; /** * Response message */ message: string; /** * Custom info data */ data: { /** * User ID */ user_id: string; /** * Custom information fields * All values are returned as strings for consistency */ custom_info: Record<string, any>; }; } /** * Update user custom info request - for Zalo API v3.0/oa/user/update/custominfo */ interface UpdateUserCustomInfoRequest { /** * User ID to update custom info for */ user_id: string; /** * Custom information to update * Structure depends on OA's custom field configuration */ custom_info: Record<string, any>; } /** * User custom information */ interface UserCustomInfo { /** * User ID */ user_id: string; /** * Custom fields (key-value pairs) */ custom_fields: Record<string, any>; /** * Last updated timestamp */ last_updated?: number; } /** * Update custom info request */ interface UpdateCustomInfoRequest { /** * User ID */ user_id: string; /** * Custom fields to update */ custom_fields: Record<string, any>; } /** * User info field types */ declare enum UserInfoFieldType { TEXT = "text", NUMBER = "number", DATE = "date", SELECT = "select" } /** * Field option for select type */ interface FieldOption { /** * Option value */ value: string; /** * Option label */ label: string; } /** * User info field definition */ interface UserInfoField { /** * Field ID */ field_id: string; /** * Field name */ field_name: string; /** * Field type */ field_type: UserInfoFieldType; /** * Field description */ description?: string; /** * Whether field is required */ required?: boolean; /** * Options for select type */ options?: FieldOption[]; /** * Default value */ default_value?: string; /** * Display order */ display_order?: number; /** * Whether it's a system field */ is_system_field?: boolean; /** * Creation time */ created_time?: number; /** * Last update time */ updated_time?: number; } /** * Create user info field request */ interface CreateUserInfoFieldRequest { /** * Field name */ field_name: string; /** * Field type */ field_type: UserInfoFieldType; /** * Field description */ description?: string; /** * Whether field is required */ required?: boolean; /** * Options for select type */ options?: FieldOption[]; /** * Default value */ default_value?: string; /** * Display order */ display_order?: number; } /** * Update user info field request */ interface UpdateUserInfoFieldRequest { /** * Field name */ field_name?: string; /** * Field description */ description?: string; /** * Whether field is required */ required?: boolean; /** * Options for select type */ options?: FieldOption[]; /** * Default value */ default_value?: string; /** * Display order */ display_order?: number; } /** * Advanced filter options for getAllUsersWithAdvancedFilters * Dựa trên các trường trong UserInfo */ interface AdvancedUserFilters { /** * Filter by specific user IDs (exact match) * Chỉ lấy những users có ID trong danh sách này */ userIds?: string[]; /** * Filter by tag name (existing from basic filters) */ tag_name?: string; /** * Filter by last interaction period (existing from basic filters) */ last_interaction_period?: "TODAY" | "YESTERDAY" | "L7D" | "L30D" | string; /** * Filter by follower status (existing from basic filters) */ is_follower?: boolean; /** * Filter by display name (contains search) */ display_name_contains?: string; /** * Filter by user alias (contains search) */ user_alias_contains?: string; /** * Filter by whether user is sensitive (under 18) */ is_sensitive?: boolean; /** * Filter by specific interaction date range */ last_interaction_date_range?: { from: string; to: string; }; /** * Filter by specific tags (multiple tags - OR operation) */ tag_names?: string[]; /** * Filter by tags (ALL tags must match - AND operation) */ require_all_tags?: string[]; /** * Filter by notes content (contains search) */ notes_contains?: string; /** * Filter by shared info - city */ city?: string; /** * Filter by shared info - district */ district?: string; /** * Filter by shared info - phone (contains search) */ phone_contains?: string; /** * Filter by shared info - name (contains search) */ name_contains?: string; /** * Filter by shared info - address (contains search) */ address_contains?: string; /** * Filter by date of birth range */ dob_range?: { from: string; to: string; }; /** * Filter by age range (calculated from dob) */ age_range?: { min: number; max: number; }; /** * Filter by external user ID (contains search) */ external_id_contains?: string; /** * Exclude users with specific tags */ exclude_tags?: string[]; /** * Filter by users who have shared info vs those who don't */ has_shared_info?: boolean; /** * Filter by users who have phone number */ has_phone?: boolean; /** * Filter by users who have address */ has_address?: boolean; } /** * ZNS (Zalo Notification Service) Type Definitions */ declare enum ZNSTemplateType { /** ZNS tùy chỉnh */ CUSTOM = 1, /** ZNS xác thực */ AUTHENTICATION = 2, /** ZNS yêu cầu thanh toán */ PAYMENT_REQUEST = 3, /** ZNS voucher */ VOUCHER = 4, /** ZNS Đánh giá dịch vụ */ SERVICE_RATING = 5 } declare enum ZNSTemplateTag { /** Transaction */ TRANSACTION = "1", /** Customer care */ CUSTOMER_CARE = "2", /** Promotion */ PROMOTION = "3" } declare enum ZNSButtonType { /** Trang doanh nghiệp */ ENTERPRISE_PAGE = 1, /** Gọi điện */ PHONE = 2, /** Trang OA */ OA_PAGE = 3, /** Zalo Mini App */ ZALO_MINI_APP = 4, /** Tải App */ DOWNLOAD_APP = 5, /** Phân phối sản phẩm */ PRODUCT_DISTRIBUTION = 6, /** Web/Zalo Mini App khác */ OTHER_WEB_APP = 7, /** App khác */ OTHER_APP = 8, /** Bài viết OA */ OA_ARTICLE = 9, /** Sao chép */ COPY = 10, /** Thanh toán ngay */ PAY_NOW = 11, /** Xem chi tiết */ VIEW_DETAILS = 12 } declare enum ZNSParamType { /** Tên khách hàng (30) */ CUSTOMER_NAME = "1", /** Số điện thoại (15) */ PHONE_NUMBER = "2", /** Địa chỉ (200) */ ADDRESS = "3", /** Mã số (30) */ CODE = "4", /** Nhãn tùy chỉnh (30) */ CUSTOM_LABEL = "5", /** Trạng thái giao dịch (30) */ TRANSACTION_STATUS = "6", /** Thông tin liên hệ (50) */ CONTACT_INFO = "7", /** Giới tính / Danh xưng (5) */ GENDER_TITLE = "8", /** Tên sản phẩm / Thương hiệu (200) */ PRODUCT_BRAND = "9", /** Số lượng / Số tiền (20) */ QUANTITY_AMOUNT = "10", /** Thời gian (20) */ TIME = "11", /** OTP (10) */ OTP = "12", /** URL (200) */ URL = "13", /** Tiền tệ (VNĐ) (12) */ CURRENCY = "14", /** Bank transfer note (90) */ BANK_TRANSFER_NOTE = "15" } interface ZNSMessage { phone: string; template_id: string; template_data: Record<string, any>; tracking_id?: string; } interface ZNSHashPhoneMessage { phone_hash: string; template_id: string; template_data: Record<string, any>; tracking_id?: string; } interface ZNSDevModeMessage { phone: string; template_id: string; template_data: Record<string, any>; tracking_id?: string; mode: "development"; } interface ZNSRsaMessage { phone_rsa: string; template_id: string; template_data: Record<string, any>; tracking_id?: string; } interface ZNSJourneyMessage { phone: string; template_id: string; template_data: Record<string, any>; tracking_id?: string; journey_id: string; } /** * ZBS/ZNS Template Message by UID * API: POST https://openapi.zalo.me/v3.0/oa/message/template * Send template message using user_id instead of phone number */ interface ZNSUidMessage { /** ID của người nhận - Định danh người dùng theo OA */ user_id: string; /** ID của template muốn sử dụng */ template_id: string; /** Các thuộc tính của template mà đối tác đã đăng ký với Zalo */ template_data: Record<string, any>; } /** * Response from sending ZBS/ZNS template message by UID */ interface ZNSUidSendResult { error: number; message: string; data?: { /** ID của tin nhắn */ message_id: string; /** ID của người dùng */ user_id: string; }; /** Thời gian gửi tin (timestamp) */ sent_time?: string; } interface ZNSSendResult { error: number; message: string; data?: { msg_id: string; sent_time: string; quota?: { remainingQuota: number; dailyQuota: number; }; }; } interface ZNSTemplate { templateId: string; templateName: string; status: "PENDING_REVIEW" | "ENABLE" | "REJECT" | "DISABLE"; listParams: Array<{ name: string; require: boolean; type: "STRING" | "NUMBER" | "DATE"; maxLength?: number; minLength?: number; }>; timeout?: number; previewUrl?: string; templateQuality?: "HIGH" | "MEDIUM" | "LOW"; templateTag?: string; price?: number; applyTemplateQuota?: boolean; templateDailyQuota?: number; templateRemainingQuota?: number; } interface ZNSTemplateDetails { error: number; message: string; data: { templateId: string; templateName: string; status: "ENABLE" | "PENDING_REVIEW" | "DELETE" | "REJECT" | "DISABLE"; reason?: string; listParams: Array<{ name: string; require: boolean; type: string; maxLength: number; minLength: number; acceptNull: boolean; }>; listButtons: Array<{ type: number; title: string; content: string; }>; timeout: number; previewUrl: string; templateQuality: string; templateTag: "TRANSACTION" | "CUSTOMER_CARE" | "PROMOTION"; price_sdt: string; price_uid: string; price: string; }; } interface ZNSTemplateList { error: number; message: string; data: Array<{ templateId: string; templateName: string; createdTime: number; status: "PENDING_REVIEW" | "DISABLE" | "ENABLE" | "REJECT"; templateQuality: "HIGH" | "MEDIUM" | "LOW" | "UNDEFINED"; }>; metadata: { total: number; }; } /** * ZNS Template Create Request - theo chuẩn Zalo API * API: POST https://business.openapi.zalo.me/template/create */ interface ZNSCreateTemplateRequest { /** Tên mẫu tin (10-60 ký tự) */ template_name: string; /** Loại mẫu tin */ template_type: 1 | 2 | 3 | 4 | 5; /** Tag mẫu tin */ tag: "1" | "2" | "3"; /** Layout của template */ layout: ZNSTemplateLayout; /** Thông tin về param (optional) */ params?: ZNSTemplateParam[]; /** Ghi chú kiểm duyệt (1-400 ký tự, optional) */ note?: string; /** Mã tracking do đối tác tự định nghĩa */ tracking_id: string; } /** * ZNS Template Edit Request - theo chuẩn Zalo API * API: POST https://business.openapi.zalo.me/template/edit * Chỉ có thể chỉnh sửa template có trạng thái REJECT */ interface ZNSUpdateTemplateRequest { /** Template ID được hệ thống tự tạo */ template_id: string; /** Tên mẫu tin (10-60 ký tự) */ template_name: string; /** Loại mẫu tin */ template_type: 1 | 2 | 3 | 4 | 5; /** Tag mẫu tin */ tag: "1" | "2" | "3"; /** Layout của template */ layout: ZNSTemplateLayout; /** Thông tin về param (optional) */ params?: ZNSTemplateParam[]; /** Ghi chú kiểm duyệt (1-400 ký tự, optional) */ note?: string; /** Mã tracking do đối tác tự định nghĩa */ tracking_id: string; } /** * Layout của ZNS Template */ interface ZNSTemplateLayout { /** Header components (optional) */ header?: { components: ZNSValidationComponent[]; }; /** Body components (required) */ body: { components: ZNSValidationComponent[]; }; /** Footer components (optional) */ footer?: { components: ZNSValidationComponent[]; }; } /** * Template parameter theo chuẩn Zalo API */ interface ZNSTemplateParam { /** Loại param */ type: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15"; /** Tên của param */ name: string; /** Dữ liệu mẫu của param */ sample_value: string; } /** * Response từ API create/edit template */ interface ZNSTemplateCreateEditResponse { error: number; message: string; data: { /** Template ID */ template_id: string; /** Tên template */ template_name: string; /** Loại template */ template_type: number; /** Trạng thái template sau khi submit */ status: "PENDING_REVIEW"; /** Template tag */ tag: number; /** App ID của template */ app_id: string; /** OA ID của template */ oa_id: string; /** Đơn giá gửi tin qua SĐT */ price_sdt: string; /** Đơn giá gửi tin qua UID */ price_uid: string; /** Timeout của template */ timeout: number; /** Link preview template */ preview_url: string; }; } interface ZNSUploadImageResult { error: number; message: string; data?: { media_id: string; }; } interface ZNSStatusInfo { error: number; message: string; data?: { status: "PENDING" | "SENT" | "RECEIVED" | "FAILED"; sent_time?: string; received_time?: string; fail_reason?: string; }; } interface ZNSMessageStatusInfo { error: number; message: string; data?: { delivery_time: string; message: string; status: number; }; } interface ZNSBatchMessageStatusRequest { message_ids: string[]; } interface ZNSBatchMessageStatusResponse { error: number; message: string; data?: { [messageId: string]: { delivery_time: string; message: string; status: number; }; }; } interface ZNSQuotaInfo { error: number; message: string; data?: { dailyQuota: string; remainingQuota: string; dailyQuotaPromotion: string | null; remainingQuotaPromotion: string | null; monthlyPromotionQuota: number; remainingMonthlyPromotionQuota: number; estimatedNextMonthPromotionQuota: number; }; } interface ZNSAllowedContentTypes { error: number; message: string; data?: string[]; } interface ZNSTemplateSampleData { error: number; message: string; data: Record<string, any>; } interface ZNSCustomerRatingResponse { error: number; data: { total: number; data: Array<{ note: string; rate: number; submitDate: string; msgId: string; feedbacks: string[]; trackingId: string; }>; }; } interface ZNSOAQualityInfo { error: number; message: string; data: { oaCurrentQuality: "HIGH" | "MEDIUM" | "LOW" | "UNDEFINED"; oa7dayQuality: "HIGH" | "MEDIUM" | "LOW" | "UNDEFINED"; }; } interface ZNSQualityHistoryList { error: number; message: string; data?: { history: Array<{ date: string; quality: "HIGH" | "MEDIUM" | "LOW"; qualityScore: number; metrics: { sent: number; delivered: number; read: number; responded: number; complained: number; }; }>; }; } interface ZNSTemplateStatus { templateId: string; status: "PENDING_REVIEW" | "ENABLE" | "REJECT" | "DISABLE"; rejectReason?: string; enabledTime?: string; disabledTime?: string; } interface ZNSComponent { type: "HEADER" | "BODY" | "FOOTER"; format?: "TEXT" | "IMAGE" | "VIDEO"; text?: string; url?: string; example?: { header_text?: string[]; body_text?: string[][]; header_handle?: string[]; }; } interface ZNSTemplateComponent { type: "TITLE" | "PARAGRAPH" | "TABLE" | "LOGO" | "IMAGE" | "BUTTONS"; content?: string; url?: string; buttons?: Array<{ title: string; type: "PHONE_NUMBER" | "URL"; payload: string; }>; table?: { headers: string[]; rows: string[][]; }; } interface ZNSError { error: number; message: string; details?: { field?: string; code?: string; description?: string; }; } interface ZNSAnalytics { templateId: string; period: { from: string; to: string; }; metrics: { sent: number; delivered: number; read: number; clicked: number; failed: number; deliveryRate: number; readRate: number; clickRate: number; }; breakdown?: { daily?: Array<{ date: string; sent: number; delivered: number; read: number; clicked: number; failed: number; }>; hourly?: Array<{ hour: number; sent: number; delivered: number; read: number; clicked: number; failed: number; }>; }; } /** Attachment object cho LOGO và IMAGES */ interface ZNSAttachment { type: "IMAGE"; media_id: string; } /** TITLE component */ interface ZNSTitleComponent { value: string; } /** PARAGRAPH component */ interface ZNSParagraphComponent { value: string; } /** OTP component */ interface ZNSOTPComponent { value: string; } /** TABLE component */ interface ZNSTableComponent { rows: ZNSTableRow[]; } interface ZNSTableRow { title: string; value: string; row_type?: 0 | 1 | 2 | 3 | 4 | 5; } /** LOGO component */ interface ZNSLogoComponent { light: ZNSAttachment; dark: ZNSAttachment; } /** IMAGES component */ interface ZNSImagesComponent { items: ZNSAttachment[]; } /** BUTTONS component */ interface ZNSButtonsComponent { items: ZNSButtonItem[]; } interface ZNSButtonItem { type: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; title: string; content: string; } /** PAYMENT component */ interface ZNSPaymentComponent { bank_code: string; account_name: string; bank_account: string; amount: string; note?: string; } /** VOUCHER component */ interface ZNSVoucherComponent { name: string; condition: string; start_date?: string; end_date: string; voucher_code: string; } /** RATING component */ interface ZNSRatingComponent { items: ZNSRatingItem[]; } interface ZNSRatingItem { star: 1 | 2 | 3 | 4 | 5; title: string; question?: string; answers?: string[]; thanks: string; description: string; } /** Union type cho tất cả các component */ type ZNSValidationComponent = { TITLE: ZNSTitleComponent; } | { PARAGRAPH: ZNSParagraphComponent; } | { OTP: ZNSOTPComponent; } | { TABLE: ZNSTableComponent; } | { LOGO: ZNSLogoComponent; } | { IMAGES: ZNSImagesComponent; } | { BUTTONS: ZNSButtonsComponent; } | { PAYMENT: ZNSPaymentComponent; } | { VOUCHER: ZNSVoucherComponent; } | { RATING: ZNSRatingComponent; }; /** * Types for Zalo Official Account Article Management * Based on Zalo Article API v2.0 */ /** * Article cover configuration */ interface ArticleCover { /** Cover type: photo or video */ cover_type: 'photo' | 'video'; /** Photo URL (required when cover_type is 'photo') */ photo_url?: string; /** Video ID (required when cover_type is 'video') */ video_id?: string; /** Cover view orientation for video */ cover_view?: 'horizontal' | 'vertical' | 'square'; /** Cover status */ status: 'show' | 'hide'; } /** * Article body content item */ interface ArticleBodyItem { /** Content type */ type: 'text' | 'image' | 'video' | 'product'; /** Text content (for type: text) */ content?: string; /** Image URL (for type: image) */ url?: string; /** Video ID (for type: video) */ video_id?: string; /** Product ID (for type: product) */ id?: string; /** Additional properties for video */ width?: number; height?: number; thumbnail?: string; } /** * Normal article creation request */ interface ArticleNormalRequest { type: 'normal'; title: string; author: string; cover: ArticleCover; description: string; body: ArticleBodyItem[]; related_medias?: string[]; tracking_link?: string; status?: 'show' | 'hide'; comment?: 'show' | 'hide'; } /** * Video article creation request */ interface ArticleVideoRequest { type: 'video'; title: string; description: string; video_id: string; avatar: string; status?: 'show' | 'hide'; comment?: 'show' | 'hide'; } /** * Article creation request (union type) */ type ArticleRequest = ArticleNormalRequest | ArticleVideoRequest; /** * Article creation response */ type ArticleResponse = ZaloResponse<{ token: string; }>; /** * Article process check response */ interface ArticleProcessResponse { /** Article ID if creation is successful */ article_id?: string; /** Process status */ status: 'processing' | 'success' | 'failed'; /** Error message if failed */ error_message?: string; /** Creation timestamp */ created_time: number; /** Last update timestamp */ updated_time: number; } /** * Article verification response */ interface ArticleVerifyResponse { /** Article ID */ id: string; } /** * Article cite information */ interface ArticleCite { url: string; description: string; } /** * Article detail (normal type) */ interface ArticleDetailNormal { id: string; type: 'normal'; title: string; author: string; cover: ArticleCover; description: string; body: ArticleBodyItem[]; related_medias: string[]; tracking_link: string; status: 'show' | 'hide'; comment: 'show' | 'hide'; cite?: ArticleCite; link_view: string; total_view: number; total_share: number; total_like: number; total_comment: number; } /** * Article detail (video type) */ interface ArticleDetailVideo { id: string; type: 'video'; title: string; description: string; video_id: string; avatar: string; status: 'show' | 'hide'; comment: 'show' | 'hide'; link_view: string; total_view: number; total_share: number; total_like: number; total_comment: number; } /** * Article detail (union type) */ type ArticleDetail = ArticleDetailNormal | ArticleDetailVideo; /** * Article list request */ interface ArticleListRequest { /** Starting position */ offset: number; /** Number of articles to return (max 10) */ limit: number; /** Article type filter */ type: 'normal' | 'video'; } /** * Article list item - matches Zalo API response structure exactly */ interface ArticleListItem { /** Article ID */ id: string; /** Article type */ type: 'normal' | 'video'; /** Article title */ title: string; /** Article status */ status: 'show' | 'hide'; /** Total view count */ total_view: number; /** Total share count */ total_share: number; /** Article creation date (timestamp) */ create_date: number; /** Article update date (timestamp) */ update_date: number; /** Article thumbnail URL */ thumb: string; /** Article view link */ link_view: string; } /** * Article list response data - matches Zalo API response structure exactly */ interface ArticleListData { /** Array of articles (called "medias" in Zalo API) */ medias: ArticleListItem[]; /** Total number of articles */ total: number; } /** * Article list response */ type ArticleListResponse = ZaloApiResponse<ArticleListData>; /** * Normal article update request */ interface ArticleUpdateNormalRequest { id: string; type: 'normal'; title: string; author: string; cover: ArticleCover; description: string; body: ArticleBodyItem[]; related_medias?: string[]; tracking_link?: string; status?: 'show' | 'hide'; comment?: 'show' | 'hide'; } /** * Video article update request */ interface ArticleUpdateVideoRequest { id: string; type: 'video'; title: string; description: string; video_id: string; avatar: string; status?: 'show' | 'hide'; comment?: 'show' | 'hide'; } /** * Article update request (union type) */ type ArticleUpdateRequest = ArticleUpdateNormalRequest | ArticleUpdateVideoRequest; /** * Article update response */ interface ArticleUpdateResponse { /** Token for tracking article update progress */ token: string; } /** * Article removal request */ interface ArticleRemoveRequest { /** Article ID to remove */ id: string; } /** * Article removal response */ interface ArticleRemoveResponse { /** Success message */ message: string; } /** * Bulk article removal result for individual item */ interface BulkRemoveItemResult { /** Article ID that was processed */ article_id: string; /** Whether the removal was successful */ success: boolean; /** Success message if removal succeeded */ message?: string; /** Error message if removal failed */ error?: string; /** Processing time in milliseconds */ processing_time?: number; } /** * Progress information for bulk article removal */ interface BulkRemoveProgress { /** Current number of articles processed */ current_count: number; /** Total number of articles to process */ total_count: number; /** Progress percentage (0-100) */ percentage: number; /** Number of successful removals so far */ successful_count: number; /** Number of failed removals so far */ failed_count: number; /** Whether the operation is complete */ is_complete: boolean; /** Current batch being processed */ current_batch?: number; /** Total number of batches */ total_batches?: number; } /** * Options for bulk article removal */ interface BulkRemoveOptions { /** Number of articles to process in each batch (default: 10) */ batch_size?: number; /** Maximum number of concurrent requests (default: 3) */ max_concurrency?: number; /** Whether to continue processing if some articles fail (default: true) */ continue_on_error?: boolean; /** Delay between batches in milliseconds (default: 100) */ batch_delay?: number; /** Timeout for each removal request in milliseconds (default: 10000) */ request_timeout?: number; } /** * Complete result for bulk article removal operation */ interface BulkRemoveResult { /** Total number of articles processed */ total_processed: number; /** Number of successful removals */ successful_count: number; /** Number of failed removals */ failed_count: number; /** Success rate as percentage (0-100) */ success_rate: number; /** Total processing time in milliseconds */ total_time: number; /** Detailed results for each article */ results: BulkRemoveItemResult[]; /** Summary of errors encountered */ error_summary?: { [errorType: string]: number; }; } /** * Result for individual article detail fetch in bulk operation */ interface BulkDetailItemResult { /** Article ID that was processed */ article_id: string; /** Whether the detail fetch was successful */ success: boolean; /** Article detail if fetch succeeded */ detail?: ArticleDetail; /** Error message if fetch failed */ error?: string; /** Processing time in milliseconds */ processing_time?: number; } /** * Progress information for bulk article details fetch */ interface BulkDetailProgress { /** Current number of articles processed */ current_count: number; /** Total number of articles to process */ total_count: number; /** Progress percentage (0-100) */ percentage: number; /** Number of successful detail fetches so far */ successful_count: number; /** Number of failed detail fetches so far */ failed_count: number; /** Whether the operation is complete */ is_complete: boolean; /** Current phase of operation */ phase: 'fetching_list' | 'fetching_details' | 'complete'; /** Current batch being processed (for details phase) */ current_batch?: number; /** Total number of batches (for details phase) */ total_batches?: number; } /** * Options for bulk article details fetch */ interface BulkDetailOptions { /** Number of articles to fetch details for in each batch (default: 5) */ detail_batch_size?: number; /** Maximum number of concurrent detail requests (default: 3) */ max_concurrency?: number; /** Whether to continue processing if some details fail (default: true) */ continue_on_error?: boolean; /** Delay between detail batches in milliseconds (default: 200) */ batch_delay?: number; /** Timeout for each detail request in milliseconds (default: 15000) */ request_timeout?: number; /** Maximum number of articles to process (default: unlimited) */ max_articles?: number; /** Options for the initial article list fetch */ list_options?: { batch_size?: number; max_articles?: number; }; } /** * Complete result for bulk article details fetch operation */ interface BulkDetailResult { /** Total number of articles processed */ total_pro