@codeswayam/api-client 1.3.1 → 1.3.2

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,176 +1,961 @@
1
1
  # @codeswayam/api-client
2
2
 
3
- Low-level HTTP client and typed API functions for the Codeswayam platform. Used internally by `@codeswayam/auth` — most apps should use that package instead.
3
+ > The canonical HTTP client and TypeScript SDK for all CodeSwayam API interactions.
4
+
5
+ [![Version](https://img.shields.io/badge/version-1.3.2-blue.svg)](./package.json)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
7
+ [![Axios](https://img.shields.io/badge/HTTP-Axios-blue.svg)](https://axios-http.com/)
8
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)
9
+
10
+ `@codeswayam/api-client` is the low-level HTTP SDK that powers every CodeSwayam application. It wraps the CodeSwayam REST API with typed functions and a class-based SDK interface, handling authentication headers, cookie credentials, and response parsing so your app code never has to.
11
+
12
+ ---
13
+
14
+ ## Table of Contents
15
+
16
+ - [Overview](#overview)
17
+ - [Installation](#installation)
18
+ - [Peer Dependencies](#peer-dependencies)
19
+ - [Authentication](#authentication)
20
+ - [SDK Class](#codeswayamsdk-class)
21
+ - [API Reference](#api-reference)
22
+ - [Auth Functions](#auth-functions)
23
+ - [Subscription Functions](#subscription-functions)
24
+ - [Credit Functions](#credit-functions)
25
+ - [Referral Functions](#referral-functions)
26
+ - [Entitlement Functions](#entitlement-functions)
27
+ - [Notification Functions](#notification-functions)
28
+ - [Admin Functions](#admin-functions)
29
+ - [TypeScript Types](#typescript-types)
30
+ - [Code Examples](#code-examples)
31
+ - [Integration Guide (Next.js)](#integration-guide-nextjs)
32
+ - [Error Handling](#error-handling)
33
+ - [Changelog](#changelog)
34
+
35
+ ---
36
+
37
+ ## Overview
38
+
39
+ `@codeswayam/api-client` is the foundation layer of the CodeSwayam SDK stack:
40
+
41
+ ```
42
+ @codeswayam/auth — Auth, guards, SSO, notifications
43
+
44
+ @codeswayam/access — Entitlements, feature gates, usage
45
+
46
+ @codeswayam/api-client — HTTP client, types, raw API functions
47
+ ```
48
+
49
+ All packages in the CodeSwayam ecosystem call into `@codeswayam/api-client` for network requests. You can use this package directly for advanced use cases, admin tooling, or building custom integrations.
50
+
51
+ **Key design decisions:**
52
+
53
+ | Decision | Detail |
54
+ |---|---|
55
+ | HTTP library | Axios — consistent request/response interceptors |
56
+ | Auth strategy | Dual: `credentials: 'include'` (cookie) + `Authorization: Bearer` header fallback |
57
+ | Token source | `localStorage` via `getAuthHeaders()` |
58
+ | TypeScript | All functions and types are fully typed |
59
+ | Tree-shaking | Named exports only — import only what you use |
60
+
61
+ ---
4
62
 
5
63
  ## Installation
6
64
 
7
65
  ```bash
8
66
  npm install @codeswayam/api-client
67
+ # or
68
+ yarn add @codeswayam/api-client
69
+ # or
70
+ pnpm add @codeswayam/api-client
9
71
  ```
10
72
 
11
73
  ---
12
74
 
13
- ## When to use this directly
75
+ ## Peer Dependencies
14
76
 
15
- Use `@codeswayam/api-client` directly when:
16
- - Writing **server-side** code (NestJS services, Next.js server actions)
17
- - Building **admin tools** that need raw API access
18
- - You need functions not exposed by `@codeswayam/auth`
77
+ | Package | Version |
78
+ |---|---|
79
+ | `axios` | `^1.0.0` |
19
80
 
20
- For everything else, use `@codeswayam/auth`.
81
+ ```bash
82
+ npm install axios
83
+ ```
21
84
 
22
85
  ---
23
86
 
24
- ## SDK Class
87
+ ## Authentication
25
88
 
26
- ```typescript
89
+ All API functions in this package authenticate using a dual strategy:
90
+
91
+ ### 1. HTTP Cookies (primary)
92
+ All requests are made with `withCredentials: true`, which sends the `csw_session` HttpOnly cookie automatically if present.
93
+
94
+ ### 2. Bearer Token (fallback)
95
+ `getAuthHeaders()` reads the JWT from localStorage and returns an `Authorization` header. Used as a fallback when cookies are unavailable (e.g. cross-origin requests).
96
+
97
+ ```ts
98
+ import { getAuthHeaders } from '@codeswayam/api-client';
99
+
100
+ // Returns: { Authorization: 'Bearer eyJ...' }
101
+ // Returns: {} if no token is stored
102
+ const headers = getAuthHeaders();
103
+ ```
104
+
105
+ The token is stored under the key `CSW_TOKEN_KEY` (re-exported from `@codeswayam/auth`).
106
+
107
+ ---
108
+
109
+ ## `CodeSwayamSDK` Class
110
+
111
+ For applications that need a configured SDK instance (e.g. with a custom base URL), use the `CodeSwayamSDK` class.
112
+
113
+ ```ts
27
114
  import { CodeSwayamSDK } from '@codeswayam/api-client';
28
115
 
29
116
  const sdk = new CodeSwayamSDK({
30
- baseUrl: process.env.NEXT_PUBLIC_API_URL,
31
- onUnauthorized: () => redirectToLogin(),
117
+ baseUrl: 'https://api.codeswayam.com',
118
+ });
119
+
120
+ // Generic request method
121
+ const data = await sdk.request<ResponseType>({
122
+ method: 'GET',
123
+ path: '/v1/some-endpoint',
124
+ params: { foo: 'bar' },
32
125
  });
33
126
 
34
- // Auth
127
+ // Namespaced API groups
35
128
  const profile = await sdk.auth.getProfile();
129
+ const entitlements = await sdk.entitlements.fetchMyEntitlements('auraflow');
130
+ ```
36
131
 
37
- // Billing
38
- const subs = await sdk.billing.getSubscriptions();
132
+ **Constructor options:**
39
133
 
40
- // Credits
41
- const wallet = await sdk.credits.getWallet();
134
+ | Option | Type | Required | Description |
135
+ |---|---|---|---|
136
+ | `baseUrl` | `string` | ✅ | Base URL for all API requests |
137
+ | `timeout` | `number` | — | Request timeout in ms (default: `10000`) |
138
+ | `headers` | `Record<string, string>` | — | Additional headers for every request |
42
139
 
43
- // Entitlements
44
- const canUse = sdk.entitlements.canAccess('smart_ai', activeSubs);
45
- const remaining = sdk.entitlements.getRemainingLimit('max_automations', 5, activeSubs);
140
+ **SDK namespaces:**
46
141
 
47
- // Full profile in one call
48
- const { profile, subscriptions, wallet } = await sdk.getFullProfile();
49
- ```
142
+ | Namespace | Methods |
143
+ |---|---|
144
+ | `sdk.auth` | `getProfile`, `login`, `logout`, `getUsersBatch` |
145
+ | `sdk.entitlements` | `fetchMyEntitlements`, `trackUsage`, `getAllAppsEntitlements` |
50
146
 
51
147
  ---
52
148
 
53
- ## Auth Functions
149
+ ## API Reference
54
150
 
55
- ```typescript
56
- import { getSession, fetchProfile, updateProfile, logout } from '@codeswayam/api-client';
151
+ ### Auth Functions
57
152
 
58
- const user = await getSession(); // { id, email, name, access_scopes }
59
- const profile = await fetchProfile();
60
- await updateProfile({ name: 'New Name' });
61
- await logout();
153
+ ```ts
154
+ import {
155
+ getProfile,
156
+ login,
157
+ logout,
158
+ getUsersBatch,
159
+ } from '@codeswayam/api-client';
62
160
  ```
63
161
 
162
+ | Function | Signature | Description |
163
+ |---|---|---|
164
+ | `getProfile` | `() => Promise<CSWUser>` | Fetch the authenticated user's profile |
165
+ | `login` | `(email: string, password: string) => Promise<{ token: string; user: CSWUser }>` | Email/password login (non-SSO apps) |
166
+ | `logout` | `() => Promise<void>` | Invalidate the current session |
167
+ | `getUsersBatch` | `(userIds: string[]) => Promise<CSWUser[]>` | Fetch multiple user profiles by ID |
168
+
64
169
  ---
65
170
 
66
- ## Subscription Functions
171
+ ### Subscription Functions
67
172
 
68
- ```typescript
173
+ ```ts
69
174
  import {
70
- fetchPublicPlans,
71
175
  fetchUserSubscriptions,
72
176
  fetchSubscriptionById,
73
- createRazorpayOrder,
74
- verifyRazorpayPayment,
177
+ fetchPublicPlans,
75
178
  changeSubscriptionPlan,
76
179
  cancelUserSubscription,
77
180
  } from '@codeswayam/api-client';
181
+ ```
78
182
 
79
- // Public plans (no auth needed)
80
- const { products, bundles } = await fetchPublicPlans();
183
+ | Function | Signature | Description |
184
+ |---|---|---|
185
+ | `fetchUserSubscriptions` | `() => Promise<UserSubscription[]>` | All subscriptions for the authenticated user |
186
+ | `fetchSubscriptionById` | `(id: string) => Promise<UserSubscription>` | Single subscription by ID |
187
+ | `fetchPublicPlans` | `(appId?: string) => Promise<SaasProduct[]>` | Publicly listed plans (for pricing pages) |
188
+ | `changeSubscriptionPlan` | `(subscriptionId: string, newPlanId: string) => Promise<UserSubscription>` | Upgrade or downgrade a subscription |
189
+ | `cancelUserSubscription` | `(subscriptionId: string) => Promise<void>` | Cancel a subscription |
81
190
 
82
- // User's subscriptions
83
- const subs = await fetchUserSubscriptions();
84
- const sub = await fetchSubscriptionById(123);
191
+ ---
85
192
 
86
- // Payment — pass returnUrl for cross-domain redirect, and optional upgradeFromSubscriptionId
87
- const order = await createRazorpayOrder({
88
- saasProductId: 1,
89
- billingCycle: 'monthly',
90
- currency: 'INR',
91
- returnUrl: `${window.location.origin}/dashboard`,
92
- upgradeFromSubscriptionId: 123, // Optional: old subscription ID to upgrade from (prorates cost)
93
- });
193
+ ### Credit Functions
94
194
 
95
- await verifyRazorpayPayment({
96
- razorpay_order_id: order.orderId,
97
- razorpay_payment_id: paymentId,
98
- razorpay_signature: signature,
99
- saasProductId: 1,
100
- billingCycle: 'monthly',
101
- currency: 'INR',
102
- amount: order.amount,
103
- upgradeFromSubscriptionId: 123, // Pass old subscription ID to automatically cancel it upon payment success
104
- });
195
+ ```ts
196
+ import {
197
+ fetchMyWallet,
198
+ useCredits,
199
+ fetchCreditPacks,
200
+ fetchFeatureCosts,
201
+ createCreditPurchaseOrder,
202
+ verifyCreditPurchase,
203
+ } from '@codeswayam/api-client';
204
+ ```
105
205
 
106
- // Upgrade/downgrade
107
- await changeSubscriptionPlan(subId, {
108
- saasProductId: 2,
109
- billingCycle: 'yearly',
110
- currency: 'INR',
111
- });
206
+ | Function | Signature | Description |
207
+ |---|---|---|
208
+ | `fetchMyWallet` | `() => Promise<UserWalletResponse>` | Current balance, transactions, and feature costs |
209
+ | `useCredits` | `(feature: string) => Promise<CreditTransaction>` | Deduct credits for a feature use |
210
+ | `fetchCreditPacks` | `() => Promise<CreditPack[]>` | Available credit packs for purchase |
211
+ | `fetchFeatureCosts` | `() => Promise<FeatureCreditCost[]>` | Per-feature credit cost table |
212
+ | `createCreditPurchaseOrder` | `(packId: string) => Promise<{ orderId: string; amount: number; currency: string }>` | Create a Razorpay order for a credit pack |
213
+ | `verifyCreditPurchase` | `(payload: VerifyPurchasePayload) => Promise<UserWalletResponse>` | Verify a Razorpay payment and credit the wallet |
214
+
215
+ ---
216
+
217
+ ### Referral Functions
112
218
 
113
- await cancelUserSubscription(subId);
219
+ ```ts
220
+ import {
221
+ fetchReferralStats,
222
+ redeemReferralCode,
223
+ redeemCouponCode,
224
+ } from '@codeswayam/api-client';
114
225
  ```
115
226
 
227
+ | Function | Signature | Description |
228
+ |---|---|---|
229
+ | `fetchReferralStats` | `() => Promise<ReferralStats>` | Referral link, history, and earned rewards |
230
+ | `redeemReferralCode` | `(code: string) => Promise<{ creditsEarned: number }>` | Apply a friend's referral code |
231
+ | `redeemCouponCode` | `(code: string) => Promise<{ creditsEarned: number; discount?: number }>` | Apply a promotional coupon code |
232
+
116
233
  ---
117
234
 
118
- ## Credits Functions
235
+ ### Entitlement Functions
236
+
237
+ The core functions consumed by `@codeswayam/access`. You can call these directly for server-side data fetching.
238
+
239
+ ```ts
240
+ import {
241
+ fetchMyEntitlements,
242
+ trackUsage,
243
+ getAllAppsEntitlements,
244
+ } from '@codeswayam/api-client';
245
+ ```
246
+
247
+ | Function | Signature | Description |
248
+ |---|---|---|
249
+ | `fetchMyEntitlements` | `(appId: string) => Promise<EntitlementResult>` | Full entitlements for a specific app |
250
+ | `trackUsage` | `(payload: TrackUsagePayload) => Promise<TrackUsageResult>` | Increment a usage counter |
251
+ | `getAllAppsEntitlements` | `() => Promise<AppEntitlementSummary[]>` | Entitlements across all apps (admin / dashboard use) |
252
+
253
+ **`TrackUsagePayload`:**
119
254
 
120
255
  ```typescript
256
+ interface TrackUsagePayload {
257
+ appId: string;
258
+ counterKey: string;
259
+ increment?: number; // defaults to 1
260
+ }
261
+ ```
262
+
263
+ ---
264
+
265
+ ### Notification Functions
266
+
267
+ ```ts
121
268
  import {
122
- fetchMyWallet,
123
- fetchCreditPacks,
124
- fetchFeatureCosts,
125
- createCreditPurchaseOrder,
126
- verifyCreditPurchase,
127
- useCredits,
269
+ registerPushSubscription,
270
+ unregisterPushSubscription,
271
+ fetchVapidPublicKey,
272
+ sendNotificationCampaign,
273
+ fetchNotificationCampaigns,
274
+ fetchNotificationStats,
275
+ deleteNotificationCampaign,
128
276
  } from '@codeswayam/api-client';
277
+ ```
278
+
279
+ | Function | Signature | Description |
280
+ |---|---|---|
281
+ | `fetchVapidPublicKey` | `() => Promise<{ publicKey: string }>` | Fetch the VAPID public key for Web Push |
282
+ | `registerPushSubscription` | `(subscription: PushSubscription) => Promise<void>` | Register a browser push subscription |
283
+ | `unregisterPushSubscription` | `(endpoint: string) => Promise<void>` | Remove a push subscription |
284
+ | `sendNotificationCampaign` | `(payload: NotificationPayload) => Promise<NotificationCampaign>` | Send a push notification campaign (admin) |
285
+ | `fetchNotificationCampaigns` | `() => Promise<NotificationCampaign[]>` | List all notification campaigns (admin) |
286
+ | `fetchNotificationStats` | `(campaignId: string) => Promise<NotificationStats>` | Delivery and click stats for a campaign (admin) |
287
+ | `deleteNotificationCampaign` | `(campaignId: string) => Promise<void>` | Delete a notification campaign (admin) |
288
+
289
+ ---
129
290
 
130
- const { wallet, transactions } = await fetchMyWallet();
131
- const packs = await fetchCreditPacks();
132
- const costs = await fetchFeatureCosts('auraflow');
291
+ ### Admin Functions
133
292
 
134
- // Deduct credits (server-side)
135
- await useCredits({ saasId: 'auraflow', featureKey: 'ai_chat', quantity: 1 });
293
+ Admin-only functions. All require the caller to have an `admin` role; the API will return `403` otherwise.
294
+
295
+ ```ts
296
+ import {
297
+ // User admin
298
+ adminListUsers,
299
+ adminGetUser,
300
+ adminUpdateUser,
301
+ adminDeleteUser,
302
+ // Subscription admin
303
+ adminListSubscriptions,
304
+ adminUpdateSubscription,
305
+ // Credit admin
306
+ adminAdjustCredits,
307
+ adminListCreditTransactions,
308
+ // Settings admin
309
+ adminGetSettings,
310
+ adminUpdateSettings,
311
+ } from '@codeswayam/api-client';
136
312
  ```
137
313
 
314
+ | Function | Description |
315
+ |---|---|
316
+ | `adminListUsers` | Paginated list of all users |
317
+ | `adminGetUser(userId)` | Fetch a single user by ID |
318
+ | `adminUpdateUser(userId, data)` | Update user fields (role, name, etc.) |
319
+ | `adminDeleteUser(userId)` | Permanently delete a user account |
320
+ | `adminListSubscriptions` | List all subscriptions (all users) |
321
+ | `adminUpdateSubscription(id, data)` | Override subscription fields |
322
+ | `adminAdjustCredits(userId, amount, reason)` | Manually add or remove credits |
323
+ | `adminListCreditTransactions` | Paginated credit transaction log |
324
+ | `adminGetSettings` | Fetch platform-wide settings |
325
+ | `adminUpdateSettings(settings)` | Update platform settings |
326
+
138
327
  ---
139
328
 
140
- ## Cross-Domain Auth
329
+ ## TypeScript Types
330
+
331
+ All types are exported from the package root:
332
+
333
+ ```ts
334
+ import type {
335
+ // Products & subscriptions
336
+ SaasProduct,
337
+ UserSubscription,
338
+ // Credits
339
+ CreditPack,
340
+ UserCredits,
341
+ CreditTransaction,
342
+ FeatureCreditCost,
343
+ UserWalletResponse,
344
+ // Referrals
345
+ ReferralStats,
346
+ ReferralHistoryItem,
347
+ // Entitlements
348
+ EntitlementResult,
349
+ AppEntitlementSummary,
350
+ TrackUsagePayload,
351
+ TrackUsageResult,
352
+ UsageSummary,
353
+ // Notifications
354
+ NotificationPayload,
355
+ NotificationCampaign,
356
+ NotificationStats,
357
+ } from '@codeswayam/api-client';
358
+ ```
141
359
 
142
- All functions automatically inject the Bearer token from localStorage for cross-domain compatibility:
360
+ ### Interface Definitions
143
361
 
144
362
  ```typescript
145
- import { getAuthHeaders } from '@codeswayam/api-client';
363
+ interface SaasProduct {
364
+ id: string;
365
+ name: string;
366
+ appId: string;
367
+ planType: string; // e.g. "pro_monthly"
368
+ billingCycle: 'monthly' | 'annual';
369
+ price: number;
370
+ currency: string;
371
+ features: Record<string, boolean | number>;
372
+ isActive: boolean;
373
+ }
374
+
375
+ interface UserSubscription {
376
+ id: string;
377
+ userId: string;
378
+ productId: string;
379
+ appId: string;
380
+ status: 'active' | 'cancelled' | 'expired' | 'trialing';
381
+ planType: string;
382
+ billingCycle: 'monthly' | 'annual';
383
+ currentPeriodStart: string;
384
+ currentPeriodEnd: string;
385
+ expiresAt: string | null;
386
+ cancelledAt: string | null;
387
+ }
388
+
389
+ interface CreditPack {
390
+ id: string;
391
+ name: string;
392
+ credits: number;
393
+ price: number;
394
+ currency: string;
395
+ bonus?: number; // Bonus credits for promotional packs
396
+ isPopular?: boolean;
397
+ }
398
+
399
+ interface UserCredits {
400
+ userId: string;
401
+ balance: number;
402
+ lifetimeEarned: number;
403
+ lifetimeSpent: number;
404
+ }
405
+
406
+ interface CreditTransaction {
407
+ id: string;
408
+ userId: string;
409
+ type: 'earned' | 'spent' | 'purchased' | 'adjusted' | 'refunded';
410
+ amount: number;
411
+ feature?: string;
412
+ description: string;
413
+ createdAt: string;
414
+ }
415
+
416
+ interface FeatureCreditCost {
417
+ featureKey: string;
418
+ cost: number;
419
+ appId?: string;
420
+ }
421
+
422
+ interface UserWalletResponse {
423
+ credits: UserCredits;
424
+ recentTransactions: CreditTransaction[];
425
+ featureCosts: FeatureCreditCost[];
426
+ }
427
+
428
+ interface ReferralStats {
429
+ referralCode: string;
430
+ referralUrl: string;
431
+ totalReferrals: number;
432
+ creditsEarned: number;
433
+ history: ReferralHistoryItem[];
434
+ }
435
+
436
+ interface ReferralHistoryItem {
437
+ id: string;
438
+ referredUserId: string;
439
+ referredUserName: string;
440
+ creditsEarned: number;
441
+ createdAt: string;
442
+ }
443
+
444
+ interface EntitlementResult {
445
+ appId: string;
446
+ userId: string;
447
+ role: string;
448
+ tier: {
449
+ name: string;
450
+ label: string;
451
+ aiIncluded: boolean;
452
+ };
453
+ subscription: {
454
+ id: string;
455
+ status: string;
456
+ planType: string;
457
+ expiresAt: string | null;
458
+ billingCycle: string;
459
+ } | null;
460
+ credits: {
461
+ balance: number;
462
+ featureCosts: Record<string, number>;
463
+ };
464
+ usage: Record<string, UsageSummary>;
465
+ features: Record<string, boolean | number>;
466
+ }
467
+
468
+ interface AppEntitlementSummary {
469
+ appId: string;
470
+ tier: string;
471
+ hasActivePlan: boolean;
472
+ usageSummaries: Record<string, UsageSummary>;
473
+ }
474
+
475
+ interface TrackUsagePayload {
476
+ appId: string;
477
+ counterKey: string;
478
+ increment?: number;
479
+ }
480
+
481
+ interface TrackUsageResult {
482
+ counterKey: string;
483
+ used: number;
484
+ limit: number;
485
+ remaining: number;
486
+ percentage: number;
487
+ }
488
+
489
+ interface UsageSummary {
490
+ used: number;
491
+ limit: number;
492
+ remaining: number;
493
+ percentage: number;
494
+ }
495
+
496
+ interface NotificationPayload {
497
+ title: string;
498
+ body: string;
499
+ icon?: string;
500
+ url?: string;
501
+ targetUserIds?: string[]; // empty = broadcast to all
502
+ appId?: string;
503
+ }
504
+
505
+ interface NotificationCampaign {
506
+ id: string;
507
+ title: string;
508
+ body: string;
509
+ sentAt: string;
510
+ targetCount: number;
511
+ deliveredCount: number;
512
+ status: 'pending' | 'sent' | 'failed';
513
+ }
514
+
515
+ interface NotificationStats {
516
+ campaignId: string;
517
+ sent: number;
518
+ delivered: number;
519
+ clicked: number;
520
+ failed: number;
521
+ deliveryRate: number;
522
+ clickRate: number;
523
+ }
524
+ ```
146
525
 
147
- // Use in any custom fetch call
148
- const headers = getAuthHeaders();
149
- fetch(`${apiUrl}/my-endpoint`, { headers });
526
+ ---
527
+
528
+ ## Code Examples
529
+
530
+ ### 1. SDK Initialization
531
+
532
+ ```ts
533
+ import { CodeSwayamSDK } from '@codeswayam/api-client';
534
+
535
+ // Create a configured SDK instance
536
+ export const sdk = new CodeSwayamSDK({
537
+ baseUrl: process.env.NEXT_PUBLIC_API_URL ?? 'https://api.codeswayam.com',
538
+ timeout: 15_000,
539
+ });
540
+
541
+ // Use throughout your app
542
+ export default sdk;
543
+ ```
544
+
545
+ Or use standalone functions (recommended for tree-shaking):
546
+
547
+ ```ts
548
+ // Import only what you need
549
+ import { fetchMyEntitlements, trackUsage } from '@codeswayam/api-client';
150
550
  ```
151
551
 
152
552
  ---
153
553
 
154
- ## Referrals & Coupons
554
+ ### 2. `fetchMyEntitlements` Usage
155
555
 
156
- ```typescript
157
- import { fetchReferralStats, redeemReferralCode, redeemCouponCode } from '@codeswayam/api-client';
556
+ ```ts
557
+ import { fetchMyEntitlements } from '@codeswayam/api-client';
558
+
559
+ // Fetch full entitlements for the 'auraflow' app
560
+ async function loadAccess() {
561
+ const entitlements = await fetchMyEntitlements('auraflow');
158
562
 
159
- const stats = await fetchReferralStats();
160
- await redeemReferralCode('FRIEND123');
161
- await redeemCouponCode('LAUNCH50');
563
+ console.log('Tier:', entitlements.tier.name);
564
+ console.log('DM usage:', entitlements.usage['dms']);
565
+ console.log('AI chat feature:', entitlements.features['ai_chat']);
566
+ }
567
+
568
+ // Server-side usage in Next.js (App Router)
569
+ import { cookies } from 'next/headers';
570
+
571
+ export async function getUserEntitlements(appId: string) {
572
+ // fetchMyEntitlements uses cookies: 'include' — works server-side
573
+ // when the request context has the session cookie
574
+ return fetchMyEntitlements(appId);
575
+ }
162
576
  ```
163
577
 
164
578
  ---
165
579
 
166
- ## Push Notifications
580
+ ### 3. `trackUsage` Usage
167
581
 
168
- ```typescript
169
- import { registerPushSubscription, fetchVapidPublicKey } from '@codeswayam/api-client';
582
+ ```ts
583
+ import { trackUsage } from '@codeswayam/api-client';
584
+
585
+ // Track a single DM send
586
+ async function onMessageSent() {
587
+ const result = await trackUsage({
588
+ appId: 'auraflow',
589
+ counterKey: 'dms',
590
+ increment: 1, // optional, defaults to 1
591
+ });
592
+
593
+ console.log(`DMs used: ${result.used}/${result.limit}`);
594
+
595
+ if (result.remaining === 0) {
596
+ showUpgradePrompt();
597
+ }
598
+ }
599
+
600
+ // Track a bulk operation
601
+ async function onBulkExport(count: number) {
602
+ const result = await trackUsage({
603
+ appId: 'auraflow',
604
+ counterKey: 'exports',
605
+ increment: count,
606
+ });
607
+
608
+ return result;
609
+ }
610
+ ```
611
+
612
+ ---
613
+
614
+ ### 4. `fetchMyWallet` + `useCredits`
615
+
616
+ ```ts
617
+ import { fetchMyWallet, useCredits } from '@codeswayam/api-client';
618
+
619
+ // Load the wallet on component mount
620
+ async function initWallet() {
621
+ const wallet = await fetchMyWallet();
622
+
623
+ console.log('Balance:', wallet.credits.balance);
624
+ console.log('AI chat costs:', wallet.featureCosts.find(f => f.featureKey === 'ai_chat')?.cost);
625
+
626
+ return wallet;
627
+ }
628
+
629
+ // Deduct credits when a feature is used
630
+ async function consumeAiCredit() {
631
+ try {
632
+ const transaction = await useCredits('ai_chat');
633
+ console.log('Credits deducted:', transaction.amount);
634
+ console.log('New balance available via fetchMyWallet()');
635
+ } catch (error) {
636
+ // API returns 402 when balance is insufficient
637
+ if ((error as any).response?.status === 402) {
638
+ console.error('Insufficient credits');
639
+ showBuyCreditsModal();
640
+ }
641
+ }
642
+ }
643
+ ```
644
+
645
+ ---
646
+
647
+ ### 5. Push Notification Registration
648
+
649
+ ```ts
650
+ import {
651
+ fetchVapidPublicKey,
652
+ registerPushSubscription,
653
+ unregisterPushSubscription,
654
+ } from '@codeswayam/api-client';
655
+
656
+ // Register the browser for push notifications
657
+ async function enablePushNotifications() {
658
+ // 1. Check browser support
659
+ if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
660
+ console.warn('Push notifications not supported');
661
+ return;
662
+ }
663
+
664
+ // 2. Request permission
665
+ const permission = await Notification.requestPermission();
666
+ if (permission !== 'granted') return;
667
+
668
+ // 3. Fetch VAPID public key from server
669
+ const { publicKey } = await fetchVapidPublicKey();
670
+
671
+ // 4. Get push subscription from browser
672
+ const registration = await navigator.serviceWorker.ready;
673
+ const subscription = await registration.pushManager.subscribe({
674
+ userVisibleOnly: true,
675
+ applicationServerKey: publicKey,
676
+ });
677
+
678
+ // 5. Register with CodeSwayam API
679
+ await registerPushSubscription(subscription);
680
+ console.log('Push notifications enabled');
681
+ }
682
+
683
+ // Unregister
684
+ async function disablePushNotifications(endpoint: string) {
685
+ await unregisterPushSubscription(endpoint);
686
+ console.log('Push notifications disabled');
687
+ }
688
+ ```
689
+
690
+ ---
691
+
692
+ ### 6. `CodeSwayamSDK` Class Usage
693
+
694
+ ```ts
695
+ import { CodeSwayamSDK } from '@codeswayam/api-client';
696
+
697
+ const sdk = new CodeSwayamSDK({
698
+ baseUrl: 'https://api.codeswayam.com',
699
+ });
700
+
701
+ // Using namespaced methods
702
+ async function bootstrap(appId: string) {
703
+ const [profile, entitlements] = await Promise.all([
704
+ sdk.auth.getProfile(),
705
+ sdk.entitlements.fetchMyEntitlements(appId),
706
+ ]);
707
+
708
+ return { profile, entitlements };
709
+ }
710
+
711
+ // Using the generic request method for custom endpoints
712
+ async function fetchCustomData<T>(path: string): Promise<T> {
713
+ return sdk.request<T>({
714
+ method: 'GET',
715
+ path,
716
+ });
717
+ }
718
+
719
+ // POST with body
720
+ async function postCustomData<T>(path: string, body: unknown): Promise<T> {
721
+ return sdk.request<T>({
722
+ method: 'POST',
723
+ path,
724
+ data: body,
725
+ });
726
+ }
727
+ ```
728
+
729
+ ---
730
+
731
+ ### 7. Subscription Management
732
+
733
+ ```ts
734
+ import {
735
+ fetchUserSubscriptions,
736
+ fetchPublicPlans,
737
+ changeSubscriptionPlan,
738
+ cancelUserSubscription,
739
+ } from '@codeswayam/api-client';
170
740
 
171
- const { publicKey } = await fetchVapidPublicKey();
172
- const sub = await navigator.serviceWorker.ready.then(sw =>
173
- sw.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: publicKey })
174
- );
175
- await registerPushSubscription(sub.toJSON(), 'auraflow');
741
+ // Load current subscriptions + available plans
742
+ async function loadSubscriptionPage(appId: string) {
743
+ const [subscriptions, plans] = await Promise.all([
744
+ fetchUserSubscriptions(),
745
+ fetchPublicPlans(appId),
746
+ ]);
747
+
748
+ const active = subscriptions.find(
749
+ s => s.appId === appId && s.status === 'active'
750
+ );
751
+
752
+ return { active, plans };
753
+ }
754
+
755
+ // Upgrade subscription
756
+ async function upgradeToPro(subscriptionId: string, proPlanId: string) {
757
+ const updated = await changeSubscriptionPlan(subscriptionId, proPlanId);
758
+ console.log('Upgraded to:', updated.planType);
759
+ return updated;
760
+ }
761
+
762
+ // Cancel subscription
763
+ async function cancelPlan(subscriptionId: string) {
764
+ await cancelUserSubscription(subscriptionId);
765
+ console.log('Subscription cancelled');
766
+ }
176
767
  ```
768
+
769
+ ---
770
+
771
+ ### 8. Admin: Adjust Credits
772
+
773
+ ```ts
774
+ import { adminAdjustCredits } from '@codeswayam/api-client';
775
+
776
+ // Grant 100 bonus credits to a user (admin only)
777
+ async function grantBonusCredits(userId: string) {
778
+ await adminAdjustCredits(userId, 100, 'Promotional bonus — Q4 campaign');
779
+ console.log('Credited 100 bonus credits to user', userId);
780
+ }
781
+
782
+ // Deduct credits as penalty (negative amount)
783
+ async function deductCredits(userId: string) {
784
+ await adminAdjustCredits(userId, -50, 'Chargeback adjustment');
785
+ }
786
+ ```
787
+
788
+ ---
789
+
790
+ ## Integration Guide (Next.js)
791
+
792
+ ### Server-Side Data Fetching (App Router)
793
+
794
+ ```ts
795
+ // app/dashboard/page.tsx
796
+ import { fetchMyEntitlements } from '@codeswayam/api-client';
797
+
798
+ export default async function DashboardPage() {
799
+ // Server Component — runs on the server with the user's cookie
800
+ const entitlements = await fetchMyEntitlements('auraflow');
801
+
802
+ return (
803
+ <main>
804
+ <p>Tier: {entitlements.tier.label}</p>
805
+ <p>Credits: {entitlements.credits.balance}</p>
806
+ </main>
807
+ );
808
+ }
809
+ ```
810
+
811
+ ### API Route Handler
812
+
813
+ ```ts
814
+ // app/api/usage/route.ts
815
+ import { trackUsage } from '@codeswayam/api-client';
816
+ import { NextRequest, NextResponse } from 'next/server';
817
+
818
+ export async function POST(req: NextRequest) {
819
+ const { appId, counterKey, increment } = await req.json();
820
+
821
+ const result = await trackUsage({ appId, counterKey, increment });
822
+
823
+ return NextResponse.json(result);
824
+ }
825
+ ```
826
+
827
+ ### Client-Side Usage
828
+
829
+ ```tsx
830
+ // components/WalletWidget.tsx
831
+ 'use client';
832
+ import { fetchMyWallet } from '@codeswayam/api-client';
833
+ import { useEffect, useState } from 'react';
834
+ import type { UserWalletResponse } from '@codeswayam/api-client';
835
+
836
+ export function WalletWidget() {
837
+ const [wallet, setWallet] = useState<UserWalletResponse | null>(null);
838
+
839
+ useEffect(() => {
840
+ fetchMyWallet().then(setWallet);
841
+ }, []);
842
+
843
+ if (!wallet) return <span>Loading...</span>;
844
+
845
+ return <span>{wallet.credits.balance} credits</span>;
846
+ }
847
+ ```
848
+
849
+ > **Note:** For React-based apps, prefer `@codeswayam/access` hooks (`useAppAccess`, `useCSWCredits`) over calling `@codeswayam/api-client` functions directly in components. The hooks provide SWR caching and auto-revalidation.
850
+
851
+ ---
852
+
853
+ ## Error Handling
854
+
855
+ All functions throw Axios errors on HTTP failures. The response body contains error details:
856
+
857
+ ```ts
858
+ import { fetchMyEntitlements } from '@codeswayam/api-client';
859
+ import axios from 'axios';
860
+
861
+ async function safeLoad(appId: string) {
862
+ try {
863
+ return await fetchMyEntitlements(appId);
864
+ } catch (error) {
865
+ if (axios.isAxiosError(error)) {
866
+ const status = error.response?.status;
867
+ const message = error.response?.data?.message;
868
+
869
+ if (status === 401) {
870
+ // Token expired or missing — redirect to login
871
+ redirectToLogin();
872
+ } else if (status === 403) {
873
+ // Authenticated but not authorized (e.g. wrong role)
874
+ console.error('Access denied:', message);
875
+ } else if (status === 402) {
876
+ // Insufficient credits
877
+ showBuyCreditsModal();
878
+ } else {
879
+ console.error('API error:', status, message);
880
+ }
881
+ }
882
+ throw error;
883
+ }
884
+ }
885
+ ```
886
+
887
+ **Common HTTP status codes:**
888
+
889
+ | Status | Meaning |
890
+ |---|---|
891
+ | `200` | Success |
892
+ | `400` | Bad request (invalid params) |
893
+ | `401` | Unauthenticated — token missing or expired |
894
+ | `402` | Payment required — insufficient credits |
895
+ | `403` | Forbidden — authenticated but not authorized |
896
+ | `404` | Resource not found |
897
+ | `429` | Rate limited |
898
+ | `500` | Internal server error |
899
+
900
+ ---
901
+
902
+ ## Source Structure
903
+
904
+ ```
905
+ packages/api-client/src/
906
+ ├── index.ts — Barrel exports (all functions and types)
907
+ ├── client.ts — Axios instance configuration
908
+ ├── auth.ts — getAuthHeaders(), token utilities
909
+ ├── sdk.ts — CodeSwayamSDK class
910
+ ├── functions/
911
+ │ ├── auth.ts — getProfile, login, logout, getUsersBatch
912
+ │ ├── subscriptions.ts — Subscription CRUD functions
913
+ │ ├── credits.ts — Wallet, purchase, usage functions
914
+ │ ├── referrals.ts — Referral and coupon functions
915
+ │ ├── entitlements.ts — fetchMyEntitlements, trackUsage
916
+ │ ├── notifications.ts — Push notification functions
917
+ │ └── admin.ts — Admin-only functions
918
+ └── types/
919
+ ├── index.ts — Re-exports all types
920
+ ├── subscriptions.ts
921
+ ├── credits.ts
922
+ ├── entitlements.ts
923
+ └── notifications.ts
924
+ ```
925
+
926
+ ---
927
+
928
+ ## Changelog
929
+
930
+ ### v1.3.1
931
+ - Fixed `fetchVapidPublicKey` timeout on slow networks
932
+ - `trackUsage` now returns full `TrackUsageResult` including `percentage`
933
+
934
+ ### v1.3.0
935
+ - Added `getAllAppsEntitlements()` for cross-app dashboard use cases
936
+ - Added `deleteNotificationCampaign()`
937
+ - Added `fetchNotificationStats()` with delivery and click rate fields
938
+
939
+ ### v1.2.0
940
+ - Added `sendNotificationCampaign()` for admin push campaigns
941
+ - Added `fetchNotificationCampaigns()`
942
+ - `CodeSwayamSDK` class: added `sdk.entitlements` namespace
943
+
944
+ ### v1.1.0
945
+ - Added `redeemCouponCode()` for promotional codes
946
+ - Added `createCreditPurchaseOrder()` and `verifyCreditPurchase()` (Razorpay integration)
947
+ - `fetchMyWallet` now includes `featureCosts` in the response
948
+
949
+ ### v1.0.0 — Initial Release
950
+ - Auth functions: `getProfile`, `login`, `logout`, `getUsersBatch`
951
+ - Subscription functions: full CRUD
952
+ - Credit functions: wallet, packs, feature costs
953
+ - Referral functions: stats and redeem
954
+ - Entitlement functions: `fetchMyEntitlements`, `trackUsage`
955
+ - `CodeSwayamSDK` class with `sdk.auth` namespace
956
+ - `getAuthHeaders()` utility
957
+ - Full TypeScript types
958
+
959
+ ---
960
+
961
+ *Part of the [CodeSwayam](https://codeswayam.com) platform. For support, open an issue in the monorepo.*