perspectapi-ts-sdk 3.0.2 → 3.2.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/dist/index.d.mts +167 -1
- package/dist/index.d.ts +167 -1
- package/dist/index.js +261 -0
- package/dist/index.mjs +260 -0
- package/package.json +1 -1
- package/src/client/bundles-client.ts +263 -0
- package/src/client/site-users-client.ts +115 -0
- package/src/index.ts +8 -0
- package/src/perspect-api-client.ts +3 -0
- package/src/types/index.ts +92 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundles & Collections client for PerspectAPI SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { BaseClient } from './base-client';
|
|
6
|
+
import type { CacheManager } from '../cache/cache-manager';
|
|
7
|
+
import type { CachePolicy } from '../cache/types';
|
|
8
|
+
import type {
|
|
9
|
+
ProductBundleGroup,
|
|
10
|
+
CreateBundleGroupRequest,
|
|
11
|
+
BundleCollection,
|
|
12
|
+
CreateBundleCollectionRequest,
|
|
13
|
+
BundleCollectionItem,
|
|
14
|
+
BundleCollectionItemWithProduct,
|
|
15
|
+
AddCollectionItemRequest,
|
|
16
|
+
ApiResponse,
|
|
17
|
+
} from '../types';
|
|
18
|
+
|
|
19
|
+
export class BundlesClient extends BaseClient {
|
|
20
|
+
constructor(http: any, cache?: CacheManager) {
|
|
21
|
+
super(http, '/api/v1', cache);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// BUNDLE GROUPS (structural "pick N items" on a product)
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
async getBundleGroups(
|
|
29
|
+
siteName: string,
|
|
30
|
+
productId: number,
|
|
31
|
+
cachePolicy?: CachePolicy
|
|
32
|
+
): Promise<ApiResponse<ProductBundleGroup[]>> {
|
|
33
|
+
const endpoint = this.siteScopedEndpoint(
|
|
34
|
+
siteName,
|
|
35
|
+
`/products/${productId}/bundle-groups`,
|
|
36
|
+
{ includeSitesSegment: false }
|
|
37
|
+
);
|
|
38
|
+
const path = this.buildPath(endpoint);
|
|
39
|
+
|
|
40
|
+
return this.fetchWithCache<ApiResponse<ProductBundleGroup[]>>(
|
|
41
|
+
endpoint,
|
|
42
|
+
undefined,
|
|
43
|
+
this.buildBundleTags(siteName, [`bundles:product:${productId}`]),
|
|
44
|
+
cachePolicy,
|
|
45
|
+
() => this.http.get<ProductBundleGroup[]>(path)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async createBundleGroup(
|
|
50
|
+
siteName: string,
|
|
51
|
+
productId: number,
|
|
52
|
+
data: CreateBundleGroupRequest
|
|
53
|
+
): Promise<ApiResponse<ProductBundleGroup>> {
|
|
54
|
+
const endpoint = this.siteScopedEndpoint(
|
|
55
|
+
siteName,
|
|
56
|
+
`/products/${productId}/bundle-groups`,
|
|
57
|
+
{ includeSitesSegment: false }
|
|
58
|
+
);
|
|
59
|
+
return this.create(endpoint, data);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async updateBundleGroup(
|
|
63
|
+
siteName: string,
|
|
64
|
+
productId: number,
|
|
65
|
+
bundleGroupId: number,
|
|
66
|
+
data: Partial<CreateBundleGroupRequest>
|
|
67
|
+
): Promise<ApiResponse<ProductBundleGroup>> {
|
|
68
|
+
const endpoint = this.siteScopedEndpoint(
|
|
69
|
+
siteName,
|
|
70
|
+
`/products/${productId}/bundle-groups/${bundleGroupId}`,
|
|
71
|
+
{ includeSitesSegment: false }
|
|
72
|
+
);
|
|
73
|
+
return this.patch(endpoint, data);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async deleteBundleGroup(
|
|
77
|
+
siteName: string,
|
|
78
|
+
productId: number,
|
|
79
|
+
bundleGroupId: number
|
|
80
|
+
): Promise<ApiResponse<{ message: string }>> {
|
|
81
|
+
const endpoint = this.siteScopedEndpoint(
|
|
82
|
+
siteName,
|
|
83
|
+
`/products/${productId}/bundle-groups/${bundleGroupId}`,
|
|
84
|
+
{ includeSitesSegment: false }
|
|
85
|
+
);
|
|
86
|
+
return this.delete<{ message: string }>(endpoint);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// BUNDLE COLLECTIONS (time-bounded, site-scoped sets of products)
|
|
91
|
+
// ============================================================================
|
|
92
|
+
|
|
93
|
+
async getCollections(
|
|
94
|
+
siteName: string,
|
|
95
|
+
cachePolicy?: CachePolicy
|
|
96
|
+
): Promise<ApiResponse<BundleCollection[]>> {
|
|
97
|
+
const endpoint = this.siteScopedEndpoint(
|
|
98
|
+
siteName,
|
|
99
|
+
'/collections',
|
|
100
|
+
{ includeSitesSegment: false }
|
|
101
|
+
);
|
|
102
|
+
const path = this.buildPath(endpoint);
|
|
103
|
+
|
|
104
|
+
return this.fetchWithCache<ApiResponse<BundleCollection[]>>(
|
|
105
|
+
endpoint,
|
|
106
|
+
undefined,
|
|
107
|
+
this.buildCollectionTags(siteName, ['collections:list']),
|
|
108
|
+
cachePolicy,
|
|
109
|
+
() => this.http.get<BundleCollection[]>(path)
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async getCurrentCollection(
|
|
114
|
+
siteName: string,
|
|
115
|
+
cachePolicy?: CachePolicy
|
|
116
|
+
): Promise<ApiResponse<BundleCollection & { items: BundleCollectionItemWithProduct[] }>> {
|
|
117
|
+
const endpoint = this.siteScopedEndpoint(
|
|
118
|
+
siteName,
|
|
119
|
+
'/collections/current',
|
|
120
|
+
{ includeSitesSegment: false }
|
|
121
|
+
);
|
|
122
|
+
const path = this.buildPath(endpoint);
|
|
123
|
+
|
|
124
|
+
return this.fetchWithCache<ApiResponse<BundleCollection & { items: BundleCollectionItemWithProduct[] }>>(
|
|
125
|
+
endpoint,
|
|
126
|
+
undefined,
|
|
127
|
+
this.buildCollectionTags(siteName, ['collections:current']),
|
|
128
|
+
cachePolicy,
|
|
129
|
+
() => this.http.get(path)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async getCollection(
|
|
134
|
+
siteName: string,
|
|
135
|
+
collectionId: number,
|
|
136
|
+
cachePolicy?: CachePolicy
|
|
137
|
+
): Promise<ApiResponse<BundleCollection & { items: BundleCollectionItemWithProduct[] }>> {
|
|
138
|
+
const endpoint = this.siteScopedEndpoint(
|
|
139
|
+
siteName,
|
|
140
|
+
`/collections/${collectionId}`,
|
|
141
|
+
{ includeSitesSegment: false }
|
|
142
|
+
);
|
|
143
|
+
const path = this.buildPath(endpoint);
|
|
144
|
+
|
|
145
|
+
return this.fetchWithCache<ApiResponse<BundleCollection & { items: BundleCollectionItemWithProduct[] }>>(
|
|
146
|
+
endpoint,
|
|
147
|
+
undefined,
|
|
148
|
+
this.buildCollectionTags(siteName, [`collections:id:${collectionId}`]),
|
|
149
|
+
cachePolicy,
|
|
150
|
+
() => this.http.get(path)
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async createCollection(
|
|
155
|
+
siteName: string,
|
|
156
|
+
data: CreateBundleCollectionRequest
|
|
157
|
+
): Promise<ApiResponse<BundleCollection>> {
|
|
158
|
+
const endpoint = this.siteScopedEndpoint(
|
|
159
|
+
siteName,
|
|
160
|
+
'/collections',
|
|
161
|
+
{ includeSitesSegment: false }
|
|
162
|
+
);
|
|
163
|
+
return this.create(endpoint, data);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async updateCollection(
|
|
167
|
+
siteName: string,
|
|
168
|
+
collectionId: number,
|
|
169
|
+
data: Partial<CreateBundleCollectionRequest>
|
|
170
|
+
): Promise<ApiResponse<BundleCollection>> {
|
|
171
|
+
const endpoint = this.siteScopedEndpoint(
|
|
172
|
+
siteName,
|
|
173
|
+
`/collections/${collectionId}`,
|
|
174
|
+
{ includeSitesSegment: false }
|
|
175
|
+
);
|
|
176
|
+
return this.patch(endpoint, data);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async deleteCollection(
|
|
180
|
+
siteName: string,
|
|
181
|
+
collectionId: number
|
|
182
|
+
): Promise<ApiResponse<{ message: string }>> {
|
|
183
|
+
const endpoint = this.siteScopedEndpoint(
|
|
184
|
+
siteName,
|
|
185
|
+
`/collections/${collectionId}`,
|
|
186
|
+
{ includeSitesSegment: false }
|
|
187
|
+
);
|
|
188
|
+
return this.delete<{ message: string }>(endpoint);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ============================================================================
|
|
192
|
+
// COLLECTION ITEMS
|
|
193
|
+
// ============================================================================
|
|
194
|
+
|
|
195
|
+
async getCollectionItems(
|
|
196
|
+
siteName: string,
|
|
197
|
+
collectionId: number,
|
|
198
|
+
cachePolicy?: CachePolicy
|
|
199
|
+
): Promise<ApiResponse<BundleCollectionItemWithProduct[]>> {
|
|
200
|
+
const endpoint = this.siteScopedEndpoint(
|
|
201
|
+
siteName,
|
|
202
|
+
`/collections/${collectionId}/items`,
|
|
203
|
+
{ includeSitesSegment: false }
|
|
204
|
+
);
|
|
205
|
+
const path = this.buildPath(endpoint);
|
|
206
|
+
|
|
207
|
+
return this.fetchWithCache<ApiResponse<BundleCollectionItemWithProduct[]>>(
|
|
208
|
+
endpoint,
|
|
209
|
+
undefined,
|
|
210
|
+
this.buildCollectionTags(siteName, [`collections:items:${collectionId}`]),
|
|
211
|
+
cachePolicy,
|
|
212
|
+
() => this.http.get(path)
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async addCollectionItem(
|
|
217
|
+
siteName: string,
|
|
218
|
+
collectionId: number,
|
|
219
|
+
data: AddCollectionItemRequest
|
|
220
|
+
): Promise<ApiResponse<BundleCollectionItem>> {
|
|
221
|
+
const endpoint = this.siteScopedEndpoint(
|
|
222
|
+
siteName,
|
|
223
|
+
`/collections/${collectionId}/items`,
|
|
224
|
+
{ includeSitesSegment: false }
|
|
225
|
+
);
|
|
226
|
+
return this.create(endpoint, data);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async removeCollectionItem(
|
|
230
|
+
siteName: string,
|
|
231
|
+
collectionId: number,
|
|
232
|
+
itemId: number
|
|
233
|
+
): Promise<ApiResponse<{ message: string }>> {
|
|
234
|
+
const endpoint = this.siteScopedEndpoint(
|
|
235
|
+
siteName,
|
|
236
|
+
`/collections/${collectionId}/items/${itemId}`,
|
|
237
|
+
{ includeSitesSegment: false }
|
|
238
|
+
);
|
|
239
|
+
return this.delete<{ message: string }>(endpoint);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ============================================================================
|
|
243
|
+
// CACHE TAGS
|
|
244
|
+
// ============================================================================
|
|
245
|
+
|
|
246
|
+
private buildBundleTags(siteName?: string, extraTags: string[] = []): string[] {
|
|
247
|
+
const tags = new Set<string>(['bundles']);
|
|
248
|
+
if (siteName) {
|
|
249
|
+
tags.add(`bundles:site:${siteName}`);
|
|
250
|
+
}
|
|
251
|
+
extraTags.filter(Boolean).forEach(tag => tags.add(tag));
|
|
252
|
+
return Array.from(tags.values());
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private buildCollectionTags(siteName?: string, extraTags: string[] = []): string[] {
|
|
256
|
+
const tags = new Set<string>(['collections']);
|
|
257
|
+
if (siteName) {
|
|
258
|
+
tags.add(`collections:site:${siteName}`);
|
|
259
|
+
}
|
|
260
|
+
extraTags.filter(Boolean).forEach(tag => tags.add(tag));
|
|
261
|
+
return Array.from(tags.values());
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -10,6 +10,9 @@ import type {
|
|
|
10
10
|
SiteUserProfile,
|
|
11
11
|
SiteUserSubscription,
|
|
12
12
|
SiteUserOrder,
|
|
13
|
+
CreditBalance,
|
|
14
|
+
CreditBalanceWithTransactions,
|
|
15
|
+
GrantCreditRequest,
|
|
13
16
|
RequestOtpRequest,
|
|
14
17
|
VerifyOtpRequest,
|
|
15
18
|
VerifyOtpResponse,
|
|
@@ -290,6 +293,68 @@ export class SiteUsersClient extends BaseClient {
|
|
|
290
293
|
);
|
|
291
294
|
}
|
|
292
295
|
|
|
296
|
+
/**
|
|
297
|
+
* Pause a subscription via Stripe pause_collection
|
|
298
|
+
* @param siteName - The site name
|
|
299
|
+
* @param subscriptionId - Subscription ID
|
|
300
|
+
* @param csrfToken - CSRF token (required)
|
|
301
|
+
* @param resumesAt - Optional ISO date string when subscription should auto-resume
|
|
302
|
+
*/
|
|
303
|
+
async pauseSubscription(
|
|
304
|
+
siteName: string,
|
|
305
|
+
subscriptionId: string,
|
|
306
|
+
csrfToken?: string,
|
|
307
|
+
resumesAt?: string
|
|
308
|
+
): Promise<ApiResponse<{ success: boolean }>> {
|
|
309
|
+
const body: Record<string, string> = {};
|
|
310
|
+
if (resumesAt) {
|
|
311
|
+
body.resumes_at = resumesAt;
|
|
312
|
+
}
|
|
313
|
+
return this.create<Record<string, string>, { success: boolean }>(
|
|
314
|
+
this.siteUserEndpoint(siteName, `/users/me/subscriptions/${encodeURIComponent(subscriptionId)}/pause`),
|
|
315
|
+
body,
|
|
316
|
+
csrfToken
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Resume a paused subscription
|
|
322
|
+
* @param siteName - The site name
|
|
323
|
+
* @param subscriptionId - Subscription ID
|
|
324
|
+
* @param csrfToken - CSRF token (required)
|
|
325
|
+
*/
|
|
326
|
+
async resumeSubscription(
|
|
327
|
+
siteName: string,
|
|
328
|
+
subscriptionId: string,
|
|
329
|
+
csrfToken?: string
|
|
330
|
+
): Promise<ApiResponse<{ success: boolean }>> {
|
|
331
|
+
return this.create<Record<string, never>, { success: boolean }>(
|
|
332
|
+
this.siteUserEndpoint(siteName, `/users/me/subscriptions/${encodeURIComponent(subscriptionId)}/resume`),
|
|
333
|
+
{},
|
|
334
|
+
csrfToken
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Change subscription plan tier
|
|
340
|
+
* @param siteName - The site name
|
|
341
|
+
* @param subscriptionId - Subscription ID
|
|
342
|
+
* @param productId - New product ID to switch to
|
|
343
|
+
* @param csrfToken - CSRF token (required)
|
|
344
|
+
*/
|
|
345
|
+
async changeSubscriptionPlan(
|
|
346
|
+
siteName: string,
|
|
347
|
+
subscriptionId: string,
|
|
348
|
+
productId: number,
|
|
349
|
+
csrfToken?: string
|
|
350
|
+
): Promise<ApiResponse<{ success: boolean }>> {
|
|
351
|
+
return this.create<{ product_id: number }, { success: boolean }>(
|
|
352
|
+
this.siteUserEndpoint(siteName, `/users/me/subscriptions/${encodeURIComponent(subscriptionId)}/change-plan`),
|
|
353
|
+
{ product_id: productId },
|
|
354
|
+
csrfToken
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
293
358
|
/**
|
|
294
359
|
* Get linked newsletter subscriptions
|
|
295
360
|
* @param siteName - The site name
|
|
@@ -300,6 +365,35 @@ export class SiteUsersClient extends BaseClient {
|
|
|
300
365
|
);
|
|
301
366
|
}
|
|
302
367
|
|
|
368
|
+
// ============================================================================
|
|
369
|
+
// CREDIT ENDPOINTS (site user JWT required)
|
|
370
|
+
// ============================================================================
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Get current credit balance
|
|
374
|
+
* @param siteName - The site name
|
|
375
|
+
*/
|
|
376
|
+
async getCreditBalance(siteName: string): Promise<ApiResponse<CreditBalance>> {
|
|
377
|
+
return this.getSingle<CreditBalance>(
|
|
378
|
+
this.siteUserEndpoint(siteName, '/users/me/credits/balance')
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Get credit balance and paginated transactions
|
|
384
|
+
* @param siteName - The site name
|
|
385
|
+
* @param params - Pagination params
|
|
386
|
+
*/
|
|
387
|
+
async getCreditTransactions(
|
|
388
|
+
siteName: string,
|
|
389
|
+
params?: { limit?: number; offset?: number }
|
|
390
|
+
): Promise<ApiResponse<CreditBalanceWithTransactions>> {
|
|
391
|
+
return this.http.get<CreditBalanceWithTransactions>(
|
|
392
|
+
this.buildPath(this.siteUserEndpoint(siteName, '/users/me/credits')),
|
|
393
|
+
params
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
303
397
|
// ============================================================================
|
|
304
398
|
// ADMIN ENDPOINTS (API key auth required)
|
|
305
399
|
// ============================================================================
|
|
@@ -349,4 +443,25 @@ export class SiteUsersClient extends BaseClient {
|
|
|
349
443
|
csrfToken
|
|
350
444
|
);
|
|
351
445
|
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Grant credit to a user (admin only)
|
|
449
|
+
* Adds credit to the user's ledger and Stripe Customer Balance.
|
|
450
|
+
* @param siteName - The site name
|
|
451
|
+
* @param userId - User ID
|
|
452
|
+
* @param data - Amount in cents and description
|
|
453
|
+
* @param csrfToken - CSRF token (required)
|
|
454
|
+
*/
|
|
455
|
+
async grantCredit(
|
|
456
|
+
siteName: string,
|
|
457
|
+
userId: string,
|
|
458
|
+
data: GrantCreditRequest,
|
|
459
|
+
csrfToken?: string
|
|
460
|
+
): Promise<ApiResponse<{ success: boolean; new_balance_cents: number }>> {
|
|
461
|
+
return this.create<GrantCreditRequest, { success: boolean; new_balance_cents: number }>(
|
|
462
|
+
this.siteUserEndpoint(siteName, `/users/${encodeURIComponent(userId)}/credits/grant`),
|
|
463
|
+
data,
|
|
464
|
+
csrfToken
|
|
465
|
+
);
|
|
466
|
+
}
|
|
352
467
|
}
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export { CheckoutClient } from './client/checkout-client';
|
|
|
20
20
|
export { ContactClient } from './client/contact-client';
|
|
21
21
|
export { NewsletterClient } from './client/newsletter-client';
|
|
22
22
|
export { SiteUsersClient } from './client/site-users-client';
|
|
23
|
+
export { BundlesClient } from './client/bundles-client';
|
|
23
24
|
|
|
24
25
|
// Base classes
|
|
25
26
|
export { BaseClient } from './client/base-client';
|
|
@@ -116,4 +117,11 @@ export type {
|
|
|
116
117
|
VerifyOtpResponse,
|
|
117
118
|
UpdateSiteUserRequest,
|
|
118
119
|
SetProfileValueRequest,
|
|
120
|
+
ProductBundleGroup,
|
|
121
|
+
CreateBundleGroupRequest,
|
|
122
|
+
BundleCollection,
|
|
123
|
+
CreateBundleCollectionRequest,
|
|
124
|
+
BundleCollectionItem,
|
|
125
|
+
BundleCollectionItemWithProduct,
|
|
126
|
+
AddCollectionItemRequest,
|
|
119
127
|
} from './types';
|
|
@@ -17,6 +17,7 @@ import { CheckoutClient } from './client/checkout-client';
|
|
|
17
17
|
import { ContactClient } from './client/contact-client';
|
|
18
18
|
import { NewsletterClient } from './client/newsletter-client';
|
|
19
19
|
import { SiteUsersClient } from './client/site-users-client';
|
|
20
|
+
import { BundlesClient } from './client/bundles-client';
|
|
20
21
|
|
|
21
22
|
import type { PerspectApiConfig, ApiResponse } from './types';
|
|
22
23
|
|
|
@@ -37,6 +38,7 @@ export class PerspectApiClient {
|
|
|
37
38
|
public readonly contact: ContactClient;
|
|
38
39
|
public readonly newsletter: NewsletterClient;
|
|
39
40
|
public readonly siteUsers: SiteUsersClient;
|
|
41
|
+
public readonly bundles: BundlesClient;
|
|
40
42
|
|
|
41
43
|
constructor(config: PerspectApiConfig) {
|
|
42
44
|
// Validate required configuration
|
|
@@ -61,6 +63,7 @@ export class PerspectApiClient {
|
|
|
61
63
|
this.contact = new ContactClient(this.http, this.cache);
|
|
62
64
|
this.newsletter = new NewsletterClient(this.http, this.cache);
|
|
63
65
|
this.siteUsers = new SiteUsersClient(this.http, this.cache);
|
|
66
|
+
this.bundles = new BundlesClient(this.http, this.cache);
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
/**
|
package/src/types/index.ts
CHANGED
|
@@ -464,6 +464,8 @@ export interface CreateCheckoutSessionRequest {
|
|
|
464
464
|
quantity: number;
|
|
465
465
|
// SKU-based checkout (variant products)
|
|
466
466
|
sku_id?: number;
|
|
467
|
+
// Product ID-based checkout (server resolves to Stripe price)
|
|
468
|
+
product_id?: number;
|
|
467
469
|
// Or define price data inline
|
|
468
470
|
price_data?: {
|
|
469
471
|
currency: string;
|
|
@@ -484,6 +486,8 @@ export interface CreateCheckoutSessionRequest {
|
|
|
484
486
|
customer_email?: string;
|
|
485
487
|
customerEmail?: string; // Alternative naming
|
|
486
488
|
site_user_id?: string; // Authenticated site user — enables checkout prefill
|
|
489
|
+
referral_code?: string; // Referral code for first-checkout discount
|
|
490
|
+
referrer_site_user_id?: string; // Referrer's site_user_id for credit
|
|
487
491
|
currency?: string;
|
|
488
492
|
metadata?: CheckoutMetadata;
|
|
489
493
|
mode?: 'payment' | 'subscription' | 'setup';
|
|
@@ -620,6 +624,29 @@ export interface SiteUserOrder {
|
|
|
620
624
|
completed_at?: string;
|
|
621
625
|
}
|
|
622
626
|
|
|
627
|
+
// Credits
|
|
628
|
+
export interface CreditTransaction {
|
|
629
|
+
id: number;
|
|
630
|
+
amount_cents: number;
|
|
631
|
+
balance_after_cents: number;
|
|
632
|
+
type: string;
|
|
633
|
+
description: string | null;
|
|
634
|
+
created_at: string;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export interface CreditBalance {
|
|
638
|
+
balance_cents: number;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export interface CreditBalanceWithTransactions extends CreditBalance {
|
|
642
|
+
transactions: CreditTransaction[];
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
export interface GrantCreditRequest {
|
|
646
|
+
amount_cents: number;
|
|
647
|
+
description: string;
|
|
648
|
+
}
|
|
649
|
+
|
|
623
650
|
export interface RequestOtpRequest {
|
|
624
651
|
email: string;
|
|
625
652
|
waitlist?: boolean; // Mark user as waitlist signup
|
|
@@ -654,6 +681,71 @@ export interface SetProfileValueRequest {
|
|
|
654
681
|
value: string;
|
|
655
682
|
}
|
|
656
683
|
|
|
684
|
+
// Bundle Groups (structural "pick N items" metadata on a product)
|
|
685
|
+
export interface ProductBundleGroup {
|
|
686
|
+
bundle_group_id: number;
|
|
687
|
+
product_id: number;
|
|
688
|
+
name: string;
|
|
689
|
+
description?: string;
|
|
690
|
+
quantity: number;
|
|
691
|
+
position: number;
|
|
692
|
+
created_at: string;
|
|
693
|
+
updated_at: string;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export interface CreateBundleGroupRequest {
|
|
697
|
+
name: string;
|
|
698
|
+
description?: string;
|
|
699
|
+
quantity: number;
|
|
700
|
+
position?: number;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// Bundle Collections (time-bounded, site-scoped sets of products)
|
|
704
|
+
export interface BundleCollection {
|
|
705
|
+
collection_id: number;
|
|
706
|
+
site_id: string;
|
|
707
|
+
site_name: string;
|
|
708
|
+
name: string;
|
|
709
|
+
description?: string;
|
|
710
|
+
available_from?: string;
|
|
711
|
+
available_until?: string;
|
|
712
|
+
published: number;
|
|
713
|
+
created_at: string;
|
|
714
|
+
updated_at: string;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
export interface CreateBundleCollectionRequest {
|
|
718
|
+
name: string;
|
|
719
|
+
description?: string;
|
|
720
|
+
available_from?: string;
|
|
721
|
+
available_until?: string;
|
|
722
|
+
published?: number;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
export interface BundleCollectionItem {
|
|
726
|
+
id: number;
|
|
727
|
+
collection_id: number;
|
|
728
|
+
product_id: number;
|
|
729
|
+
max_quantity?: number;
|
|
730
|
+
position: number;
|
|
731
|
+
created_at: string;
|
|
732
|
+
updated_at: string;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
export interface BundleCollectionItemWithProduct extends BundleCollectionItem {
|
|
736
|
+
product_name: string;
|
|
737
|
+
slug: string;
|
|
738
|
+
unit_amount: number;
|
|
739
|
+
currency: string;
|
|
740
|
+
image_url?: string;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
export interface AddCollectionItemRequest {
|
|
744
|
+
product_id: number;
|
|
745
|
+
max_quantity?: number;
|
|
746
|
+
position?: number;
|
|
747
|
+
}
|
|
748
|
+
|
|
657
749
|
// Error Types
|
|
658
750
|
export interface ApiError {
|
|
659
751
|
message: string;
|