@bzbs/react-api-client 1.4.14 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,22 @@
1
1
  # @bzbs/react-api-client
2
2
 
3
- A TypeScript API client library for integrating with Buzzebees services. Provides strongly-typed methods for authentication, campaigns, profiles, shopping carts, notifications, and more.
3
+ A TypeScript library providing a type-safe API client for Buzzebees loyalty and reward services. Supports authentication, campaigns, user profiles, shopping carts, notifications, stamps, consent management, and more.
4
4
 
5
- **Version:** 1.4.12 | **License:** ISC | **Author:** Buzzebees Co., Ltd.
5
+ **Version:** 1.4.15 | **License:** ISC | **Author:** Buzzebees Co., Ltd.
6
+ **Repository:** [Azure DevOps](https://dev.azure.com/buzzebees/Buzzebees/_git/React_API_Client)
7
+
8
+ ---
6
9
 
7
10
  ## Table of Contents
8
11
 
9
12
  - [Installation](#installation)
10
13
  - [Quick Start](#quick-start)
14
+ - [API Version](#api-version)
11
15
  - [Configuration](#configuration)
12
16
  - [Architecture](#architecture)
17
+ - [BzbsService Properties](#bzbsservice-properties)
18
+ - [Response Handling](#response-handling)
19
+ - [Complete API Endpoint Table](#complete-api-endpoint-table)
13
20
  - [API Reference](#api-reference)
14
21
  - [AuthenticateApi](#authenticateapi)
15
22
  - [CampaignApi](#campaignapi)
@@ -31,10 +38,11 @@ A TypeScript API client library for integrating with Buzzebees services. Provide
31
38
  - [RequestHelpApi (Forum)](#requesthelpapi-forum)
32
39
  - [SettingApi](#settingapi)
33
40
  - [Blob](#blob)
34
- - [Response Handling](#response-handling)
35
- - [Error Handling](#error-handling)
36
- - [Models](#models)
37
- - [Development](#development)
41
+ - [Models Reference](#models-reference)
42
+ - [BaseService Utilities](#baseservice-utilities)
43
+ - [Testing Guide](#testing-guide)
44
+ - [Development Commands](#development-commands)
45
+ - [Adding a New API](#adding-a-new-api)
38
46
  - [Build Output](#build-output)
39
47
 
40
48
  ---
@@ -45,6 +53,14 @@ A TypeScript API client library for integrating with Buzzebees services. Provide
45
53
  npm install @bzbs/react-api-client
46
54
  ```
47
55
 
56
+ Peer dependency: `axios`
57
+
58
+ ```bash
59
+ npm install axios
60
+ ```
61
+
62
+ ---
63
+
48
64
  ## Quick Start
49
65
 
50
66
  ```typescript
@@ -81,6 +97,20 @@ if (result.type === 'success') {
81
97
  }
82
98
  ```
83
99
 
100
+ ---
101
+
102
+ ## API Version
103
+
104
+ This library targets **Buzzebees API v2**. Key differences from v1:
105
+
106
+ - All POST request bodies use **JSON** (`application/json`) — no more `application/x-www-form-urlencoded`
107
+ - Profile image upload uses `multipart/form-data` via the dedicated `updateProfileImage()` method
108
+ - Flat endpoint paths replace REST-style path parameters (e.g. `campaign/detail?campaignId=123` replaces `campaign/123`)
109
+ - `profile/me/` prefix removed — the auth token identifies the user (e.g. `profile/info` replaces `profile/me`)
110
+ - Address lookups moved from `main/` to `address/` prefix
111
+
112
+ ---
113
+
84
114
  ## Configuration
85
115
 
86
116
  ### Constructor
@@ -122,8 +152,6 @@ axiosClient.interceptors.request.use((config) => {
122
152
 
123
153
  ### Dynamic URL Updates
124
154
 
125
- You can update base URLs at runtime:
126
-
127
155
  ```typescript
128
156
  bzbsService.setBaseUrl('https://new-api.buzzebees.com/api/');
129
157
  bzbsService.setBlobUrl('https://new-blob.buzzebees.com/');
@@ -134,36 +162,43 @@ bzbsService.setLineUrl('https://api.line.me/');
134
162
 
135
163
  ## Architecture
136
164
 
137
- The library follows a layered service architecture:
138
-
139
165
  ```
166
+ Consumer Code
167
+
168
+
140
169
  BzbsService (entry point)
141
170
  ├── AuthenticateApi → auth/
142
171
  ├── BadgeApi → profile/me/badges
143
172
  ├── CampaignApi → campaign/
144
173
  ├── CartApi → cart/
145
- ├── CategoryApi → campaigncat/
174
+ ├── CategoryApi → category/
146
175
  ├── ConsentApi → consent/
147
176
  ├── CouponApi → coupon/
148
- ├── DashboardApi → dashboard/
177
+ ├── DashboardApi → dashboard/config
149
178
  ├── HistoryApi → redeem/
150
179
  ├── LineApi → LINE OAuth (optional)
151
- ├── NotificationApi → noti/
180
+ ├── NotificationApi → notification/
152
181
  ├── PlaceApi → place/
153
182
  ├── PointLogApi → log/points
154
- ├── ProfileApi → profile/me
183
+ ├── ProfileApi → profile/
155
184
  ├── RegistrationApi → auth/register
156
- ├── AddressApi → profile/me/address, main/
185
+ ├── AddressApi → profile/address, address/
157
186
  ├── StampApi → stamp/
158
187
  ├── RequestHelpApi → buzz/, profile/me/help
159
- ├── SettingApi → setting/
188
+ ├── SettingApi → setting/add
160
189
  └── Blob → blob storage
190
+
191
+
192
+ BaseService ← Abstract HTTP layer
193
+
194
+
195
+ AxiosInstance ← Consumer-injected, fully configurable
161
196
  ```
162
197
 
163
198
  All API classes extend `BaseService`, which provides:
164
199
  - HTTP methods: `get`, `post`, `put`, `delete`, `patch`
165
- - Automatic response normalization
166
- - Error handling with typed responses
200
+ - Automatic response normalization (handles both `{ Success, Data }` and `{ success, data }` formats)
201
+ - Error handling with typed `ServiceResponse<T>`
167
202
  - URL construction utilities
168
203
  - FormData creation utility
169
204
 
@@ -200,11 +235,92 @@ src/
200
235
 
201
236
  ---
202
237
 
203
- ## API Reference
238
+ ## BzbsService Properties
239
+
240
+ | Property | Type | Description |
241
+ |---|---|---|
242
+ | `authApi` | `AuthenticateApi` | Authentication, login, OTP, session management |
243
+ | `badgeApi` | `BadgeApi` | User badges and missions |
244
+ | `campaignApi` | `CampaignApi` | Campaigns, redemption, favorites |
245
+ | `cartApi` | `CartApi` | Shopping cart |
246
+ | `categoryApi` | `CategoryApi` | Campaign categories |
247
+ | `consentApi` | `ConsentApi` | PDPA / privacy consent |
248
+ | `couponApi` | `CouponApi` | Coupon code processing |
249
+ | `dashboardApi` | `DashboardApi` | Dashboard content |
250
+ | `historyApi` | `HistoryApi` | Redemption history, voucher usage |
251
+ | `lineApi` | `LineApi \| undefined` | LINE OAuth (only if `baseLineUrl` provided) |
252
+ | `notificationApi` | `NotificationApi` | Push notifications |
253
+ | `placeApi` | `PlaceApi` | Locations / stores |
254
+ | `pointLogApi` | `PointLogApi` | Point transaction logs |
255
+ | `profileApi` | `ProfileApi` | User profile, points, account |
256
+ | `registerApi` | `RegistrationApi` | User registration |
257
+ | `addressApi` | `AddressApi` | Addresses, provinces, districts |
258
+ | `stampApi` | `StampApi` | Stamp cards |
259
+ | `forumApi` | `RequestHelpApi` | Help/support forum (Buzz) |
260
+ | `settingApi` | `SettingApi` | Web landing / cart settings |
261
+ | `blob` | `Blob` | Blob storage, maintenance, consent versions |
262
+
263
+ ---
264
+
265
+ ## Response Handling
266
+
267
+ All API methods return `Promise<ServiceResponse<T>>`, a discriminated union:
268
+
269
+ ```typescript
270
+ type ServiceResponse<T> = SuccessResponse<T> | ErrorResponse;
204
271
 
205
- Every API method returns `Promise<ServiceResponse<T>>`. All methods accept an optional `requestOptions` parameter as the last argument for custom headers or query params.
272
+ type SuccessResponse<T> = {
273
+ type: 'success';
274
+ model: T; // The typed response data
275
+ response: AxiosResponse;
276
+ };
206
277
 
207
- ### RequestOptions
278
+ type ErrorResponse = ClientError | ServerError;
279
+
280
+ type ServerError = {
281
+ type: 'server-error';
282
+ error: BzbsErrorResponse; // { requestId, error: { id, message, code, type } }
283
+ statusCode: number;
284
+ response: AxiosResponse;
285
+ };
286
+
287
+ type ClientError = {
288
+ type: 'client-error';
289
+ message: string;
290
+ details?: any;
291
+ };
292
+ ```
293
+
294
+ ### Usage Pattern
295
+
296
+ ```typescript
297
+ const result = await bzbsService.campaignApi.campaigns({ config: 'main' });
298
+
299
+ switch (result.type) {
300
+ case 'success':
301
+ console.log(result.model); // Campaign[]
302
+ break;
303
+
304
+ case 'server-error':
305
+ console.error(result.error.error?.message);
306
+ console.error('Status:', result.statusCode);
307
+ break;
308
+
309
+ case 'client-error':
310
+ console.error(result.message);
311
+ break;
312
+ }
313
+ ```
314
+
315
+ ### Response Normalization
316
+
317
+ The library automatically handles both uppercase and lowercase API response formats:
318
+ - `{ Success: true, Data: ... }` and `{ success: true, data: ... }` are both supported
319
+ - HTTP 204 responses return an empty object as the model
320
+
321
+ ### Custom Request Headers
322
+
323
+ Pass `RequestOptions` as the last argument to any API method:
208
324
 
209
325
  ```typescript
210
326
  type RequestOptions = {
@@ -213,13 +329,123 @@ type RequestOptions = {
213
329
  data?: any;
214
330
  baseUrl?: string;
215
331
  };
332
+
333
+ const response = await bzbsService.profileApi.profile(undefined, {
334
+ headers: { 'Accept-Language': 'th' },
335
+ });
216
336
  ```
217
337
 
218
338
  ---
219
339
 
340
+ ## Complete API Endpoint Table
341
+
342
+ > All endpoints are relative to `baseUrl` (constructor param), except `LineApi` (uses `baseLineUrl`) and `Blob` (uses `baseBlobUrl`).
343
+ >
344
+ > **Feature Tags:** `#auth` `#campaign` `#cart` `#category` `#consent` `#coupon` `#dashboard` `#history` `#line` `#notification` `#place` `#points` `#profile` `#registration` `#address` `#stamp` `#forum` `#setting` `#blob`
345
+
346
+ | Service | Method | HTTP | Endpoint | Key Parameters | Return Model | Tags |
347
+ |---|---|---|---|---|---|---|
348
+ | `authApi` | `deviceLogin` | POST | `auth/device_login` | appId, uuid, deviceLocale, os, platform, deviceToken, macAddress; opt: otp, refcode, contact_number | `LoginResponse` | `#auth` |
349
+ | `authApi` | `facebookLogin` | POST | `auth/login` | accessToken, appId, uuid, deviceLocale, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth` |
350
+ | `authApi` | `googleLogin` | POST | `auth/google_login` | idToken, appId, uuid, deviceLocale, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth` |
351
+ | `authApi` | `lineLogin` | POST | `auth/line_login` | idToken, lineAccessToken, authorizationCode, appId, uuid, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth #line` |
352
+ | `authApi` | `appleLogin` | POST | `auth/apple_login` | idToken, refreshToken, appId, uuid, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth` |
353
+ | `authApi` | `appleToken` | POST | `auth/apple_token` | authorizationCode, idToken, appId, os, platform, macAddress, clientVersion | `AppleToken` | `#auth` |
354
+ | `authApi` | `usernamePasswordLogin` | POST | `auth/bzbs_login` | username, password, appId, uuid, deviceLocale, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth` |
355
+ | `authApi` | `connectLine` | POST | `auth/line_login` | idToken, lineAccessToken, authorizationCode, appId, uuid, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth #line` |
356
+ | `authApi` | `connectFacebook` | POST | `auth/login` | accessToken, appId, uuid, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth` |
357
+ | `authApi` | `connectGoogle` | POST | `auth/google_login` | idToken, appId, uuid, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth` |
358
+ | `authApi` | `connectApple` | POST | `auth/apple_login` | idToken, refreshToken, appId, uuid, os, platform, deviceToken, macAddress | `LoginResponse` | `#auth` |
359
+ | `authApi` | `logout` | POST | `auth/logout` | uuid | `unknown` | `#auth` |
360
+ | `authApi` | `forgetPassword` | GET | `profile/forget_password` | contact (as `id` param), type (`email`\|`contact_number`\|`email_otp`) | `ForgetPasswordResponse` | `#auth #profile` |
361
+ | `authApi` | `resetPassword` | POST | `profile/forget_password` | contact (as `id`), refCode, newPassword; opt: otp | `StatusResponse` | `#auth #profile` |
362
+ | `authApi` | `otp` | GET | `auth/otp` | uuid, appId, contactNumber; opt: channel | `OtpResponse` | `#auth` |
363
+ | `authApi` | `otpV2` | POST | `auth/otp` | appId, contactNumber; opt: channel | `OtpResponse` | `#auth` |
364
+ | `authApi` | `otpEmail` | GET | `auth/otp_email` | uuid, appId, email; opt: channel | `OtpResponse` | `#auth` |
365
+ | `authApi` | `confirmOtp` | POST | `auth/bzbs_authen` | otp, refCode, contactNumber | `ConfirmOtpResponse` | `#auth` |
366
+ | `authApi` | `validateOtp` | POST | `auth/validate_otp` | appId, otp, refCode, type; opt: contactNumber, email, use, channel | `ValidateOtpResponse` | `#auth` |
367
+ | `authApi` | `resume` | POST | `auth/device_resume` | uuid, deviceAppId, os, platform, macAddress, deviceNotificationEnabled, clientVersion, deviceToken | `ResumeResponse` | `#auth` |
368
+ | `authApi` | `updateDevice` | POST | `auth/update_device` | uuid, deviceAppId, os, platform, macAddress, deviceNotificationEnabled, clientVersion, deviceToken | `ResumeResponse` | `#auth` |
369
+ | `authApi` | `version` | GET | `auth/version` | clientVersion | `Version` | `#auth` |
370
+ | `authApi` | `versionRaw` | GET | `auth/version` | clientVersion | `any` | `#auth` |
371
+ | `badgeApi` | `badges` | GET | `profile/me/badges` | opt: badgeId | `Badge[]` | `#profile` |
372
+ | `campaignApi` | `campaigns` | GET | `campaign/list` | config; opt: cat, byConfig, skip, top, locale, keyword, startDate, sponsorId, maxPoints, minPoints, sortBy, center, hashTags, locationAgencyId | `Campaign[]` | `#campaign` |
373
+ | `campaignApi` | `favoriteCampaigns` | GET | `profile/favourite_campaign` | opt: skip, top, locale | `Campaign[]` | `#campaign #profile` |
374
+ | `campaignApi` | `campaignDetails` | GET | `campaign/detail` | id (as `campaignId`); opt: deviceLocale | `CampaignDetail` | `#campaign` |
375
+ | `campaignApi` | `addToFavorite` | POST | `campaign/favourite` | id (as body `id`, `favourite: true`) | `FavoriteResponse` | `#campaign` |
376
+ | `campaignApi` | `removeFromFavorite` | DELETE | `campaign/favourite` | id (as query param) | `FavoriteResponse` | `#campaign` |
377
+ | `campaignApi` | `redeem` | POST | `campaign/redeem` | id (as `campaignid`); opt: addressKey, contactNumber, pointUnit, spPoints | `RedeemResponse` | `#campaign #points` |
378
+ | `campaignApi` | `bulkRedeem` | POST | `campaign/{id}/bulkredeem` | id, quantity; opt: addressKey, contactNumber, pointUnit, spPoints | `RedeemResponse` | `#campaign #points` |
379
+ | `cartApi` | `addCart` | POST | `cart/{id}/add` | id; opt: mode, qty, sideCampaignJson | `CartCountResponse` | `#cart #campaign` |
380
+ | `cartApi` | `cartCount` | GET | `cart/count` | opt: options | `CartCountResponse` | `#cart` |
381
+ | `cartApi` | `cartAccess` | POST | `setting/add` | errorUrl, successUrl, returnUrl, appId, appName | `CartAccessResponse` | `#cart #setting` |
382
+ | `categoryApi` | `categories` | GET | `category/menu` | config; opt: byConfig | `Category[]` | `#category #campaign` |
383
+ | `consentApi` | `consent` | GET | `consent/status` | opt: options | `Consent` | `#consent` |
384
+ | `consentApi` | `updateConsent` | POST | `consent/consent` | opt: termsAndConditions, dataPrivacy, marketingOption, consentAge, email, sms, notification, line, analyticsBuzzebeesCookies, analyticsFirebaseCookies, analyticsGoogleCookies, analyticsMetaCookies, analyticsOtherCookies, functionalCookies, marketingCookies, necessaryCookies | `Consent` | `#consent` |
385
+ | `consentApi` | `unconsent` | POST | `consent/unconsent` | opt: options | `unknown` | `#consent` |
386
+ | `couponApi` | `processCodes` | POST | `coupon/process` | codes (string or string[], sent as JSON array) | `CouponResponse` | `#coupon #campaign` |
387
+ | `dashboardApi` | `mainDashboard` | GET | `dashboard/config` | appName (as `config`), locale | `Dashboard[]` | `#dashboard` |
388
+ | `dashboardApi` | `subDashboard` | GET | `dashboard/config` | dashboardName (as `config`), locale | `Dashboard[]` | `#dashboard` |
389
+ | `historyApi` | `redeemHistories` | GET | `redeem/list` | byConfig, config, skip, top; opt: locale, startDate, endDate | `Purchase[]` | `#history #campaign` |
390
+ | `historyApi` | `use` | POST | `redeem/use` | redeemKey (as `redeemkey` in body) | `UseCampaignResponse` | `#history #campaign` |
391
+ | `lineApi` | `lineAuth` | POST | `oauth2/v2.1/token` _(baseLineUrl)_ | grantType, code, clientId, clientSecret, redirectUrl | `LineAuthResponse` | `#line #auth` |
392
+ | `notificationApi` | `notifications` | GET | `notification/list` | mode (`new`\|`all`), sortBy (`createdate_desc`\|`createdate_asc`); opt: top, skip | `Notification[]` | `#notification` |
393
+ | `notificationApi` | `read` | POST | `notification/read` | ids (comma-separated, sent as JSON body) | `unknown` | `#notification` |
394
+ | `placeApi` | `placeList` | GET | `place` | agencyId, center, distance, top; opt: provinceCode, category, mode, requiredCampaign, keyword, isFavourite | `Place[]` | `#place` |
395
+ | `placeApi` | `place` | GET | `place/{id}` | id, agencyId; opt: requiredCampaign, isFavourite | `Place` | `#place` |
396
+ | `placeApi` | `addToFavourite` | POST | `place/{id}/favourite` | id | `unknown` | `#place` |
397
+ | `placeApi` | `removeFromFavourite` | POST | `place/{id}/unfavourite` | id | `unknown` | `#place` |
398
+ | `pointLogApi` | `getPointLog` | GET | `log/points` | month; opt: type, lastRowKey, top | `PointLog[]` | `#points #profile` |
399
+ | `profileApi` | `profile` | GET | `profile/info` | opt: options | `ProfileResponse` | `#profile` |
400
+ | `profileApi` | `updateProfile` | POST | `profile/info` | opt: firstName, lastName, contactNumber, email, notification, locale, title, gender, birthDate, address, subdistrictCode, districtCode, provinceCode, countryCode, zipCode, idCard, passport, maritalStatus, displayName, latitude, longitude, income, interests, region, occupation, remark, ... (JSON body) | `ProfileResponse` | `#profile` |
401
+ | `profileApi` | `updateProfileImage` | POST | `profile/picture` | image (File or `{uri, name, type}`, sent as `multipart/form-data` with key `data`) | `ProfileResponse` | `#profile` |
402
+ | `profileApi` | `changePassword` | POST | `profile/change_password` | current, change | `StatusResponse` | `#profile #auth` |
403
+ | `profileApi` | `updateShipping` | POST | `profile/shipping` | opt: shippingFirstName, shippingLastName, shippingProvinceCode, shippingDistrictCode, shippingSubDistrictCode, shippingZipCode, shippingAddress, shippingContactNumber, ... | `unknown` | `#profile #address` |
404
+ | `profileApi` | `changeContactNumber` | POST | `auth/change_authen` | contactNumber, otp, refCode; opt: idCard | `ConfirmOtpResponse` | `#profile #auth` |
405
+ | `profileApi` | `changeContactNumberV2` | POST | `profile/contact_number` | contactNumber, otp, refCode | `any` | `#profile #auth` |
406
+ | `profileApi` | `changeContactNumberV3` | POST | `profile/contact_number` | userId (as `userid` in body), contactNumber, otp, refCode | `any` | `#profile #auth` |
407
+ | `profileApi` | `points` | GET | `profile/updated_points` | opt: options | `UpdatedPoints` | `#profile #points` |
408
+ | `profileApi` | `expiringPoints` | GET | `profile/allexpiring_points` | opt: options | `ExpiringPoints` | `#profile #points` |
409
+ | `profileApi` | `deactivate` | POST | `profile/deactivate` | opt: options | `unknown` | `#profile` |
410
+ | `registerApi` | `validateRegister` | POST | `auth/validate_register` | appId, username, email, contactNumber | `OtpResponse` | `#registration #auth` |
411
+ | `registerApi` | `register` | POST | `auth/register` | appId, uuid, macAddress, os, platform, clientVersion, deviceNotificationEnable, username, password, confirmPassword, firstName, lastName, contactNumber, otp, refCode, options; opt: address, gender, birthdate, email, refUserCode, termAndConditionVersion, dataPrivacyVersion, marketingOptionsVersion, consentAge, emailMarketing, smsMarketing, notificationMarketing, lineMarketing, phoneMarketing | `RegistrationResponse` | `#registration #auth` |
412
+ | `addressApi` | `zipCodes` | GET | `address/postcode` | opt: zipCode | `ZipCode[]` | `#address` |
413
+ | `addressApi` | `provinces` | GET | `address/province` | opt: options | `Province[]` | `#address` |
414
+ | `addressApi` | `districts` | GET | `address/district` | opt: provinceCode | `District[]` | `#address` |
415
+ | `addressApi` | `subDistricts` | GET | `address/subdistrict` | opt: provinceCode, districtCode | `SubDistrict[]` | `#address` |
416
+ | `addressApi` | `userAddresses` | GET | `profile/addresses` | opt: options | `Address[]` | `#address #profile` |
417
+ | `addressApi` | `updateAddress` | POST | `profile/address` | opt: name, addressName, firstName, lastName, address, zipcode, provinceCode, provinceName, districtCode, districtName, subDistrictCode, subDistrictName, contactNumber, countryCode, countryName, latitude, longitude, landmark, isDefault, rowKey | `Address` | `#address #profile` |
418
+ | `addressApi` | `deleteAddress` | DELETE | `profile/address` | opt: rowKey | `unknown` | `#address #profile` |
419
+ | `addressApi` | `userTaxAddresses` | GET | `profile/taxes` | opt: options | `Address[]` | `#address #profile` |
420
+ | `addressApi` | `updateTaxAddress` | POST | `profile/tax` | opt: rowKey, taxId, isDefault, personType, title, name, firstName, lastName, email, contactNumber, brnachId, branchName, companyName, address, addressName, floor, building, moo, road, room, soi, village, districtCode, provinceName, subDistrictCode, zipcode | `Address` | `#address #profile` |
421
+ | `addressApi` | `deleteTaxAddress` | DELETE | `profile/tax` | opt: rowKey | `unknown` | `#address #profile` |
422
+ | `stampApi` | `createStamp` | POST | `stamp/create` | opt: imei, issuer, os, platform | `CreateStampResponse` | `#stamp` |
423
+ | `stampApi` | `stamps` | GET | `stamp` | options | `Stamp[]` | `#stamp` |
424
+ | `stampApi` | `stampProfile` | GET | `stamp/{id}/profile` | id, cardId | `StampProfileResponse` | `#stamp` |
425
+ | `forumApi` | `helpCode` | POST | `profile/me/help` | os, platform, clientVersion | `RequestHelpCode` | `#forum #profile` |
426
+ | `forumApi` | `requestHelpList` | GET | `buzz/{requestId}/list` | requestId | `ChatMessage[]` | `#forum` |
427
+ | `forumApi` | `requestDetail` | GET | `buzz/{buzzKey}` | buzzKey | `ChatMessage` | `#forum` |
428
+ | `forumApi` | `postRequestHelp` | POST | `buzz/{requestId}/buzz` | requestId, message; opt: image (File) | `ChatMessage` | `#forum` |
429
+ | `forumApi` | `comments` | GET | `buzz/{buzzKey}/comments` | buzzKey; opt: lastRowKey | `ChatMessage[]` | `#forum` |
430
+ | `forumApi` | `postComment` | POST | `buzz/{buzzKey}/comments` | buzzKey, message; opt: image (File) | `ChatMessage` | `#forum` |
431
+ | `forumApi` | `like` | POST | `buzz/{buzzKey}/like` | buzzKey | `LikeForumResponse` | `#forum` |
432
+ | `forumApi` | `unlike` | DELETE | `buzz/{buzzKey}/like` | buzzKey | `LikeForumResponse` | `#forum` |
433
+ | `settingApi` | `accessKey` | POST | `setting/add` | data (JSON: app_id, campaign_id, locale, return_url, version; opt: redeem_key) | `AccessTokenResponse` | `#setting #campaign` |
434
+ | `blob` | `consentVersion` | GET | `pdpaconsent/{appId}/version` _(baseBlobUrl)_ | appId | `ConsentVersion` | `#blob #consent` |
435
+ | `blob` | `maintenance` | GET | `config/maintenance/{appId}.json` _(baseBlobUrl)_ | appId | `Maintenance` | `#blob` |
436
+ | `blob` | `blob` | GET | `{path}` _(baseBlobUrl)_ | path | `unknown` | `#blob` |
437
+
438
+ ---
439
+
440
+ ## API Reference
441
+
442
+ Every method accepts an optional `requestOptions` as the last argument for custom headers or query params.
443
+
444
+ ---
445
+
220
446
  ### AuthenticateApi
221
447
 
222
- Accessed via `bzbsService.authApi`.
448
+ `bzbsService.authApi` — Authentication, login providers, OTP, session management.
223
449
 
224
450
  | Method | Description | Returns |
225
451
  |---|---|---|
@@ -230,26 +456,27 @@ Accessed via `bzbsService.authApi`.
230
456
  | `appleLogin(params)` | Login with Apple ID token + refresh token | `LoginResponse` |
231
457
  | `appleToken(params)` | Request Apple refresh token | `AppleToken` |
232
458
  | `usernamePasswordLogin(params)` | Login with username/password | `LoginResponse` |
233
- | `connectLine(params)` | Connect/login with LINE | `LoginResponse` |
234
- | `connectFacebook(params)` | Connect/login with Facebook | `LoginResponse` |
235
- | `connectGoogle(params)` | Connect/login with Google | `LoginResponse` |
236
- | `connectApple(params)` | Connect/login with Apple | `LoginResponse` |
459
+ | `connectLine(params)` | Connect/link LINE to existing account | `LoginResponse` |
460
+ | `connectFacebook(params)` | Connect/link Facebook to existing account | `LoginResponse` |
461
+ | `connectGoogle(params)` | Connect/link Google to existing account | `LoginResponse` |
462
+ | `connectApple(params)` | Connect/link Apple to existing account | `LoginResponse` |
237
463
  | `logout(params)` | Logout user | `unknown` |
238
464
  | `forgetPassword(params)` | Send forget password request | `ForgetPasswordResponse` |
239
- | `resetPassword(params)` | Reset user password | `StatusResponse` |
240
- | `otp(params)` | Request OTP via GET | `OtpResponse` |
241
- | `otpV2(params)` | Request OTP via POST | `OtpResponse` |
465
+ | `resetPassword(params)` | Reset user password with OTP | `StatusResponse` |
466
+ | `otp(params)` | Request OTP (GET) | `OtpResponse` |
467
+ | `otpV2(params)` | Request OTP (POST) | `OtpResponse` |
242
468
  | `otpEmail(params)` | Request OTP via email | `OtpResponse` |
243
- | `confirmOtp(params)` | Confirm OTP | `ConfirmOtpResponse` |
244
- | `validateOtp(params)` | Validate OTP | `ValidateOtpResponse` |
245
- | `resume(params)` | Refresh token (session resume) | `ResumeResponse` |
246
- | `updateDevice(params)` | Update device token for push notifications | `ResumeResponse` |
469
+ | `confirmOtp(params)` | Confirm OTP for authentication | `ConfirmOtpResponse` |
470
+ | `validateOtp(params)` | Validate OTP (generic) | `ValidateOtpResponse` |
471
+ | `resume(params)` | Resume/refresh session | `ResumeResponse` |
472
+ | `updateDevice(params)` | Update device push token | `ResumeResponse` |
247
473
  | `version(clientVersion)` | Get app version info | `Version` |
248
474
  | `versionRaw(clientVersion)` | Get raw version info | `any` |
249
475
 
250
- #### Login Example
476
+ #### Examples
251
477
 
252
478
  ```typescript
479
+ // Device login
253
480
  const result = await bzbsService.authApi.deviceLogin({
254
481
  appId: 'your-app-id',
255
482
  uuid: 'device-uuid',
@@ -262,25 +489,14 @@ const result = await bzbsService.authApi.deviceLogin({
262
489
  macAddress: 'device-mac-address',
263
490
  });
264
491
 
265
- if (result.type === 'success') {
266
- const { token, userId, jwt } = result.model;
267
- // Store token for subsequent requests
268
- }
269
- ```
270
-
271
- #### OTP Flow Example
272
-
273
- ```typescript
274
- // 1. Request OTP
275
- const otpResult = await bzbsService.authApi.otp({
276
- uuid: 'device-uuid',
492
+ // OTP flow
493
+ const otpResult = await bzbsService.authApi.otpV2({
277
494
  appId: 'your-app-id',
278
495
  contactNumber: '0812345678',
279
496
  });
280
497
 
281
- // 2. Validate OTP
282
498
  if (otpResult.type === 'success') {
283
- const validateResult = await bzbsService.authApi.validateOtp({
499
+ const validated = await bzbsService.authApi.validateOtp({
284
500
  appId: 'your-app-id',
285
501
  otp: '123456',
286
502
  refCode: otpResult.model.refcode,
@@ -294,7 +510,7 @@ if (otpResult.type === 'success') {
294
510
 
295
511
  ### CampaignApi
296
512
 
297
- Accessed via `bzbsService.campaignApi`.
513
+ `bzbsService.campaignApi` — Campaign listing, details, redemption, and favorites.
298
514
 
299
515
  | Method | Description | Returns |
300
516
  |---|---|---|
@@ -317,14 +533,12 @@ Accessed via `bzbsService.campaignApi`.
317
533
  | `top` | `number` | No | Number of items to retrieve |
318
534
  | `keyword` | `string` | No | Search keyword |
319
535
  | `sortBy` | `string` | No | Sort order |
320
- | `center` | `string` | No | Geo coordinates for location-based search |
536
+ | `center` | `string` | No | Geo coordinates (`lat,lng`) for location-based search |
321
537
  | `hashTags` | `string` | No | Filter by hashtags |
322
538
  | `sponsorId` | `string` | No | Sponsor filter |
323
539
  | `minPoints` | `string` | No | Minimum points filter |
324
540
  | `maxPoints` | `string` | No | Maximum points filter |
325
541
 
326
- #### Example
327
-
328
542
  ```typescript
329
543
  // List campaigns
330
544
  const campaigns = await bzbsService.campaignApi.campaigns({
@@ -333,7 +547,6 @@ const campaigns = await bzbsService.campaignApi.campaigns({
333
547
  skip: 0,
334
548
  top: 20,
335
549
  keyword: 'coffee',
336
- sortBy: 'popular',
337
550
  });
338
551
 
339
552
  // Redeem a campaign
@@ -347,12 +560,13 @@ const redeem = await bzbsService.campaignApi.redeem({
347
560
 
348
561
  ### ProfileApi
349
562
 
350
- Accessed via `bzbsService.profileApi`.
563
+ `bzbsService.profileApi` — User profile management, points, password, contact number.
351
564
 
352
565
  | Method | Description | Returns |
353
566
  |---|---|---|
354
567
  | `profile()` | Get current user profile | `ProfileResponse` |
355
- | `updateProfile(params)` | Update user profile (supports image upload) | `ProfileResponse` |
568
+ | `updateProfile(params)` | Update user profile fields (JSON body) | `ProfileResponse` |
569
+ | `updateProfileImage(params)` | Upload profile picture (multipart/form-data) | `ProfileResponse` |
356
570
  | `changePassword(params)` | Change user password | `StatusResponse` |
357
571
  | `updateShipping(params)` | Update shipping information | `unknown` |
358
572
  | `changeContactNumber(params)` | Change contact number (v1) | `ConfirmOtpResponse` |
@@ -360,12 +574,10 @@ Accessed via `bzbsService.profileApi`.
360
574
  | `changeContactNumberV3(params)` | Change contact number by user ID (v3) | `any` |
361
575
  | `points()` | Get user's current points | `UpdatedPoints` |
362
576
  | `expiringPoints()` | Get user's expiring points | `ExpiringPoints` |
363
- | `deactivate()` | Deactivate user profile | `unknown` |
364
-
365
- #### Profile Update Example
577
+ | `deactivate()` | Deactivate user account | `unknown` |
366
578
 
367
579
  ```typescript
368
- // Update profile with image
580
+ // Update profile fields (JSON)
369
581
  const result = await bzbsService.profileApi.updateProfile({
370
582
  firstName: 'John',
371
583
  lastName: 'Doe',
@@ -373,7 +585,11 @@ const result = await bzbsService.profileApi.updateProfile({
373
585
  contactNumber: '0812345678',
374
586
  gender: 'male',
375
587
  birthDate: 946684800, // Unix timestamp in seconds
376
- profileImage: fileObject, // File, { uri, name, type }, or object
588
+ });
589
+
590
+ // Upload profile picture (multipart/form-data, field key: "data")
591
+ await bzbsService.profileApi.updateProfileImage({
592
+ image: imageFile, // File | { uri: string; name: string; type: string }
377
593
  });
378
594
  ```
379
595
 
@@ -381,7 +597,7 @@ const result = await bzbsService.profileApi.updateProfile({
381
597
 
382
598
  ### CartApi
383
599
 
384
- Accessed via `bzbsService.cartApi`.
600
+ `bzbsService.cartApi` — Shopping cart management.
385
601
 
386
602
  | Method | Description | Returns |
387
603
  |---|---|---|
@@ -398,7 +614,7 @@ const count = await bzbsService.cartApi.cartCount();
398
614
 
399
615
  ### CategoryApi
400
616
 
401
- Accessed via `bzbsService.categoryApi`.
617
+ `bzbsService.categoryApi` — Campaign categories.
402
618
 
403
619
  | Method | Description | Returns |
404
620
  |---|---|---|
@@ -415,11 +631,11 @@ const categories = await bzbsService.categoryApi.categories({
415
631
 
416
632
  ### CouponApi
417
633
 
418
- Accessed via `bzbsService.couponApi`.
634
+ `bzbsService.couponApi` — Coupon code processing.
419
635
 
420
636
  | Method | Description | Returns |
421
637
  |---|---|---|
422
- | `processCodes(params)` | Process coupon codes | `CouponResponse` |
638
+ | `processCodes(params)` | Process one or more coupon codes | `CouponResponse` |
423
639
 
424
640
  ```typescript
425
641
  const result = await bzbsService.couponApi.processCodes({
@@ -431,7 +647,7 @@ const result = await bzbsService.couponApi.processCodes({
431
647
 
432
648
  ### NotificationApi
433
649
 
434
- Accessed via `bzbsService.notificationApi`.
650
+ `bzbsService.notificationApi` — Push notification management.
435
651
 
436
652
  | Method | Description | Returns |
437
653
  |---|---|---|
@@ -440,23 +656,20 @@ Accessed via `bzbsService.notificationApi`.
440
656
 
441
657
  ```typescript
442
658
  const notifs = await bzbsService.notificationApi.notifications({
443
- mode: 'new', // 'new' | 'all'
659
+ mode: 'new', // 'new' | 'all'
444
660
  sortBy: 'createdate_desc',
445
661
  top: 20,
446
662
  skip: 0,
447
663
  });
448
664
 
449
- // Mark as read
450
- await bzbsService.notificationApi.read({
451
- ids: 'rowKey1,rowKey2',
452
- });
665
+ await bzbsService.notificationApi.read({ ids: 'rowKey1,rowKey2' });
453
666
  ```
454
667
 
455
668
  ---
456
669
 
457
670
  ### HistoryApi
458
671
 
459
- Accessed via `bzbsService.historyApi`.
672
+ `bzbsService.historyApi` — Redemption history and voucher usage.
460
673
 
461
674
  | Method | Description | Returns |
462
675
  |---|---|---|
@@ -471,7 +684,6 @@ const history = await bzbsService.historyApi.redeemHistories({
471
684
  top: 20,
472
685
  });
473
686
 
474
- // Use a coupon
475
687
  await bzbsService.historyApi.use({ redeemKey: 'ABC123_1' });
476
688
  ```
477
689
 
@@ -479,17 +691,17 @@ await bzbsService.historyApi.use({ redeemKey: 'ABC123_1' });
479
691
 
480
692
  ### RegistrationApi
481
693
 
482
- Accessed via `bzbsService.registerApi`.
694
+ `bzbsService.registerApi` — New user registration with OTP verification.
483
695
 
484
696
  | Method | Description | Returns |
485
697
  |---|---|---|
486
- | `validateRegister(params)` | Validate registration (triggers OTP) | `OtpResponse` |
698
+ | `validateRegister(params)` | Validate registration and trigger OTP | `OtpResponse` |
487
699
  | `register(params)` | Register a new user | `RegistrationResponse` |
488
700
 
489
701
  **Validation Error Codes:**
490
- - `2078` - Duplicate contact number
491
- - `2089` - Duplicate email
492
- - `401` - Duplicate username
702
+ - `2078` Duplicate contact number
703
+ - `2089` Duplicate email
704
+ - `401` Duplicate username
493
705
 
494
706
  ```typescript
495
707
  // Step 1: Validate
@@ -525,7 +737,7 @@ const registration = await bzbsService.registerApi.register({
525
737
 
526
738
  ### AddressApi
527
739
 
528
- Accessed via `bzbsService.addressApi`.
740
+ `bzbsService.addressApi` — User addresses and Thailand geographical data.
529
741
 
530
742
  | Method | Description | Returns |
531
743
  |---|---|---|
@@ -534,22 +746,19 @@ Accessed via `bzbsService.addressApi`.
534
746
  | `districts(params)` | Get districts by province | `District[]` |
535
747
  | `subDistricts(params)` | Get sub-districts by province/district | `SubDistrict[]` |
536
748
  | `userAddresses()` | Get user's saved addresses | `Address[]` |
537
- | `updateAddress(params)` | Create or update an address | `Address` |
749
+ | `updateAddress(params)` | Create or update a delivery address | `Address` |
538
750
  | `deleteAddress(params)` | Delete an address | `unknown` |
539
751
  | `userTaxAddresses()` | Get user's tax addresses | `Address[]` |
540
752
  | `updateTaxAddress(params)` | Create or update a tax address | `Address` |
541
753
  | `deleteTaxAddress(params)` | Delete a tax address | `unknown` |
542
754
 
543
755
  ```typescript
544
- // Get provinces
545
756
  const provinces = await bzbsService.addressApi.provinces();
546
757
 
547
- // Get districts for a province
548
758
  const districts = await bzbsService.addressApi.districts({
549
759
  provinceCode: '10',
550
760
  });
551
761
 
552
- // Save an address
553
762
  await bzbsService.addressApi.updateAddress({
554
763
  firstName: 'John',
555
764
  lastName: 'Doe',
@@ -568,15 +777,14 @@ await bzbsService.addressApi.updateAddress({
568
777
 
569
778
  ### BadgeApi
570
779
 
571
- Accessed via `bzbsService.badgeApi`.
780
+ `bzbsService.badgeApi` — User badges and mission progress.
572
781
 
573
782
  | Method | Description | Returns |
574
783
  |---|---|---|
575
- | `badges(params)` | Get user badges | `Badge[]` |
784
+ | `badges(params)` | Get user badges (opt: filter by badgeId) | `Badge[]` |
576
785
 
577
786
  ```typescript
578
787
  const badges = await bzbsService.badgeApi.badges({});
579
- // Or filter by badge ID
580
788
  const badge = await bzbsService.badgeApi.badges({ badgeId: '123' });
581
789
  ```
582
790
 
@@ -584,7 +792,9 @@ const badge = await bzbsService.badgeApi.badges({ badgeId: '123' });
584
792
 
585
793
  ### ConsentApi
586
794
 
587
- Accessed via `bzbsService.consentApi`.
795
+ `bzbsService.consentApi` — PDPA and marketing consent management.
796
+
797
+ > **v2 change:** `consent()` now calls `consent/status`; `updateConsent()` now calls `consent/consent`.
588
798
 
589
799
  | Method | Description | Returns |
590
800
  |---|---|---|
@@ -592,16 +802,18 @@ Accessed via `bzbsService.consentApi`.
592
802
  | `updateConsent(params)` | Update consent preferences | `Consent` |
593
803
  | `unconsent()` | Withdraw all consent | `unknown` |
594
804
 
595
- ```typescript
596
- // Get consent
597
- const consent = await bzbsService.consentApi.consent();
805
+ **`consentAge`** accepts one of:
806
+ - `'0'` — user has not consented to age verification
807
+ - `'1'` user has consented (age confirmed)
808
+ - The user's actual age as a string (e.g. `'25'`)
598
809
 
599
- // Update consent
810
+ ```typescript
600
811
  await bzbsService.consentApi.updateConsent({
601
812
  termsAndConditions: '1.0',
602
813
  dataPrivacy: '1.0',
603
814
  marketingOption: '1.0',
604
- email: '1', // '0' or '1'
815
+ consentAge: '25', // '0' | '1' | actual age string
816
+ email: '1', // '0' or '1'
605
817
  sms: '1',
606
818
  notification: '1',
607
819
  line: '0',
@@ -612,7 +824,9 @@ await bzbsService.consentApi.updateConsent({
612
824
 
613
825
  ### DashboardApi
614
826
 
615
- Accessed via `bzbsService.dashboardApi`.
827
+ `bzbsService.dashboardApi` — Dashboard content configuration.
828
+
829
+ > **v2 change:** Both `mainDashboard` and `subDashboard` now call `dashboard/config`. The `appName`/`dashboardName` param is sent as `config`.
616
830
 
617
831
  | Method | Description | Returns |
618
832
  |---|---|---|
@@ -621,12 +835,12 @@ Accessed via `bzbsService.dashboardApi`.
621
835
 
622
836
  ```typescript
623
837
  const dashboard = await bzbsService.dashboardApi.mainDashboard({
624
- appName: 'buzzebeesdemo',
625
- locale: 1054, // Thai locale
838
+ appName: 'buzzebeesdemo', // sent as `config` query param
839
+ locale: 1054,
626
840
  });
627
841
 
628
- const subDashboard = await bzbsService.dashboardApi.subDashboard({
629
- dashboardName: 'featured',
842
+ const sub = await bzbsService.dashboardApi.subDashboard({
843
+ dashboardName: 'featured', // sent as `config` query param
630
844
  locale: 1054,
631
845
  });
632
846
  ```
@@ -635,7 +849,7 @@ const subDashboard = await bzbsService.dashboardApi.subDashboard({
635
849
 
636
850
  ### LineApi
637
851
 
638
- Accessed via `bzbsService.lineApi` (only initialized if `baseLineUrl` is provided).
852
+ `bzbsService.lineApi` LINE OAuth token exchange. Only initialized when `baseLineUrl` is provided. Uses `baseLineUrl` as the base URL.
639
853
 
640
854
  | Method | Description | Returns |
641
855
  |---|---|---|
@@ -657,7 +871,7 @@ if (bzbsService.lineApi) {
657
871
 
658
872
  ### PlaceApi
659
873
 
660
- Accessed via `bzbsService.placeApi`.
874
+ `bzbsService.placeApi` — Location/store management with geo-search.
661
875
 
662
876
  | Method | Description | Returns |
663
877
  |---|---|---|
@@ -680,16 +894,16 @@ const places = await bzbsService.placeApi.placeList({
680
894
 
681
895
  ### PointLogApi
682
896
 
683
- Accessed via `bzbsService.pointLogApi`.
897
+ `bzbsService.pointLogApi` — Point transaction history.
684
898
 
685
899
  | Method | Description | Returns |
686
900
  |---|---|---|
687
- | `getPointLog(params)` | Get point transaction log | `PointLog[]` |
901
+ | `getPointLog(params)` | Get point transaction log by month | `PointLog[]` |
688
902
 
689
903
  ```typescript
690
904
  const logs = await bzbsService.pointLogApi.getPointLog({
691
905
  month: '2025-01',
692
- type: 'earn', // 'earn' | 'burn' | etc.
906
+ type: 'earn',
693
907
  top: 50,
694
908
  });
695
909
  ```
@@ -698,7 +912,7 @@ const logs = await bzbsService.pointLogApi.getPointLog({
698
912
 
699
913
  ### StampApi
700
914
 
701
- Accessed via `bzbsService.stampApi`.
915
+ `bzbsService.stampApi` — Stamp card system.
702
916
 
703
917
  | Method | Description | Returns |
704
918
  |---|---|---|
@@ -719,28 +933,26 @@ const profile = await bzbsService.stampApi.stampProfile({
719
933
 
720
934
  ### RequestHelpApi (Forum)
721
935
 
722
- Accessed via `bzbsService.forumApi`.
936
+ `bzbsService.forumApi` — Help/support forum (Buzz chat system).
723
937
 
724
938
  | Method | Description | Returns |
725
939
  |---|---|---|
726
940
  | `helpCode(params)` | Get help request code | `RequestHelpCode` |
727
- | `requestHelpList(params)` | List help request messages | `ChatMessage[]` |
728
- | `requestDetail(params)` | Get help request detail | `ChatMessage` |
729
- | `postRequestHelp(params)` | Post a help request (supports image) | `ChatMessage` |
941
+ | `requestHelpList(params)` | List messages in a help request | `ChatMessage[]` |
942
+ | `requestDetail(params)` | Get a specific message | `ChatMessage` |
943
+ | `postRequestHelp(params)` | Post a help message (supports image) | `ChatMessage` |
730
944
  | `comments(params)` | Get comments on a post | `ChatMessage[]` |
731
945
  | `postComment(params)` | Post a comment (supports image) | `ChatMessage` |
732
946
  | `like(params)` | Like a post | `LikeForumResponse` |
733
947
  | `unlike(params)` | Unlike a post | `LikeForumResponse` |
734
948
 
735
949
  ```typescript
736
- // Create a help request
737
950
  const helpCode = await bzbsService.forumApi.helpCode({
738
951
  os: 'ios 17.0',
739
952
  platform: 'iPhone',
740
953
  clientVersion: 'ios_myapp1.0.0',
741
954
  });
742
955
 
743
- // Post a message
744
956
  await bzbsService.forumApi.postRequestHelp({
745
957
  requestId: 'req-123',
746
958
  message: 'I need help with my order',
@@ -752,7 +964,9 @@ await bzbsService.forumApi.postRequestHelp({
752
964
 
753
965
  ### SettingApi
754
966
 
755
- Accessed via `bzbsService.settingApi`.
967
+ `bzbsService.settingApi` — Web landing page access tokens.
968
+
969
+ > **v2 change:** Endpoint changed from `setting` to `setting/add`.
756
970
 
757
971
  | Method | Description | Returns |
758
972
  |---|---|---|
@@ -774,12 +988,12 @@ const accessKey = await bzbsService.settingApi.accessKey({
774
988
 
775
989
  ### Blob
776
990
 
777
- Accessed via `bzbsService.blob`.
991
+ `bzbsService.blob` Blob storage retrieval. Uses `baseBlobUrl` as base URL.
778
992
 
779
993
  | Method | Description | Returns |
780
994
  |---|---|---|
781
- | `consentVersion(appId)` | Get PDPA consent version | `ConsentVersion` |
782
- | `maintenance(appId)` | Get maintenance configuration | `Maintenance` |
995
+ | `consentVersion(appId)` | Get PDPA consent document version | `ConsentVersion` |
996
+ | `maintenance(appId)` | Get app maintenance configuration | `Maintenance` |
783
997
  | `blob(path)` | Fetch any blob storage path | `unknown` |
784
998
 
785
999
  ```typescript
@@ -789,183 +1003,245 @@ const maintenance = await bzbsService.blob.maintenance('your-app-id');
789
1003
 
790
1004
  ---
791
1005
 
792
- ## Response Handling
1006
+ ## Models Reference
793
1007
 
794
- All API methods return `ServiceResponse<T>`, a discriminated union type:
1008
+ All TypeScript interfaces are exported from `@bzbs/react-api-client`:
795
1009
 
796
1010
  ```typescript
797
- type ServiceResponse<T> = SuccessResponse<T> | ErrorResponse;
1011
+ import {
1012
+ Campaign,
1013
+ CampaignDetail,
1014
+ ProfileResponse,
1015
+ LoginResponse,
1016
+ Purchase,
1017
+ // ... etc
1018
+ } from '@bzbs/react-api-client';
798
1019
  ```
799
1020
 
800
- ### Success Response
1021
+ ### Authentication Models
801
1022
 
802
- ```typescript
803
- type SuccessResponse<T> = {
804
- type: 'success';
805
- model: T; // The typed response data
806
- response: AxiosResponse; // Raw Axios response
807
- };
808
- ```
1023
+ | Model | Key Fields |
1024
+ |---|---|
1025
+ | `LoginResponse` | Token, UserId, UserCode, Username, Points, Consent fields, ProfileImage, Locale |
1026
+ | `ResumeResponse` | Same structure as LoginResponse |
1027
+ | `AppleToken` | refresh_token, id_token |
1028
+ | `LineAuthResponse` | access_token, token_type, refresh_token, expires_in, scope, id_token |
1029
+ | `OtpResponse` | refcode, channel, expiredate, expireinseconds |
1030
+ | `ConfirmOtpResponse` | status, token |
1031
+ | `ValidateOtpResponse` | validatecode |
1032
+ | `ForgetPasswordResponse` | status, refcode, expiredate, expireinseconds |
1033
+ | `RegistrationResponse` | Registration result with Buzzebees user account |
1034
+ | `Version` | allow_use, has_new_version, welcome_page_times |
1035
+
1036
+ ### Campaign Models
1037
+
1038
+ | Model | Key Fields |
1039
+ |---|---|
1040
+ | `Campaign` | ID, Name, Points, StartDate, EndDate, CategoryId, ImageUrl, Quantity, IsLike |
1041
+ | `CampaignDetail` | All Campaign fields + images (Picture[]), SubCampaigns, conditions, terms |
1042
+ | `Picture` | ID, Type, Sequence, ImageUrl |
1043
+ | `SubCampaign` | ID, Name, styles (SubCampaignStyle[]), quantity, points |
1044
+ | `RedeemResponse` | RedeemKey, PrivilegeMessageEN, PrivilegeMessageTH, UpdatedPoints, ExpiryDate |
1045
+ | `UseCampaignResponse` | PrivilegeMessageEN, PrivilegeMessageTH, redeemKey, points |
1046
+ | `FavoriteResponse` | totalLike, isLike |
1047
+ | `CouponResponse` | success/error results per code |
1048
+ | `Purchase` | RedeemKey, CampaignName, ExpiryDate, Status, Points, barcode, images |
1049
+
1050
+ ### Cart Models
1051
+
1052
+ | Model | Key Fields |
1053
+ |---|---|
1054
+ | `CartCountResponse` | cart_count |
1055
+ | `CartAccessResponse` | success, access key |
809
1056
 
810
- ### Error Response
1057
+ ### Profile & Points Models
811
1058
 
812
- ```typescript
813
- type ErrorResponse = ClientError | ServerError;
1059
+ | Model | Key Fields |
1060
+ |---|---|
1061
+ | `ProfileResponse` | UserId, Name, FirstName, LastName, Email, Contact_Number, address fields, TermAndCondition, DataPrivacy, MarketingOption, ConsentAge (0=not consented, 1=consented, or actual age), EmailMarketing, SMSMarketing, NotificationMarketing, LineMarketing, Token, Jwt, updated_points, Info1–Info10 (60+ fields) |
1062
+ | `UpdatedPoints` | points, time |
1063
+ | `ExpiringPoints` | expiringPoints, expiryDate |
1064
+ | `Badge` | badgeId, name, description, imageUrl, missions (Mission[]) |
1065
+ | `Mission` | missionId, name, current, target, isCompleted |
1066
+ | `PointLog` | UserId, Info, Detail, Points, Type, Timestamp |
814
1067
 
815
- type ServerError = {
816
- type: 'server-error';
817
- error: BzbsErrorResponse; // { requestId, error: { id, message, code, type } }
818
- statusCode: number;
819
- response: AxiosResponse;
820
- };
1068
+ ### Address & Location Models
821
1069
 
822
- type ClientError = {
823
- type: 'client-error';
824
- message: string;
825
- details?: any;
826
- };
827
- ```
1070
+ | Model | Key Fields |
1071
+ |---|---|
1072
+ | `Address` | rowKey, name, firstName, lastName, address, zipcode, province/district/subdistrict codes and names, contactNumber, isDefault, taxId |
1073
+ | `Province` | province_code, province_name_th, province_name_en |
1074
+ | `District` | district_code, district_name_th, district_name_en, province_code |
1075
+ | `SubDistrict` | subdistrict_code, subdistrict_name_th, zip_code |
1076
+ | `ZipCode` | Hierarchical address with zone info |
1077
+ | `Place` | id, name, latitude, longitude, address, workingHours, services, isFavorite |
828
1078
 
829
- ### Usage Pattern
1079
+ ### Consent & Settings Models
830
1080
 
831
- ```typescript
832
- const result = await bzbsService.campaignApi.campaigns({
833
- config: 'campaign_list',
834
- });
1081
+ | Model | Key Fields |
1082
+ |---|---|
1083
+ | `Consent` | TermAndCondition, DataPrivacy, MarketingOption, SMSMarketing, NotificationMarketing, LineMarketing, cookie consent flags |
1084
+ | `ConsentVersion` | version values per consent type |
1085
+ | `Version` | allow_use, has_new_version, welcome_page_times |
1086
+ | `Maintenance` | isUnderMaintenance, message, startDate, endDate |
835
1087
 
836
- switch (result.type) {
837
- case 'success':
838
- // result.model is Campaign[]
839
- console.log(result.model);
840
- break;
1088
+ ### Stamp & Dashboard Models
841
1089
 
842
- case 'server-error':
843
- // Server returned an error
844
- console.error(result.error.error?.message);
845
- console.error('Status:', result.statusCode);
846
- break;
1090
+ | Model | Key Fields |
1091
+ |---|---|
1092
+ | `Stamp` | stampId, cardId, count, maxCount, rewards, expiry |
1093
+ | `StampProfileResponse` | stamp card profile with history |
1094
+ | `CreateStampResponse` | result of stamp creation |
1095
+ | `Dashboard` | id, name, menuItems, images, startDate, endDate |
1096
+ | `Category` | id, name (TH/EN), subcategories, imageUrl |
847
1097
 
848
- case 'client-error':
849
- // Network error or client-side issue
850
- console.error(result.message);
851
- break;
852
- }
853
- ```
1098
+ ### Notification & Forum Models
854
1099
 
855
- ### Response Normalization
1100
+ | Model | Key Fields |
1101
+ |---|---|
1102
+ | `Notification` | notiId, title, message, objectType, imageUrl, expireDate, isRead |
1103
+ | `ChatMessage` | buzzKey, message, images, sender info, likes, comments count, createdDate (65+ fields) |
1104
+ | `LikeForumResponse` | likeCount, isLiked |
1105
+ | `RequestHelpCode` | helpCode |
856
1106
 
857
- The library automatically handles both uppercase and lowercase API response formats:
858
- - `{ Success: true, Data: ... }` and `{ success: true, data: ... }` are both supported
859
- - HTTP 204 responses return an empty object as the model
860
- - Non-standard responses (without success flags) are treated as raw data
1107
+ ### Error & Response Models
1108
+
1109
+ | Model | Key Fields |
1110
+ |---|---|
1111
+ | `BzbsErrorResponse` | requestId, error: { id, message, code, type } |
1112
+ | `StatusResponse` | status |
1113
+ | `AccessTokenResponse` | token key |
1114
+
1115
+ **Common Error Codes:**
1116
+
1117
+ | Code | Description |
1118
+ |---|---|
1119
+ | `401` | Unauthorized / Duplicate username |
1120
+ | `2078` | Duplicate contact number |
1121
+ | `2089` | Duplicate email |
861
1122
 
862
1123
  ---
863
1124
 
864
- ## Error Handling
1125
+ ## BaseService Utilities
865
1126
 
866
- ### BzbsErrorResponse
1127
+ ### createFormData
1128
+
1129
+ Static method for building `multipart/form-data` payloads. Skips `undefined`, `null`, and empty string values — preserves `0` and `false`.
867
1130
 
868
1131
  ```typescript
869
- interface BzbsErrorResponse {
870
- requestId?: string;
871
- error?: {
872
- id?: number;
873
- message?: string;
874
- code?: number;
875
- type?: string;
876
- };
877
- }
1132
+ const formData = BaseService.createFormData(
1133
+ { name: 'John', age: 0, active: false },
1134
+ 'profileImage', // optional file field key
1135
+ imageFile // optional File object
1136
+ );
878
1137
  ```
879
1138
 
880
- ### Common Error Codes
1139
+ ### setBaseUrl / setLineUrl / setBlobUrl
881
1140
 
882
- | Code | Description |
883
- |---|---|
884
- | `401` | Unauthorized / Duplicate username |
885
- | `2078` | Duplicate contact number |
886
- | `2089` | Duplicate email |
1141
+ Update base URLs at runtime (propagates to all sub-services):
1142
+
1143
+ ```typescript
1144
+ bzbsService.setBaseUrl('https://new-api.buzzebees.com/api/');
1145
+ bzbsService.setLineUrl('https://api.line.me/');
1146
+ bzbsService.setBlobUrl('https://new-blob.buzzebees.com/');
1147
+ ```
887
1148
 
888
1149
  ---
889
1150
 
890
- ## Models
1151
+ ## Testing Guide
1152
+
1153
+ Tests are in the `tests/` directory, mirroring `src/` structure.
891
1154
 
892
- All TypeScript interfaces are exported from `@bzbs/react-api-client` and can be imported directly:
1155
+ ### Test Utilities (`tests/helpers/test-utils.ts`)
893
1156
 
894
1157
  ```typescript
895
1158
  import {
896
- Campaign,
897
- CampaignDetail,
898
- ProfileResponse,
899
- LoginResponse,
900
- Purchase,
901
- // ... etc
902
- } from '@bzbs/react-api-client';
1159
+ createMockClient,
1160
+ createSuccessResponse,
1161
+ createRawSuccessResponse,
1162
+ createServerErrorResponse,
1163
+ createAxiosError,
1164
+ createDeviceParams,
1165
+ } from '../helpers/test-utils';
1166
+
1167
+ // Create mocked Axios instance
1168
+ const { client, mockRequest } = createMockClient();
1169
+
1170
+ // Mock a wrapped success response: { Success: true, Data: {...} }
1171
+ mockRequest.mockResolvedValue(createSuccessResponse({ id: '123' }));
1172
+
1173
+ // Mock a raw success (no wrapper)
1174
+ mockRequest.mockResolvedValue(createRawSuccessResponse({ id: '123' }));
1175
+
1176
+ // Mock a server error response
1177
+ mockRequest.mockResolvedValue(createServerErrorResponse());
1178
+
1179
+ // Mock a network error (client error)
1180
+ mockRequest.mockRejectedValue(createAxiosError());
1181
+
1182
+ // Standard device parameters (appId, uuid, os, platform, clientVersion, macAddress, deviceToken, ...)
1183
+ const deviceParams = createDeviceParams();
903
1184
  ```
904
1185
 
905
- ### Key Models
1186
+ ### Test Pattern
906
1187
 
907
- | Model | Description |
908
- |---|---|
909
- | `LoginResponse` | Token, userId, jwt, consent status, points |
910
- | `Campaign` | Campaign list item (ID, name, points, dates, images) |
911
- | `CampaignDetail` | Full campaign details with pictures, subcampaigns, conditions |
912
- | `ProfileResponse` | User profile with personal info, address, shipping, marketing preferences |
913
- | `Purchase` | Redeem history item with usage status, voucher info, delivery status |
914
- | `Address` | User address with full Thailand address structure, tax fields |
915
- | `Notification` | Push notification with object type, category, read status |
916
- | `Place` | Store/place with location, services, working hours |
917
- | `Dashboard` | Dashboard configuration item with images and metadata |
918
- | `Consent` | User consent status for terms, privacy, marketing channels, cookies |
919
- | `ConsentVersion` | PDPA consent version from blob storage |
920
- | `Maintenance` | App maintenance configuration |
921
- | `Badge` | User badge information |
922
- | `Category` | Campaign category |
923
- | `PointLog` | Point transaction record |
924
- | `Stamp` | Stamp card information |
925
- | `StampProfileResponse` | Stamp card profile details |
926
- | `OtpResponse` | OTP request response with reference code |
927
- | `ConfirmOtpResponse` | OTP confirmation result |
928
- | `ValidateOtpResponse` | OTP validation result |
929
- | `RedeemResponse` | Campaign redemption result |
930
- | `FavoriteResponse` | Favorite toggle response |
931
- | `UseCampaignResponse` | Coupon usage result |
932
- | `CartCountResponse` | Cart item count |
933
- | `CartAccessResponse` | Cart web landing access token |
934
- | `AccessTokenResponse` | Web landing access token |
935
- | `LineAuthResponse` | LINE OAuth token response |
936
- | `AppleToken` | Apple refresh token response |
937
- | `ResumeResponse` | Session resume/token refresh response |
938
- | `Version` | App version info |
939
- | `RegistrationResponse` | Registration result |
940
- | `ForgetPasswordResponse` | Password reset request result |
941
- | `StatusResponse` | Generic status response |
942
- | `RequestHelpCode` | Help request code |
943
- | `ChatMessage` | Forum/help chat message |
944
- | `LikeForumResponse` | Forum like/unlike result |
945
- | `Province` | Thailand province |
946
- | `District` | Thailand district |
947
- | `SubDistrict` | Thailand sub-district |
948
- | `ZipCode` | Zip code information |
949
- | `UpdatedPoints` | User points with timestamp |
950
- | `ExpiringPoints` | User expiring points info |
951
- | `PointUnit` | Point service unit configuration |
1188
+ ```typescript
1189
+ import { AuthenticateApi } from '../../src/api/auth/auth-api';
1190
+ import { createMockClient, createSuccessResponse, createDeviceParams } from '../helpers/test-utils';
952
1191
 
953
- ---
1192
+ describe('AuthenticateApi', () => {
1193
+ let api: AuthenticateApi;
1194
+ let mockRequest: jest.Mock;
1195
+
1196
+ beforeEach(() => {
1197
+ const { client, mockRequest: mock } = createMockClient();
1198
+ mockRequest = mock;
1199
+ api = new AuthenticateApi(client, 'https://api.buzzebees.com/');
1200
+ });
1201
+
1202
+ it('deviceLogin returns success', async () => {
1203
+ const data = { Token: 'abc', UserId: '1' };
1204
+ mockRequest.mockResolvedValue(createSuccessResponse(data));
1205
+
1206
+ const result = await api.deviceLogin(createDeviceParams());
1207
+
1208
+ expect(result.type).toBe('success');
1209
+ if (result.type === 'success') {
1210
+ expect(result.model.Token).toBe('abc');
1211
+ }
1212
+ expect(mockRequest).toHaveBeenCalledWith(
1213
+ expect.objectContaining({ url: 'auth/device_login', method: 'post' })
1214
+ );
1215
+ });
1216
+
1217
+ it('deviceLogin handles server error', async () => {
1218
+ mockRequest.mockResolvedValue(createServerErrorResponse());
1219
+
1220
+ const result = await api.deviceLogin(createDeviceParams());
1221
+
1222
+ expect(result.type).toBe('server-error');
1223
+ });
1224
+ });
1225
+ ```
954
1226
 
955
- ## Development
1227
+ ### Run Tests
956
1228
 
957
- ### Prerequisites
1229
+ ```bash
1230
+ npm test # Watch mode with coverage
1231
+ npx jest --coverage # Single run with coverage
1232
+ npx jest tests/api/auth # Run specific folder
1233
+ npx jest --testNamePattern otp # Run tests matching pattern
1234
+ ```
958
1235
 
959
- - Node.js
960
- - npm
1236
+ ---
961
1237
 
962
- ### Commands
1238
+ ## Development Commands
963
1239
 
964
1240
  ```bash
965
1241
  # Install dependencies
966
1242
  npm install
967
1243
 
968
- # Build the library (CJS + ESM + type declarations)
1244
+ # Build (CJS + ESM + type declarations → dist/)
969
1245
  npm run build
970
1246
 
971
1247
  # Run tests in watch mode with coverage
@@ -979,20 +1255,18 @@ npm run lint:fix
979
1255
 
980
1256
  # Format code with Prettier
981
1257
  npm run format
982
- ```
983
1258
 
984
- ### Publishing
985
-
986
- ```bash
987
- npm run patch # Build, bump patch version, publish
988
- npm run minor # Build, bump minor version, publish
989
- npm run major # Build, bump major version, publish
1259
+ # Publish (build + version bump + npm publish)
1260
+ npm run patch # 1.4.14 → 1.4.15
1261
+ npm run minor # 1.4.14 → 1.5.0
1262
+ npm run major # 1.4.14 2.0.0
990
1263
  ```
991
1264
 
992
- ### Adding a New API
1265
+ ---
1266
+
1267
+ ## Adding a New API
993
1268
 
994
- 1. Create a new directory under `src/api/` (e.g., `src/api/my-feature/`)
995
- 2. Create an API class that extends `BaseService`:
1269
+ 1. Create `src/api/my-feature/my-feature-api.ts`:
996
1270
 
997
1271
  ```typescript
998
1272
  import { AxiosInstance } from 'axios';
@@ -1005,31 +1279,35 @@ export class MyFeatureApi extends BaseService {
1005
1279
  }
1006
1280
 
1007
1281
  public async getItems(
1008
- params: { id: string; options?: { [key: string]: unknown } },
1282
+ params: { id: string },
1009
1283
  requestOptions?: RequestOptions
1010
1284
  ): Promise<ServiceResponse<MyModel[]>> {
1011
- return await this.get<MyModel[]>(
1012
- `my-feature/${params.id}`,
1013
- { ...params.options },
1014
- requestOptions
1015
- );
1285
+ return await this.get<MyModel[]>(`my-feature/${params.id}`, {}, requestOptions);
1016
1286
  }
1017
1287
  }
1018
1288
  ```
1019
1289
 
1020
- 3. Create model interfaces in `src/models/`
1021
- 4. Export from `src/models/index.ts` and `src/api/index.ts`
1022
- 5. Add the API to `BzbsService` class and its `setBaseUrl()` method
1290
+ 2. Create model interface in `src/models/my-model.ts` and export from `src/models/index.ts`
1291
+ 3. Export from `src/api/index.ts`
1292
+ 4. Add to `BzbsService` constructor and `setBaseUrl()` method in `src/api/bzbs-service.ts`
1023
1293
 
1024
1294
  ---
1025
1295
 
1026
1296
  ## Build Output
1027
1297
 
1028
- The build process (tsup) generates:
1029
-
1030
1298
  | File | Format | Description |
1031
1299
  |---|---|---|
1032
1300
  | `dist/index.js` | CommonJS | For `require()` usage |
1033
1301
  | `dist/index.mjs` | ES Module | For `import` usage |
1034
1302
  | `dist/index.d.ts` | TypeScript | Type declarations |
1035
1303
  | `dist/*.map` | Source Maps | For debugging |
1304
+
1305
+ ### Package Exports
1306
+
1307
+ ```json
1308
+ {
1309
+ "main": "./dist/index.js",
1310
+ "module": "./dist/index.mjs",
1311
+ "types": "./dist/index.d.ts"
1312
+ }
1313
+ ```