@stackbe/sdk 0.6.5 → 0.7.1

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
@@ -549,9 +549,22 @@ stackbe.auth.invalidateSession(token);
549
549
  stackbe.auth.clearCache(); // Clear all
550
550
  ```
551
551
 
552
- ### Environment-Aware Redirects
552
+ ### Magic Link Callback URLs
553
553
 
554
- Auto-detect development environment for magic link redirects:
554
+ **Recommended approach**: Pass the callback URL explicitly for maximum reliability:
555
+
556
+ ```typescript
557
+ // Determine callback URL based on your environment
558
+ const callbackUrl = process.env.NODE_ENV === 'production'
559
+ ? 'https://myapp.com/auth/callback'
560
+ : 'http://localhost:3000/auth/callback';
561
+
562
+ await stackbe.auth.sendMagicLink('user@example.com', {
563
+ redirectUrl: callbackUrl,
564
+ });
565
+ ```
566
+
567
+ **Alternative**: Use `devCallbackUrl` for automatic detection (uses `devCallbackUrl` when `NODE_ENV !== 'production'`):
555
568
 
556
569
  ```typescript
557
570
  const stackbe = new StackBE({
@@ -560,17 +573,18 @@ const stackbe = new StackBE({
560
573
  devCallbackUrl: 'http://localhost:3000/auth/callback',
561
574
  });
562
575
 
563
- // In development (NODE_ENV !== 'production'), uses devCallbackUrl automatically
576
+ // In development, uses devCallbackUrl automatically
564
577
  await stackbe.auth.sendMagicLink('user@example.com');
565
- // Redirects to: http://localhost:3000/auth/callback
566
578
 
567
- // In production, uses your configured auth callback URL
568
- // Or pass explicit redirectUrl to override
569
- await stackbe.auth.sendMagicLink('user@example.com', {
570
- redirectUrl: 'https://myapp.com/custom-callback',
571
- });
579
+ // In production, falls back to app settings callback URL
580
+ // Explicit redirectUrl always takes priority if provided
572
581
  ```
573
582
 
583
+ **Notes:**
584
+ - `devCallbackUrl` only activates when `NODE_ENV !== 'production'`
585
+ - Explicit `redirectUrl` parameter always takes priority
586
+ - For predictable behavior, use the explicit approach above
587
+
574
588
  ## Webhooks
575
589
 
576
590
  Typed webhook payloads for handling StackBE events:
package/dist/index.d.mts CHANGED
@@ -340,7 +340,7 @@ interface ListProductsOptions {
340
340
  appId?: string;
341
341
  }
342
342
  interface CreateCheckoutOptions {
343
- /** Customer ID or email */
343
+ /** Customer ID or object with email. Use string for existing customer ID, object for email-based lookup/creation */
344
344
  customer: string | {
345
345
  email: string;
346
346
  name?: string;
@@ -351,6 +351,8 @@ interface CreateCheckoutOptions {
351
351
  successUrl: string;
352
352
  /** URL to redirect if checkout is canceled */
353
353
  cancelUrl?: string;
354
+ /** Organization ID for org-level subscriptions. Customer must be owner/admin of the org. */
355
+ organizationId?: string;
354
356
  /** Allow promotion codes */
355
357
  allowPromotionCodes?: boolean;
356
358
  /** Trial period in days */
@@ -825,7 +827,7 @@ declare class CheckoutClient {
825
827
  *
826
828
  * @example
827
829
  * ```typescript
828
- * // With new customer (will be created)
830
+ * // With customer email (looks up or creates customer)
829
831
  * const { url } = await stackbe.checkout.createSession({
830
832
  * customer: { email: 'user@example.com', name: 'John' },
831
833
  * planId: 'plan_pro_monthly',
@@ -833,6 +835,18 @@ declare class CheckoutClient {
833
835
  * trialDays: 14,
834
836
  * });
835
837
  * ```
838
+ *
839
+ * @example
840
+ * ```typescript
841
+ * // Organization-level subscription (B2B)
842
+ * const { url } = await stackbe.checkout.createSession({
843
+ * customer: 'cust_123',
844
+ * organizationId: 'org_456', // Customer must be owner/admin
845
+ * planId: 'plan_team',
846
+ * successUrl: 'https://myapp.com/success',
847
+ * cancelUrl: 'https://myapp.com/pricing',
848
+ * });
849
+ * ```
836
850
  */
837
851
  createSession(options: CreateCheckoutOptions): Promise<CheckoutSessionResponse>;
838
852
  /**
@@ -1375,6 +1389,232 @@ declare class ProductsClient {
1375
1389
  get(productId: string): Promise<Product>;
1376
1390
  }
1377
1391
 
1392
+ interface FeatureRequest {
1393
+ id: string;
1394
+ title: string;
1395
+ description?: string;
1396
+ status: 'new' | 'under_review' | 'planned' | 'in_progress' | 'completed' | 'declined';
1397
+ category?: string;
1398
+ authorId: string;
1399
+ authorEmail: string;
1400
+ voteCount: number;
1401
+ hasVoted?: boolean;
1402
+ createdAt: string;
1403
+ updatedAt: string;
1404
+ }
1405
+ interface FeatureRequestComment {
1406
+ id: string;
1407
+ customerEmail: string;
1408
+ content: string;
1409
+ isAdminReply: boolean;
1410
+ createdAt: string;
1411
+ }
1412
+ interface CreateFeatureRequestOptions {
1413
+ title: string;
1414
+ description?: string;
1415
+ category?: string;
1416
+ }
1417
+ interface ListFeatureRequestsOptions {
1418
+ status?: 'new' | 'under_review' | 'planned' | 'in_progress' | 'completed' | 'declined';
1419
+ category?: string;
1420
+ sortBy?: 'newest' | 'votes' | 'recent_activity';
1421
+ limit?: number;
1422
+ offset?: number;
1423
+ }
1424
+ interface FeatureRequestListResponse {
1425
+ data: FeatureRequest[];
1426
+ total: number;
1427
+ limit: number;
1428
+ offset: number;
1429
+ }
1430
+ interface InterestedCustomer {
1431
+ customerId: string;
1432
+ email: string;
1433
+ votedAt?: string;
1434
+ submittedAt?: string;
1435
+ }
1436
+ interface InterestedCustomersResponse {
1437
+ featureRequestId: string;
1438
+ title: string;
1439
+ status: string;
1440
+ author: {
1441
+ customerId: string;
1442
+ email: string;
1443
+ submittedAt: string;
1444
+ };
1445
+ voters: InterestedCustomer[];
1446
+ totalInterested: number;
1447
+ }
1448
+ interface CustomerFeatureActivity {
1449
+ customerId: string;
1450
+ submitted: Array<{
1451
+ id: string;
1452
+ title: string;
1453
+ status: string;
1454
+ voteCount: number;
1455
+ submittedAt: string;
1456
+ }>;
1457
+ votedOn: Array<{
1458
+ id: string;
1459
+ title: string;
1460
+ status: string;
1461
+ voteCount: number;
1462
+ votedAt: string;
1463
+ }>;
1464
+ totalSubmitted: number;
1465
+ totalVotes: number;
1466
+ }
1467
+ declare class FeatureRequestsClient {
1468
+ private http;
1469
+ private appId;
1470
+ constructor(http: HttpClient, appId: string);
1471
+ /**
1472
+ * List feature requests for the app.
1473
+ *
1474
+ * @example
1475
+ * ```typescript
1476
+ * // Get all feature requests
1477
+ * const { data, total } = await stackbe.featureRequests.list();
1478
+ *
1479
+ * // Filter by status
1480
+ * const planned = await stackbe.featureRequests.list({ status: 'planned' });
1481
+ *
1482
+ * // Sort by votes
1483
+ * const popular = await stackbe.featureRequests.list({ sortBy: 'votes' });
1484
+ * ```
1485
+ */
1486
+ list(options?: ListFeatureRequestsOptions): Promise<FeatureRequestListResponse>;
1487
+ /**
1488
+ * Submit a new feature request.
1489
+ * Requires customer session token.
1490
+ *
1491
+ * @example
1492
+ * ```typescript
1493
+ * const request = await stackbe.featureRequests.create({
1494
+ * title: 'Dark mode support',
1495
+ * description: 'Would love to have a dark theme option',
1496
+ * category: 'UI',
1497
+ * });
1498
+ * ```
1499
+ */
1500
+ create(options: CreateFeatureRequestOptions): Promise<FeatureRequest>;
1501
+ /**
1502
+ * Get a specific feature request by ID.
1503
+ *
1504
+ * @example
1505
+ * ```typescript
1506
+ * const request = await stackbe.featureRequests.get('req_123');
1507
+ * console.log(`${request.title} has ${request.voteCount} votes`);
1508
+ * ```
1509
+ */
1510
+ get(requestId: string): Promise<FeatureRequest & {
1511
+ comments: FeatureRequestComment[];
1512
+ }>;
1513
+ /**
1514
+ * Upvote a feature request.
1515
+ * Requires customer session token. Idempotent.
1516
+ *
1517
+ * @example
1518
+ * ```typescript
1519
+ * await stackbe.featureRequests.vote('req_123');
1520
+ * ```
1521
+ */
1522
+ vote(requestId: string): Promise<{
1523
+ success?: boolean;
1524
+ alreadyVoted?: boolean;
1525
+ voteCount: number;
1526
+ }>;
1527
+ /**
1528
+ * Remove your vote from a feature request.
1529
+ * Requires customer session token.
1530
+ *
1531
+ * @example
1532
+ * ```typescript
1533
+ * await stackbe.featureRequests.removeVote('req_123');
1534
+ * ```
1535
+ */
1536
+ removeVote(requestId: string): Promise<{
1537
+ success: boolean;
1538
+ voteCount: number;
1539
+ }>;
1540
+ /**
1541
+ * Add a comment to a feature request.
1542
+ * Requires customer session token.
1543
+ *
1544
+ * @example
1545
+ * ```typescript
1546
+ * await stackbe.featureRequests.addComment('req_123', {
1547
+ * content: 'This would be really helpful for my workflow!',
1548
+ * });
1549
+ * ```
1550
+ */
1551
+ addComment(requestId: string, options: {
1552
+ content: string;
1553
+ }): Promise<FeatureRequestComment>;
1554
+ /**
1555
+ * Update a feature request status or category.
1556
+ * Requires API key (admin).
1557
+ *
1558
+ * @example
1559
+ * ```typescript
1560
+ * await stackbe.featureRequests.update('req_123', {
1561
+ * status: 'planned',
1562
+ * category: 'Core Features',
1563
+ * });
1564
+ * ```
1565
+ */
1566
+ update(requestId: string, options: {
1567
+ status?: string;
1568
+ category?: string;
1569
+ }): Promise<FeatureRequest>;
1570
+ /**
1571
+ * Delete a feature request.
1572
+ * Requires API key (admin).
1573
+ *
1574
+ * @example
1575
+ * ```typescript
1576
+ * await stackbe.featureRequests.delete('req_123');
1577
+ * ```
1578
+ */
1579
+ delete(requestId: string): Promise<{
1580
+ success: boolean;
1581
+ }>;
1582
+ /**
1583
+ * Get all customers interested in a feature request (author + voters).
1584
+ * Useful for user research or notifying users when the feature ships.
1585
+ * Requires API key (admin).
1586
+ *
1587
+ * @example
1588
+ * ```typescript
1589
+ * const { author, voters, totalInterested } = await stackbe.featureRequests.getInterestedCustomers('req_123');
1590
+ *
1591
+ * // Notify all interested users
1592
+ * const emails = [author.email, ...voters.map(v => v.email)];
1593
+ * await sendNotification(emails, 'Your requested feature is now live!');
1594
+ * ```
1595
+ */
1596
+ getInterestedCustomers(requestId: string): Promise<InterestedCustomersResponse>;
1597
+ /**
1598
+ * Get a customer's feature request activity (requests submitted + votes).
1599
+ * Useful for displaying on customer profile.
1600
+ * Requires API key (admin).
1601
+ *
1602
+ * @example
1603
+ * ```typescript
1604
+ * const activity = await stackbe.featureRequests.getCustomerActivity('cust_123');
1605
+ *
1606
+ * console.log(`Submitted ${activity.totalSubmitted} requests`);
1607
+ * console.log(`Voted on ${activity.totalVotes} requests`);
1608
+ *
1609
+ * // Show their most wanted features
1610
+ * activity.votedOn.forEach(r => {
1611
+ * console.log(`- ${r.title} (${r.status})`);
1612
+ * });
1613
+ * ```
1614
+ */
1615
+ getCustomerActivity(customerId: string): Promise<CustomerFeatureActivity>;
1616
+ }
1617
+
1378
1618
  declare class StackBE {
1379
1619
  private http;
1380
1620
  private appId;
@@ -1396,6 +1636,8 @@ declare class StackBE {
1396
1636
  readonly plans: PlansClient;
1397
1637
  /** Products */
1398
1638
  readonly products: ProductsClient;
1639
+ /** Feature requests and voting */
1640
+ readonly featureRequests: FeatureRequestsClient;
1399
1641
  /**
1400
1642
  * Create a new StackBE client.
1401
1643
  *
@@ -1496,4 +1738,4 @@ declare class StackBE {
1496
1738
  }): (req: any, res: any, next: any) => Promise<any>;
1497
1739
  }
1498
1740
 
1499
- export { type AddMemberOptions, type AnyWebhookEvent, AuthClient, type CancelSubscriptionOptions, type CancelSubscriptionResponse, type CheckEntitlementResponse, type CheckUsageResponse, CheckoutClient, type CheckoutSessionResponse, type CreateCheckoutOptions, type CreateCustomerOptions, type CreateOrganizationOptions, type Customer, type CustomerCreatedEvent, type CustomerUpdatedEvent, type CustomerUsageResponse, type CustomerWebhookPayload, type CustomerWithSubscription, CustomersClient, EntitlementsClient, type EntitlementsResponse, type InviteMemberOptions, type ListPlansOptions, type ListProductsOptions, type MagicLinkOptions, type MagicLinkResponse, type Organization, type OrganizationInvite, type OrganizationMember, OrganizationsClient, type PaymentFailedEvent, type PaymentSucceededEvent, type PaymentWebhookPayload, type Plan, PlansClient, type Product, ProductsClient, type SessionResponse, StackBE, type StackBEConfig, StackBEError, type StackBEErrorCode, type StackBEErrorResponse, type Subscription, type SubscriptionCancelledEvent, type SubscriptionCreatedEvent, type SubscriptionRenewedEvent, type SubscriptionUpdatedEvent, type SubscriptionWebhookPayload, type SubscriptionWithPlan, SubscriptionsClient, type TrackUsageOptions, type TrackUsageResponse, type TrialEndedEvent, type TrialStartedEvent, type UpdateCustomerOptions, type UpdateOrganizationOptions, type UpdateSubscriptionOptions, UsageClient, type UsageMetric, type VerifyTokenResponse, type WebhookEvent, type WebhookEventType };
1741
+ export { type AddMemberOptions, type AnyWebhookEvent, AuthClient, type CancelSubscriptionOptions, type CancelSubscriptionResponse, type CheckEntitlementResponse, type CheckUsageResponse, CheckoutClient, type CheckoutSessionResponse, type CreateCheckoutOptions, type CreateCustomerOptions, type CreateFeatureRequestOptions, type CreateOrganizationOptions, type Customer, type CustomerCreatedEvent, type CustomerFeatureActivity, type CustomerUpdatedEvent, type CustomerUsageResponse, type CustomerWebhookPayload, type CustomerWithSubscription, CustomersClient, EntitlementsClient, type EntitlementsResponse, type FeatureRequest, type FeatureRequestComment, type FeatureRequestListResponse, FeatureRequestsClient, type InterestedCustomer, type InterestedCustomersResponse, type InviteMemberOptions, type ListFeatureRequestsOptions, type ListPlansOptions, type ListProductsOptions, type MagicLinkOptions, type MagicLinkResponse, type Organization, type OrganizationInvite, type OrganizationMember, OrganizationsClient, type PaymentFailedEvent, type PaymentSucceededEvent, type PaymentWebhookPayload, type Plan, PlansClient, type Product, ProductsClient, type SessionResponse, StackBE, type StackBEConfig, StackBEError, type StackBEErrorCode, type StackBEErrorResponse, type Subscription, type SubscriptionCancelledEvent, type SubscriptionCreatedEvent, type SubscriptionRenewedEvent, type SubscriptionUpdatedEvent, type SubscriptionWebhookPayload, type SubscriptionWithPlan, SubscriptionsClient, type TrackUsageOptions, type TrackUsageResponse, type TrialEndedEvent, type TrialStartedEvent, type UpdateCustomerOptions, type UpdateOrganizationOptions, type UpdateSubscriptionOptions, UsageClient, type UsageMetric, type VerifyTokenResponse, type WebhookEvent, type WebhookEventType };
package/dist/index.d.ts CHANGED
@@ -340,7 +340,7 @@ interface ListProductsOptions {
340
340
  appId?: string;
341
341
  }
342
342
  interface CreateCheckoutOptions {
343
- /** Customer ID or email */
343
+ /** Customer ID or object with email. Use string for existing customer ID, object for email-based lookup/creation */
344
344
  customer: string | {
345
345
  email: string;
346
346
  name?: string;
@@ -351,6 +351,8 @@ interface CreateCheckoutOptions {
351
351
  successUrl: string;
352
352
  /** URL to redirect if checkout is canceled */
353
353
  cancelUrl?: string;
354
+ /** Organization ID for org-level subscriptions. Customer must be owner/admin of the org. */
355
+ organizationId?: string;
354
356
  /** Allow promotion codes */
355
357
  allowPromotionCodes?: boolean;
356
358
  /** Trial period in days */
@@ -825,7 +827,7 @@ declare class CheckoutClient {
825
827
  *
826
828
  * @example
827
829
  * ```typescript
828
- * // With new customer (will be created)
830
+ * // With customer email (looks up or creates customer)
829
831
  * const { url } = await stackbe.checkout.createSession({
830
832
  * customer: { email: 'user@example.com', name: 'John' },
831
833
  * planId: 'plan_pro_monthly',
@@ -833,6 +835,18 @@ declare class CheckoutClient {
833
835
  * trialDays: 14,
834
836
  * });
835
837
  * ```
838
+ *
839
+ * @example
840
+ * ```typescript
841
+ * // Organization-level subscription (B2B)
842
+ * const { url } = await stackbe.checkout.createSession({
843
+ * customer: 'cust_123',
844
+ * organizationId: 'org_456', // Customer must be owner/admin
845
+ * planId: 'plan_team',
846
+ * successUrl: 'https://myapp.com/success',
847
+ * cancelUrl: 'https://myapp.com/pricing',
848
+ * });
849
+ * ```
836
850
  */
837
851
  createSession(options: CreateCheckoutOptions): Promise<CheckoutSessionResponse>;
838
852
  /**
@@ -1375,6 +1389,232 @@ declare class ProductsClient {
1375
1389
  get(productId: string): Promise<Product>;
1376
1390
  }
1377
1391
 
1392
+ interface FeatureRequest {
1393
+ id: string;
1394
+ title: string;
1395
+ description?: string;
1396
+ status: 'new' | 'under_review' | 'planned' | 'in_progress' | 'completed' | 'declined';
1397
+ category?: string;
1398
+ authorId: string;
1399
+ authorEmail: string;
1400
+ voteCount: number;
1401
+ hasVoted?: boolean;
1402
+ createdAt: string;
1403
+ updatedAt: string;
1404
+ }
1405
+ interface FeatureRequestComment {
1406
+ id: string;
1407
+ customerEmail: string;
1408
+ content: string;
1409
+ isAdminReply: boolean;
1410
+ createdAt: string;
1411
+ }
1412
+ interface CreateFeatureRequestOptions {
1413
+ title: string;
1414
+ description?: string;
1415
+ category?: string;
1416
+ }
1417
+ interface ListFeatureRequestsOptions {
1418
+ status?: 'new' | 'under_review' | 'planned' | 'in_progress' | 'completed' | 'declined';
1419
+ category?: string;
1420
+ sortBy?: 'newest' | 'votes' | 'recent_activity';
1421
+ limit?: number;
1422
+ offset?: number;
1423
+ }
1424
+ interface FeatureRequestListResponse {
1425
+ data: FeatureRequest[];
1426
+ total: number;
1427
+ limit: number;
1428
+ offset: number;
1429
+ }
1430
+ interface InterestedCustomer {
1431
+ customerId: string;
1432
+ email: string;
1433
+ votedAt?: string;
1434
+ submittedAt?: string;
1435
+ }
1436
+ interface InterestedCustomersResponse {
1437
+ featureRequestId: string;
1438
+ title: string;
1439
+ status: string;
1440
+ author: {
1441
+ customerId: string;
1442
+ email: string;
1443
+ submittedAt: string;
1444
+ };
1445
+ voters: InterestedCustomer[];
1446
+ totalInterested: number;
1447
+ }
1448
+ interface CustomerFeatureActivity {
1449
+ customerId: string;
1450
+ submitted: Array<{
1451
+ id: string;
1452
+ title: string;
1453
+ status: string;
1454
+ voteCount: number;
1455
+ submittedAt: string;
1456
+ }>;
1457
+ votedOn: Array<{
1458
+ id: string;
1459
+ title: string;
1460
+ status: string;
1461
+ voteCount: number;
1462
+ votedAt: string;
1463
+ }>;
1464
+ totalSubmitted: number;
1465
+ totalVotes: number;
1466
+ }
1467
+ declare class FeatureRequestsClient {
1468
+ private http;
1469
+ private appId;
1470
+ constructor(http: HttpClient, appId: string);
1471
+ /**
1472
+ * List feature requests for the app.
1473
+ *
1474
+ * @example
1475
+ * ```typescript
1476
+ * // Get all feature requests
1477
+ * const { data, total } = await stackbe.featureRequests.list();
1478
+ *
1479
+ * // Filter by status
1480
+ * const planned = await stackbe.featureRequests.list({ status: 'planned' });
1481
+ *
1482
+ * // Sort by votes
1483
+ * const popular = await stackbe.featureRequests.list({ sortBy: 'votes' });
1484
+ * ```
1485
+ */
1486
+ list(options?: ListFeatureRequestsOptions): Promise<FeatureRequestListResponse>;
1487
+ /**
1488
+ * Submit a new feature request.
1489
+ * Requires customer session token.
1490
+ *
1491
+ * @example
1492
+ * ```typescript
1493
+ * const request = await stackbe.featureRequests.create({
1494
+ * title: 'Dark mode support',
1495
+ * description: 'Would love to have a dark theme option',
1496
+ * category: 'UI',
1497
+ * });
1498
+ * ```
1499
+ */
1500
+ create(options: CreateFeatureRequestOptions): Promise<FeatureRequest>;
1501
+ /**
1502
+ * Get a specific feature request by ID.
1503
+ *
1504
+ * @example
1505
+ * ```typescript
1506
+ * const request = await stackbe.featureRequests.get('req_123');
1507
+ * console.log(`${request.title} has ${request.voteCount} votes`);
1508
+ * ```
1509
+ */
1510
+ get(requestId: string): Promise<FeatureRequest & {
1511
+ comments: FeatureRequestComment[];
1512
+ }>;
1513
+ /**
1514
+ * Upvote a feature request.
1515
+ * Requires customer session token. Idempotent.
1516
+ *
1517
+ * @example
1518
+ * ```typescript
1519
+ * await stackbe.featureRequests.vote('req_123');
1520
+ * ```
1521
+ */
1522
+ vote(requestId: string): Promise<{
1523
+ success?: boolean;
1524
+ alreadyVoted?: boolean;
1525
+ voteCount: number;
1526
+ }>;
1527
+ /**
1528
+ * Remove your vote from a feature request.
1529
+ * Requires customer session token.
1530
+ *
1531
+ * @example
1532
+ * ```typescript
1533
+ * await stackbe.featureRequests.removeVote('req_123');
1534
+ * ```
1535
+ */
1536
+ removeVote(requestId: string): Promise<{
1537
+ success: boolean;
1538
+ voteCount: number;
1539
+ }>;
1540
+ /**
1541
+ * Add a comment to a feature request.
1542
+ * Requires customer session token.
1543
+ *
1544
+ * @example
1545
+ * ```typescript
1546
+ * await stackbe.featureRequests.addComment('req_123', {
1547
+ * content: 'This would be really helpful for my workflow!',
1548
+ * });
1549
+ * ```
1550
+ */
1551
+ addComment(requestId: string, options: {
1552
+ content: string;
1553
+ }): Promise<FeatureRequestComment>;
1554
+ /**
1555
+ * Update a feature request status or category.
1556
+ * Requires API key (admin).
1557
+ *
1558
+ * @example
1559
+ * ```typescript
1560
+ * await stackbe.featureRequests.update('req_123', {
1561
+ * status: 'planned',
1562
+ * category: 'Core Features',
1563
+ * });
1564
+ * ```
1565
+ */
1566
+ update(requestId: string, options: {
1567
+ status?: string;
1568
+ category?: string;
1569
+ }): Promise<FeatureRequest>;
1570
+ /**
1571
+ * Delete a feature request.
1572
+ * Requires API key (admin).
1573
+ *
1574
+ * @example
1575
+ * ```typescript
1576
+ * await stackbe.featureRequests.delete('req_123');
1577
+ * ```
1578
+ */
1579
+ delete(requestId: string): Promise<{
1580
+ success: boolean;
1581
+ }>;
1582
+ /**
1583
+ * Get all customers interested in a feature request (author + voters).
1584
+ * Useful for user research or notifying users when the feature ships.
1585
+ * Requires API key (admin).
1586
+ *
1587
+ * @example
1588
+ * ```typescript
1589
+ * const { author, voters, totalInterested } = await stackbe.featureRequests.getInterestedCustomers('req_123');
1590
+ *
1591
+ * // Notify all interested users
1592
+ * const emails = [author.email, ...voters.map(v => v.email)];
1593
+ * await sendNotification(emails, 'Your requested feature is now live!');
1594
+ * ```
1595
+ */
1596
+ getInterestedCustomers(requestId: string): Promise<InterestedCustomersResponse>;
1597
+ /**
1598
+ * Get a customer's feature request activity (requests submitted + votes).
1599
+ * Useful for displaying on customer profile.
1600
+ * Requires API key (admin).
1601
+ *
1602
+ * @example
1603
+ * ```typescript
1604
+ * const activity = await stackbe.featureRequests.getCustomerActivity('cust_123');
1605
+ *
1606
+ * console.log(`Submitted ${activity.totalSubmitted} requests`);
1607
+ * console.log(`Voted on ${activity.totalVotes} requests`);
1608
+ *
1609
+ * // Show their most wanted features
1610
+ * activity.votedOn.forEach(r => {
1611
+ * console.log(`- ${r.title} (${r.status})`);
1612
+ * });
1613
+ * ```
1614
+ */
1615
+ getCustomerActivity(customerId: string): Promise<CustomerFeatureActivity>;
1616
+ }
1617
+
1378
1618
  declare class StackBE {
1379
1619
  private http;
1380
1620
  private appId;
@@ -1396,6 +1636,8 @@ declare class StackBE {
1396
1636
  readonly plans: PlansClient;
1397
1637
  /** Products */
1398
1638
  readonly products: ProductsClient;
1639
+ /** Feature requests and voting */
1640
+ readonly featureRequests: FeatureRequestsClient;
1399
1641
  /**
1400
1642
  * Create a new StackBE client.
1401
1643
  *
@@ -1496,4 +1738,4 @@ declare class StackBE {
1496
1738
  }): (req: any, res: any, next: any) => Promise<any>;
1497
1739
  }
1498
1740
 
1499
- export { type AddMemberOptions, type AnyWebhookEvent, AuthClient, type CancelSubscriptionOptions, type CancelSubscriptionResponse, type CheckEntitlementResponse, type CheckUsageResponse, CheckoutClient, type CheckoutSessionResponse, type CreateCheckoutOptions, type CreateCustomerOptions, type CreateOrganizationOptions, type Customer, type CustomerCreatedEvent, type CustomerUpdatedEvent, type CustomerUsageResponse, type CustomerWebhookPayload, type CustomerWithSubscription, CustomersClient, EntitlementsClient, type EntitlementsResponse, type InviteMemberOptions, type ListPlansOptions, type ListProductsOptions, type MagicLinkOptions, type MagicLinkResponse, type Organization, type OrganizationInvite, type OrganizationMember, OrganizationsClient, type PaymentFailedEvent, type PaymentSucceededEvent, type PaymentWebhookPayload, type Plan, PlansClient, type Product, ProductsClient, type SessionResponse, StackBE, type StackBEConfig, StackBEError, type StackBEErrorCode, type StackBEErrorResponse, type Subscription, type SubscriptionCancelledEvent, type SubscriptionCreatedEvent, type SubscriptionRenewedEvent, type SubscriptionUpdatedEvent, type SubscriptionWebhookPayload, type SubscriptionWithPlan, SubscriptionsClient, type TrackUsageOptions, type TrackUsageResponse, type TrialEndedEvent, type TrialStartedEvent, type UpdateCustomerOptions, type UpdateOrganizationOptions, type UpdateSubscriptionOptions, UsageClient, type UsageMetric, type VerifyTokenResponse, type WebhookEvent, type WebhookEventType };
1741
+ export { type AddMemberOptions, type AnyWebhookEvent, AuthClient, type CancelSubscriptionOptions, type CancelSubscriptionResponse, type CheckEntitlementResponse, type CheckUsageResponse, CheckoutClient, type CheckoutSessionResponse, type CreateCheckoutOptions, type CreateCustomerOptions, type CreateFeatureRequestOptions, type CreateOrganizationOptions, type Customer, type CustomerCreatedEvent, type CustomerFeatureActivity, type CustomerUpdatedEvent, type CustomerUsageResponse, type CustomerWebhookPayload, type CustomerWithSubscription, CustomersClient, EntitlementsClient, type EntitlementsResponse, type FeatureRequest, type FeatureRequestComment, type FeatureRequestListResponse, FeatureRequestsClient, type InterestedCustomer, type InterestedCustomersResponse, type InviteMemberOptions, type ListFeatureRequestsOptions, type ListPlansOptions, type ListProductsOptions, type MagicLinkOptions, type MagicLinkResponse, type Organization, type OrganizationInvite, type OrganizationMember, OrganizationsClient, type PaymentFailedEvent, type PaymentSucceededEvent, type PaymentWebhookPayload, type Plan, PlansClient, type Product, ProductsClient, type SessionResponse, StackBE, type StackBEConfig, StackBEError, type StackBEErrorCode, type StackBEErrorResponse, type Subscription, type SubscriptionCancelledEvent, type SubscriptionCreatedEvent, type SubscriptionRenewedEvent, type SubscriptionUpdatedEvent, type SubscriptionWebhookPayload, type SubscriptionWithPlan, SubscriptionsClient, type TrackUsageOptions, type TrackUsageResponse, type TrialEndedEvent, type TrialStartedEvent, type UpdateCustomerOptions, type UpdateOrganizationOptions, type UpdateSubscriptionOptions, UsageClient, type UsageMetric, type VerifyTokenResponse, type WebhookEvent, type WebhookEventType };
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ __export(index_exports, {
24
24
  CheckoutClient: () => CheckoutClient,
25
25
  CustomersClient: () => CustomersClient,
26
26
  EntitlementsClient: () => EntitlementsClient,
27
+ FeatureRequestsClient: () => FeatureRequestsClient,
27
28
  OrganizationsClient: () => OrganizationsClient,
28
29
  PlansClient: () => PlansClient,
29
30
  ProductsClient: () => ProductsClient,
@@ -620,7 +621,7 @@ var CheckoutClient = class {
620
621
  *
621
622
  * @example
622
623
  * ```typescript
623
- * // With new customer (will be created)
624
+ * // With customer email (looks up or creates customer)
624
625
  * const { url } = await stackbe.checkout.createSession({
625
626
  * customer: { email: 'user@example.com', name: 'John' },
626
627
  * planId: 'plan_pro_monthly',
@@ -628,6 +629,18 @@ var CheckoutClient = class {
628
629
  * trialDays: 14,
629
630
  * });
630
631
  * ```
632
+ *
633
+ * @example
634
+ * ```typescript
635
+ * // Organization-level subscription (B2B)
636
+ * const { url } = await stackbe.checkout.createSession({
637
+ * customer: 'cust_123',
638
+ * organizationId: 'org_456', // Customer must be owner/admin
639
+ * planId: 'plan_team',
640
+ * successUrl: 'https://myapp.com/success',
641
+ * cancelUrl: 'https://myapp.com/pricing',
642
+ * });
643
+ * ```
631
644
  */
632
645
  async createSession(options) {
633
646
  const body = {
@@ -635,15 +648,25 @@ var CheckoutClient = class {
635
648
  planId: options.planId,
636
649
  successUrl: options.successUrl,
637
650
  cancelUrl: options.cancelUrl,
651
+ organizationId: options.organizationId,
638
652
  allowPromotionCodes: options.allowPromotionCodes,
639
653
  trialDays: options.trialDays,
640
654
  metadata: options.metadata
641
655
  };
656
+ if (!options.customer) {
657
+ throw new Error(
658
+ 'customer is required. Use customer: "cust_xxx" for existing customer ID, or customer: { email: "user@example.com" } for email-based lookup.'
659
+ );
660
+ }
642
661
  if (typeof options.customer === "string") {
643
662
  body.customerId = options.customer;
644
- } else {
663
+ } else if (options.customer.email) {
645
664
  body.customerEmail = options.customer.email;
646
665
  body.customerName = options.customer.name;
666
+ } else {
667
+ throw new Error(
668
+ 'customer.email is required when using object form. Use customer: { email: "user@example.com" }'
669
+ );
647
670
  }
648
671
  return this.http.post("/v1/checkout/session", body);
649
672
  }
@@ -1438,6 +1461,194 @@ var ProductsClient = class {
1438
1461
  }
1439
1462
  };
1440
1463
 
1464
+ // src/feature-requests.ts
1465
+ var FeatureRequestsClient = class {
1466
+ constructor(http, appId) {
1467
+ this.http = http;
1468
+ this.appId = appId;
1469
+ }
1470
+ /**
1471
+ * List feature requests for the app.
1472
+ *
1473
+ * @example
1474
+ * ```typescript
1475
+ * // Get all feature requests
1476
+ * const { data, total } = await stackbe.featureRequests.list();
1477
+ *
1478
+ * // Filter by status
1479
+ * const planned = await stackbe.featureRequests.list({ status: 'planned' });
1480
+ *
1481
+ * // Sort by votes
1482
+ * const popular = await stackbe.featureRequests.list({ sortBy: 'votes' });
1483
+ * ```
1484
+ */
1485
+ async list(options = {}) {
1486
+ const params = {};
1487
+ if (options.status) params.status = options.status;
1488
+ if (options.category) params.category = options.category;
1489
+ if (options.sortBy) params.sortBy = options.sortBy;
1490
+ if (options.limit) params.limit = options.limit;
1491
+ if (options.offset) params.offset = options.offset;
1492
+ return this.http.get(
1493
+ `/v1/apps/${this.appId}/feature-requests`,
1494
+ params
1495
+ );
1496
+ }
1497
+ /**
1498
+ * Submit a new feature request.
1499
+ * Requires customer session token.
1500
+ *
1501
+ * @example
1502
+ * ```typescript
1503
+ * const request = await stackbe.featureRequests.create({
1504
+ * title: 'Dark mode support',
1505
+ * description: 'Would love to have a dark theme option',
1506
+ * category: 'UI',
1507
+ * });
1508
+ * ```
1509
+ */
1510
+ async create(options) {
1511
+ return this.http.post(
1512
+ `/v1/apps/${this.appId}/feature-requests`,
1513
+ options
1514
+ );
1515
+ }
1516
+ /**
1517
+ * Get a specific feature request by ID.
1518
+ *
1519
+ * @example
1520
+ * ```typescript
1521
+ * const request = await stackbe.featureRequests.get('req_123');
1522
+ * console.log(`${request.title} has ${request.voteCount} votes`);
1523
+ * ```
1524
+ */
1525
+ async get(requestId) {
1526
+ return this.http.get(
1527
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`
1528
+ );
1529
+ }
1530
+ /**
1531
+ * Upvote a feature request.
1532
+ * Requires customer session token. Idempotent.
1533
+ *
1534
+ * @example
1535
+ * ```typescript
1536
+ * await stackbe.featureRequests.vote('req_123');
1537
+ * ```
1538
+ */
1539
+ async vote(requestId) {
1540
+ return this.http.post(
1541
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/vote`
1542
+ );
1543
+ }
1544
+ /**
1545
+ * Remove your vote from a feature request.
1546
+ * Requires customer session token.
1547
+ *
1548
+ * @example
1549
+ * ```typescript
1550
+ * await stackbe.featureRequests.removeVote('req_123');
1551
+ * ```
1552
+ */
1553
+ async removeVote(requestId) {
1554
+ return this.http.delete(
1555
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/vote`
1556
+ );
1557
+ }
1558
+ /**
1559
+ * Add a comment to a feature request.
1560
+ * Requires customer session token.
1561
+ *
1562
+ * @example
1563
+ * ```typescript
1564
+ * await stackbe.featureRequests.addComment('req_123', {
1565
+ * content: 'This would be really helpful for my workflow!',
1566
+ * });
1567
+ * ```
1568
+ */
1569
+ async addComment(requestId, options) {
1570
+ return this.http.post(
1571
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/comments`,
1572
+ options
1573
+ );
1574
+ }
1575
+ // ==================== Admin Methods ====================
1576
+ /**
1577
+ * Update a feature request status or category.
1578
+ * Requires API key (admin).
1579
+ *
1580
+ * @example
1581
+ * ```typescript
1582
+ * await stackbe.featureRequests.update('req_123', {
1583
+ * status: 'planned',
1584
+ * category: 'Core Features',
1585
+ * });
1586
+ * ```
1587
+ */
1588
+ async update(requestId, options) {
1589
+ return this.http.patch(
1590
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`,
1591
+ options
1592
+ );
1593
+ }
1594
+ /**
1595
+ * Delete a feature request.
1596
+ * Requires API key (admin).
1597
+ *
1598
+ * @example
1599
+ * ```typescript
1600
+ * await stackbe.featureRequests.delete('req_123');
1601
+ * ```
1602
+ */
1603
+ async delete(requestId) {
1604
+ return this.http.delete(
1605
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`
1606
+ );
1607
+ }
1608
+ /**
1609
+ * Get all customers interested in a feature request (author + voters).
1610
+ * Useful for user research or notifying users when the feature ships.
1611
+ * Requires API key (admin).
1612
+ *
1613
+ * @example
1614
+ * ```typescript
1615
+ * const { author, voters, totalInterested } = await stackbe.featureRequests.getInterestedCustomers('req_123');
1616
+ *
1617
+ * // Notify all interested users
1618
+ * const emails = [author.email, ...voters.map(v => v.email)];
1619
+ * await sendNotification(emails, 'Your requested feature is now live!');
1620
+ * ```
1621
+ */
1622
+ async getInterestedCustomers(requestId) {
1623
+ return this.http.get(
1624
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/interested`
1625
+ );
1626
+ }
1627
+ /**
1628
+ * Get a customer's feature request activity (requests submitted + votes).
1629
+ * Useful for displaying on customer profile.
1630
+ * Requires API key (admin).
1631
+ *
1632
+ * @example
1633
+ * ```typescript
1634
+ * const activity = await stackbe.featureRequests.getCustomerActivity('cust_123');
1635
+ *
1636
+ * console.log(`Submitted ${activity.totalSubmitted} requests`);
1637
+ * console.log(`Voted on ${activity.totalVotes} requests`);
1638
+ *
1639
+ * // Show their most wanted features
1640
+ * activity.votedOn.forEach(r => {
1641
+ * console.log(`- ${r.title} (${r.status})`);
1642
+ * });
1643
+ * ```
1644
+ */
1645
+ async getCustomerActivity(customerId) {
1646
+ return this.http.get(
1647
+ `/v1/apps/${this.appId}/feature-requests/customer/${customerId}/activity`
1648
+ );
1649
+ }
1650
+ };
1651
+
1441
1652
  // src/client.ts
1442
1653
  var DEFAULT_BASE_URL = "https://api.stackbe.io";
1443
1654
  var DEFAULT_TIMEOUT = 3e4;
@@ -1500,6 +1711,7 @@ var StackBE = class {
1500
1711
  this.organizations = new OrganizationsClient(this.http, config.appId);
1501
1712
  this.plans = new PlansClient(this.http);
1502
1713
  this.products = new ProductsClient(this.http, config.appId);
1714
+ this.featureRequests = new FeatureRequestsClient(this.http, config.appId);
1503
1715
  }
1504
1716
  /**
1505
1717
  * Create a middleware for Express that tracks usage automatically.
@@ -1637,6 +1849,7 @@ var StackBE = class {
1637
1849
  CheckoutClient,
1638
1850
  CustomersClient,
1639
1851
  EntitlementsClient,
1852
+ FeatureRequestsClient,
1640
1853
  OrganizationsClient,
1641
1854
  PlansClient,
1642
1855
  ProductsClient,
package/dist/index.mjs CHANGED
@@ -584,7 +584,7 @@ var CheckoutClient = class {
584
584
  *
585
585
  * @example
586
586
  * ```typescript
587
- * // With new customer (will be created)
587
+ * // With customer email (looks up or creates customer)
588
588
  * const { url } = await stackbe.checkout.createSession({
589
589
  * customer: { email: 'user@example.com', name: 'John' },
590
590
  * planId: 'plan_pro_monthly',
@@ -592,6 +592,18 @@ var CheckoutClient = class {
592
592
  * trialDays: 14,
593
593
  * });
594
594
  * ```
595
+ *
596
+ * @example
597
+ * ```typescript
598
+ * // Organization-level subscription (B2B)
599
+ * const { url } = await stackbe.checkout.createSession({
600
+ * customer: 'cust_123',
601
+ * organizationId: 'org_456', // Customer must be owner/admin
602
+ * planId: 'plan_team',
603
+ * successUrl: 'https://myapp.com/success',
604
+ * cancelUrl: 'https://myapp.com/pricing',
605
+ * });
606
+ * ```
595
607
  */
596
608
  async createSession(options) {
597
609
  const body = {
@@ -599,15 +611,25 @@ var CheckoutClient = class {
599
611
  planId: options.planId,
600
612
  successUrl: options.successUrl,
601
613
  cancelUrl: options.cancelUrl,
614
+ organizationId: options.organizationId,
602
615
  allowPromotionCodes: options.allowPromotionCodes,
603
616
  trialDays: options.trialDays,
604
617
  metadata: options.metadata
605
618
  };
619
+ if (!options.customer) {
620
+ throw new Error(
621
+ 'customer is required. Use customer: "cust_xxx" for existing customer ID, or customer: { email: "user@example.com" } for email-based lookup.'
622
+ );
623
+ }
606
624
  if (typeof options.customer === "string") {
607
625
  body.customerId = options.customer;
608
- } else {
626
+ } else if (options.customer.email) {
609
627
  body.customerEmail = options.customer.email;
610
628
  body.customerName = options.customer.name;
629
+ } else {
630
+ throw new Error(
631
+ 'customer.email is required when using object form. Use customer: { email: "user@example.com" }'
632
+ );
611
633
  }
612
634
  return this.http.post("/v1/checkout/session", body);
613
635
  }
@@ -1402,6 +1424,194 @@ var ProductsClient = class {
1402
1424
  }
1403
1425
  };
1404
1426
 
1427
+ // src/feature-requests.ts
1428
+ var FeatureRequestsClient = class {
1429
+ constructor(http, appId) {
1430
+ this.http = http;
1431
+ this.appId = appId;
1432
+ }
1433
+ /**
1434
+ * List feature requests for the app.
1435
+ *
1436
+ * @example
1437
+ * ```typescript
1438
+ * // Get all feature requests
1439
+ * const { data, total } = await stackbe.featureRequests.list();
1440
+ *
1441
+ * // Filter by status
1442
+ * const planned = await stackbe.featureRequests.list({ status: 'planned' });
1443
+ *
1444
+ * // Sort by votes
1445
+ * const popular = await stackbe.featureRequests.list({ sortBy: 'votes' });
1446
+ * ```
1447
+ */
1448
+ async list(options = {}) {
1449
+ const params = {};
1450
+ if (options.status) params.status = options.status;
1451
+ if (options.category) params.category = options.category;
1452
+ if (options.sortBy) params.sortBy = options.sortBy;
1453
+ if (options.limit) params.limit = options.limit;
1454
+ if (options.offset) params.offset = options.offset;
1455
+ return this.http.get(
1456
+ `/v1/apps/${this.appId}/feature-requests`,
1457
+ params
1458
+ );
1459
+ }
1460
+ /**
1461
+ * Submit a new feature request.
1462
+ * Requires customer session token.
1463
+ *
1464
+ * @example
1465
+ * ```typescript
1466
+ * const request = await stackbe.featureRequests.create({
1467
+ * title: 'Dark mode support',
1468
+ * description: 'Would love to have a dark theme option',
1469
+ * category: 'UI',
1470
+ * });
1471
+ * ```
1472
+ */
1473
+ async create(options) {
1474
+ return this.http.post(
1475
+ `/v1/apps/${this.appId}/feature-requests`,
1476
+ options
1477
+ );
1478
+ }
1479
+ /**
1480
+ * Get a specific feature request by ID.
1481
+ *
1482
+ * @example
1483
+ * ```typescript
1484
+ * const request = await stackbe.featureRequests.get('req_123');
1485
+ * console.log(`${request.title} has ${request.voteCount} votes`);
1486
+ * ```
1487
+ */
1488
+ async get(requestId) {
1489
+ return this.http.get(
1490
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`
1491
+ );
1492
+ }
1493
+ /**
1494
+ * Upvote a feature request.
1495
+ * Requires customer session token. Idempotent.
1496
+ *
1497
+ * @example
1498
+ * ```typescript
1499
+ * await stackbe.featureRequests.vote('req_123');
1500
+ * ```
1501
+ */
1502
+ async vote(requestId) {
1503
+ return this.http.post(
1504
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/vote`
1505
+ );
1506
+ }
1507
+ /**
1508
+ * Remove your vote from a feature request.
1509
+ * Requires customer session token.
1510
+ *
1511
+ * @example
1512
+ * ```typescript
1513
+ * await stackbe.featureRequests.removeVote('req_123');
1514
+ * ```
1515
+ */
1516
+ async removeVote(requestId) {
1517
+ return this.http.delete(
1518
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/vote`
1519
+ );
1520
+ }
1521
+ /**
1522
+ * Add a comment to a feature request.
1523
+ * Requires customer session token.
1524
+ *
1525
+ * @example
1526
+ * ```typescript
1527
+ * await stackbe.featureRequests.addComment('req_123', {
1528
+ * content: 'This would be really helpful for my workflow!',
1529
+ * });
1530
+ * ```
1531
+ */
1532
+ async addComment(requestId, options) {
1533
+ return this.http.post(
1534
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/comments`,
1535
+ options
1536
+ );
1537
+ }
1538
+ // ==================== Admin Methods ====================
1539
+ /**
1540
+ * Update a feature request status or category.
1541
+ * Requires API key (admin).
1542
+ *
1543
+ * @example
1544
+ * ```typescript
1545
+ * await stackbe.featureRequests.update('req_123', {
1546
+ * status: 'planned',
1547
+ * category: 'Core Features',
1548
+ * });
1549
+ * ```
1550
+ */
1551
+ async update(requestId, options) {
1552
+ return this.http.patch(
1553
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`,
1554
+ options
1555
+ );
1556
+ }
1557
+ /**
1558
+ * Delete a feature request.
1559
+ * Requires API key (admin).
1560
+ *
1561
+ * @example
1562
+ * ```typescript
1563
+ * await stackbe.featureRequests.delete('req_123');
1564
+ * ```
1565
+ */
1566
+ async delete(requestId) {
1567
+ return this.http.delete(
1568
+ `/v1/apps/${this.appId}/feature-requests/${requestId}`
1569
+ );
1570
+ }
1571
+ /**
1572
+ * Get all customers interested in a feature request (author + voters).
1573
+ * Useful for user research or notifying users when the feature ships.
1574
+ * Requires API key (admin).
1575
+ *
1576
+ * @example
1577
+ * ```typescript
1578
+ * const { author, voters, totalInterested } = await stackbe.featureRequests.getInterestedCustomers('req_123');
1579
+ *
1580
+ * // Notify all interested users
1581
+ * const emails = [author.email, ...voters.map(v => v.email)];
1582
+ * await sendNotification(emails, 'Your requested feature is now live!');
1583
+ * ```
1584
+ */
1585
+ async getInterestedCustomers(requestId) {
1586
+ return this.http.get(
1587
+ `/v1/apps/${this.appId}/feature-requests/${requestId}/interested`
1588
+ );
1589
+ }
1590
+ /**
1591
+ * Get a customer's feature request activity (requests submitted + votes).
1592
+ * Useful for displaying on customer profile.
1593
+ * Requires API key (admin).
1594
+ *
1595
+ * @example
1596
+ * ```typescript
1597
+ * const activity = await stackbe.featureRequests.getCustomerActivity('cust_123');
1598
+ *
1599
+ * console.log(`Submitted ${activity.totalSubmitted} requests`);
1600
+ * console.log(`Voted on ${activity.totalVotes} requests`);
1601
+ *
1602
+ * // Show their most wanted features
1603
+ * activity.votedOn.forEach(r => {
1604
+ * console.log(`- ${r.title} (${r.status})`);
1605
+ * });
1606
+ * ```
1607
+ */
1608
+ async getCustomerActivity(customerId) {
1609
+ return this.http.get(
1610
+ `/v1/apps/${this.appId}/feature-requests/customer/${customerId}/activity`
1611
+ );
1612
+ }
1613
+ };
1614
+
1405
1615
  // src/client.ts
1406
1616
  var DEFAULT_BASE_URL = "https://api.stackbe.io";
1407
1617
  var DEFAULT_TIMEOUT = 3e4;
@@ -1464,6 +1674,7 @@ var StackBE = class {
1464
1674
  this.organizations = new OrganizationsClient(this.http, config.appId);
1465
1675
  this.plans = new PlansClient(this.http);
1466
1676
  this.products = new ProductsClient(this.http, config.appId);
1677
+ this.featureRequests = new FeatureRequestsClient(this.http, config.appId);
1467
1678
  }
1468
1679
  /**
1469
1680
  * Create a middleware for Express that tracks usage automatically.
@@ -1600,6 +1811,7 @@ export {
1600
1811
  CheckoutClient,
1601
1812
  CustomersClient,
1602
1813
  EntitlementsClient,
1814
+ FeatureRequestsClient,
1603
1815
  OrganizationsClient,
1604
1816
  PlansClient,
1605
1817
  ProductsClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackbe/sdk",
3
- "version": "0.6.5",
3
+ "version": "0.7.1",
4
4
  "description": "Official JavaScript/TypeScript SDK for StackBE - the billing backend for your side project",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",