@stackbe/sdk 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -77
- package/dist/index.d.mts +479 -10
- package/dist/index.d.ts +479 -10
- package/dist/index.js +538 -7
- package/dist/index.mjs +535 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,10 +6,6 @@ Official JavaScript/TypeScript SDK for [StackBE](https://stackbe.io) - the billi
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @stackbe/sdk
|
|
9
|
-
# or
|
|
10
|
-
yarn add @stackbe/sdk
|
|
11
|
-
# or
|
|
12
|
-
pnpm add @stackbe/sdk
|
|
13
9
|
```
|
|
14
10
|
|
|
15
11
|
## Quick Start
|
|
@@ -25,14 +21,26 @@ const stackbe = new StackBE({
|
|
|
25
21
|
// Track usage
|
|
26
22
|
await stackbe.usage.track('customer_123', 'api_calls');
|
|
27
23
|
|
|
28
|
-
// Check
|
|
29
|
-
const { allowed, remaining } = await stackbe.usage.check('customer_123', 'api_calls');
|
|
30
|
-
|
|
31
|
-
// Check feature access
|
|
24
|
+
// Check entitlements
|
|
32
25
|
const { hasAccess } = await stackbe.entitlements.check('customer_123', 'premium_export');
|
|
26
|
+
|
|
27
|
+
// Create checkout session
|
|
28
|
+
const { url } = await stackbe.checkout.createSession({
|
|
29
|
+
customer: 'cust_123',
|
|
30
|
+
planId: 'plan_pro',
|
|
31
|
+
successUrl: 'https://myapp.com/success',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Get subscription
|
|
35
|
+
const subscription = await stackbe.subscriptions.get('cust_123');
|
|
36
|
+
|
|
37
|
+
// Send magic link
|
|
38
|
+
await stackbe.auth.sendMagicLink('user@example.com');
|
|
33
39
|
```
|
|
34
40
|
|
|
35
|
-
##
|
|
41
|
+
## Modules
|
|
42
|
+
|
|
43
|
+
### Usage Tracking
|
|
36
44
|
|
|
37
45
|
Track billable usage events for your customers:
|
|
38
46
|
|
|
@@ -43,17 +51,16 @@ await stackbe.usage.track('customer_123', 'api_calls');
|
|
|
43
51
|
// Track multiple units
|
|
44
52
|
await stackbe.usage.track('customer_123', 'tokens', { quantity: 1500 });
|
|
45
53
|
|
|
46
|
-
// Check
|
|
47
|
-
const usage = await stackbe.usage.get('customer_123');
|
|
48
|
-
console.log(usage.metrics);
|
|
49
|
-
// [{ metric: 'api_calls', currentUsage: 150, limit: 1000, remaining: 850 }]
|
|
50
|
-
|
|
51
|
-
// Check specific metric
|
|
54
|
+
// Check if within limits
|
|
52
55
|
const { allowed, remaining } = await stackbe.usage.check('customer_123', 'api_calls');
|
|
53
56
|
if (!allowed) {
|
|
54
57
|
throw new Error('Usage limit exceeded');
|
|
55
58
|
}
|
|
56
59
|
|
|
60
|
+
// Get full usage summary
|
|
61
|
+
const usage = await stackbe.usage.get('customer_123');
|
|
62
|
+
console.log(usage.metrics);
|
|
63
|
+
|
|
57
64
|
// Track and check in one call
|
|
58
65
|
const result = await stackbe.usage.trackAndCheck('customer_123', 'api_calls');
|
|
59
66
|
if (!result.allowed) {
|
|
@@ -61,7 +68,7 @@ if (!result.allowed) {
|
|
|
61
68
|
}
|
|
62
69
|
```
|
|
63
70
|
|
|
64
|
-
|
|
71
|
+
### Entitlements
|
|
65
72
|
|
|
66
73
|
Check feature access based on customer's plan:
|
|
67
74
|
|
|
@@ -69,33 +76,135 @@ Check feature access based on customer's plan:
|
|
|
69
76
|
// Check single feature
|
|
70
77
|
const { hasAccess } = await stackbe.entitlements.check('customer_123', 'premium_export');
|
|
71
78
|
|
|
72
|
-
if (!hasAccess) {
|
|
73
|
-
return res.status(403).json({ error: 'Upgrade to access this feature' });
|
|
74
|
-
}
|
|
75
|
-
|
|
76
79
|
// Get all entitlements
|
|
77
80
|
const { entitlements, planName } = await stackbe.entitlements.getAll('customer_123');
|
|
78
|
-
console.log(`Customer is on ${planName}`);
|
|
79
|
-
console.log(entitlements);
|
|
80
81
|
// { premium_export: true, api_access: true, max_projects: 10 }
|
|
81
82
|
|
|
82
83
|
// Check multiple features at once
|
|
83
84
|
const features = await stackbe.entitlements.checkMany('customer_123', [
|
|
84
85
|
'premium_export',
|
|
85
86
|
'advanced_analytics',
|
|
86
|
-
'api_access'
|
|
87
87
|
]);
|
|
88
|
-
// { premium_export: true, advanced_analytics: false, api_access: true }
|
|
89
88
|
|
|
90
89
|
// Require a feature (throws if not available)
|
|
91
90
|
await stackbe.entitlements.require('customer_123', 'premium_export');
|
|
92
91
|
```
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
### Checkout
|
|
94
|
+
|
|
95
|
+
Create Stripe checkout sessions:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// With existing customer ID
|
|
99
|
+
const { url } = await stackbe.checkout.createSession({
|
|
100
|
+
customer: 'cust_123',
|
|
101
|
+
planId: 'plan_pro_monthly',
|
|
102
|
+
successUrl: 'https://myapp.com/success',
|
|
103
|
+
cancelUrl: 'https://myapp.com/pricing',
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Redirect to checkout
|
|
107
|
+
res.redirect(url);
|
|
108
|
+
|
|
109
|
+
// With new customer (will be created)
|
|
110
|
+
const { url } = await stackbe.checkout.createSession({
|
|
111
|
+
customer: { email: 'user@example.com', name: 'John' },
|
|
112
|
+
planId: 'plan_pro_monthly',
|
|
113
|
+
successUrl: 'https://myapp.com/success',
|
|
114
|
+
trialDays: 14,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Get checkout URL directly
|
|
118
|
+
const checkoutUrl = await stackbe.checkout.getCheckoutUrl({
|
|
119
|
+
customer: 'cust_123',
|
|
120
|
+
planId: 'plan_pro',
|
|
121
|
+
successUrl: 'https://myapp.com/success',
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Subscriptions
|
|
126
|
+
|
|
127
|
+
Manage customer subscriptions:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// Get current subscription
|
|
131
|
+
const subscription = await stackbe.subscriptions.get('cust_123');
|
|
132
|
+
if (subscription) {
|
|
133
|
+
console.log(`Plan: ${subscription.plan.name}`);
|
|
134
|
+
console.log(`Status: ${subscription.status}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Check if customer has active subscription
|
|
138
|
+
const isActive = await stackbe.subscriptions.isActive('cust_123');
|
|
139
|
+
|
|
140
|
+
// Cancel subscription (at end of billing period)
|
|
141
|
+
await stackbe.subscriptions.cancel('sub_123');
|
|
142
|
+
|
|
143
|
+
// Cancel immediately
|
|
144
|
+
await stackbe.subscriptions.cancel('sub_123', { immediate: true });
|
|
145
|
+
|
|
146
|
+
// Update subscription (change plan)
|
|
147
|
+
await stackbe.subscriptions.update('sub_123', {
|
|
148
|
+
planId: 'plan_enterprise',
|
|
149
|
+
prorate: true,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Reactivate canceled subscription
|
|
153
|
+
await stackbe.subscriptions.reactivate('sub_123');
|
|
154
|
+
|
|
155
|
+
// List all subscriptions
|
|
156
|
+
const subscriptions = await stackbe.subscriptions.list('cust_123');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Authentication
|
|
160
|
+
|
|
161
|
+
Passwordless authentication with magic links:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Send magic link
|
|
165
|
+
await stackbe.auth.sendMagicLink('user@example.com');
|
|
166
|
+
|
|
167
|
+
// With redirect URL
|
|
168
|
+
await stackbe.auth.sendMagicLink('user@example.com', {
|
|
169
|
+
redirectUrl: 'https://myapp.com/dashboard',
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// For localhost development
|
|
173
|
+
await stackbe.auth.sendMagicLink('user@example.com', {
|
|
174
|
+
useDev: true,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Verify magic link token (in your /verify route)
|
|
178
|
+
const { token } = req.query;
|
|
179
|
+
const result = await stackbe.auth.verifyToken(token);
|
|
180
|
+
|
|
181
|
+
// result includes tenant and org context:
|
|
182
|
+
// - customerId, email, sessionToken
|
|
183
|
+
// - tenantId (your StackBE tenant)
|
|
184
|
+
// - organizationId, orgRole (if in org context)
|
|
185
|
+
res.cookie('session', result.sessionToken, { httpOnly: true });
|
|
186
|
+
res.redirect('/dashboard');
|
|
187
|
+
|
|
188
|
+
// Get session from token (includes tenant context)
|
|
189
|
+
const session = await stackbe.auth.getSession(sessionToken);
|
|
190
|
+
if (session) {
|
|
191
|
+
console.log(session.customerId);
|
|
192
|
+
console.log(session.email);
|
|
193
|
+
console.log(session.tenantId); // Tenant context
|
|
194
|
+
console.log(session.organizationId); // Org context (if applicable)
|
|
195
|
+
console.log(session.subscription);
|
|
196
|
+
console.log(session.entitlements);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check if authenticated
|
|
200
|
+
const isAuthenticated = await stackbe.auth.isAuthenticated(sessionToken);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Customer Management
|
|
95
204
|
|
|
96
205
|
```typescript
|
|
97
206
|
// Get customer
|
|
98
|
-
const customer = await stackbe.customers.get('
|
|
207
|
+
const customer = await stackbe.customers.get('cust_123');
|
|
99
208
|
|
|
100
209
|
// Get by email
|
|
101
210
|
const customer = await stackbe.customers.getByEmail('user@example.com');
|
|
@@ -104,53 +213,41 @@ const customer = await stackbe.customers.getByEmail('user@example.com');
|
|
|
104
213
|
const newCustomer = await stackbe.customers.create({
|
|
105
214
|
email: 'user@example.com',
|
|
106
215
|
name: 'John Doe',
|
|
107
|
-
metadata: { source: 'api' }
|
|
216
|
+
metadata: { source: 'api' },
|
|
108
217
|
});
|
|
109
218
|
|
|
110
219
|
// Get or create (idempotent)
|
|
111
220
|
const customer = await stackbe.customers.getOrCreate({
|
|
112
221
|
email: 'user@example.com',
|
|
113
|
-
name: 'John Doe'
|
|
222
|
+
name: 'John Doe',
|
|
114
223
|
});
|
|
115
224
|
|
|
116
225
|
// Update customer
|
|
117
|
-
await stackbe.customers.update('
|
|
118
|
-
name: 'Jane Doe'
|
|
119
|
-
});
|
|
226
|
+
await stackbe.customers.update('cust_123', { name: 'Jane Doe' });
|
|
120
227
|
```
|
|
121
228
|
|
|
122
229
|
## Express Middleware
|
|
123
230
|
|
|
124
|
-
The SDK includes ready-to-use middleware for Express:
|
|
125
|
-
|
|
126
231
|
### Track Usage Automatically
|
|
127
232
|
|
|
128
233
|
```typescript
|
|
129
|
-
import express from 'express';
|
|
130
|
-
import { StackBE } from '@stackbe/sdk';
|
|
131
|
-
|
|
132
|
-
const app = express();
|
|
133
|
-
const stackbe = new StackBE({ apiKey: '...', appId: '...' });
|
|
134
|
-
|
|
135
|
-
// Track all API calls
|
|
136
234
|
app.use(stackbe.middleware({
|
|
137
235
|
getCustomerId: (req) => req.user?.customerId,
|
|
138
236
|
metric: 'api_calls',
|
|
139
|
-
skip: (req) => req.path === '/health',
|
|
237
|
+
skip: (req) => req.path === '/health',
|
|
140
238
|
}));
|
|
141
239
|
```
|
|
142
240
|
|
|
143
241
|
### Require Feature Entitlements
|
|
144
242
|
|
|
145
243
|
```typescript
|
|
146
|
-
// Protect premium endpoints
|
|
147
244
|
app.get('/api/export',
|
|
148
245
|
stackbe.requireFeature({
|
|
149
246
|
getCustomerId: (req) => req.user?.customerId,
|
|
150
247
|
feature: 'premium_export',
|
|
151
248
|
onDenied: (req, res) => {
|
|
152
|
-
res.status(403).json({ error: 'Upgrade to Pro
|
|
153
|
-
}
|
|
249
|
+
res.status(403).json({ error: 'Upgrade to Pro' });
|
|
250
|
+
},
|
|
154
251
|
}),
|
|
155
252
|
exportHandler
|
|
156
253
|
);
|
|
@@ -159,23 +256,33 @@ app.get('/api/export',
|
|
|
159
256
|
### Enforce Usage Limits
|
|
160
257
|
|
|
161
258
|
```typescript
|
|
162
|
-
// Block requests when limit exceeded
|
|
163
259
|
app.use('/api',
|
|
164
260
|
stackbe.enforceLimit({
|
|
165
261
|
getCustomerId: (req) => req.user?.customerId,
|
|
166
262
|
metric: 'api_calls',
|
|
167
263
|
onLimitExceeded: (req, res, { current, limit }) => {
|
|
168
|
-
res.status(429).json({
|
|
169
|
-
|
|
170
|
-
current,
|
|
171
|
-
limit,
|
|
172
|
-
upgradeUrl: 'https://myapp.com/upgrade'
|
|
173
|
-
});
|
|
174
|
-
}
|
|
264
|
+
res.status(429).json({ error: 'Rate limit exceeded', current, limit });
|
|
265
|
+
},
|
|
175
266
|
})
|
|
176
267
|
);
|
|
177
268
|
```
|
|
178
269
|
|
|
270
|
+
### Authenticate Requests
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
app.use('/dashboard',
|
|
274
|
+
stackbe.auth.middleware({
|
|
275
|
+
getToken: (req) => req.cookies.session,
|
|
276
|
+
onUnauthenticated: (req, res) => res.redirect('/login'),
|
|
277
|
+
})
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
app.get('/dashboard', (req, res) => {
|
|
281
|
+
// req.customer, req.subscription, req.entitlements are available
|
|
282
|
+
res.json({ email: req.customer.email });
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
179
286
|
## Next.js Integration
|
|
180
287
|
|
|
181
288
|
### API Routes (App Router)
|
|
@@ -193,30 +300,23 @@ const stackbe = new StackBE({
|
|
|
193
300
|
export async function POST(request: Request) {
|
|
194
301
|
const { customerId } = await request.json();
|
|
195
302
|
|
|
196
|
-
// Check limits
|
|
303
|
+
// Check limits
|
|
197
304
|
const { allowed, remaining } = await stackbe.usage.check(customerId, 'generations');
|
|
198
|
-
|
|
199
305
|
if (!allowed) {
|
|
200
|
-
return NextResponse.json(
|
|
201
|
-
{ error: 'Generation limit reached', remaining: 0 },
|
|
202
|
-
{ status: 429 }
|
|
203
|
-
);
|
|
306
|
+
return NextResponse.json({ error: 'Limit reached' }, { status: 429 });
|
|
204
307
|
}
|
|
205
308
|
|
|
206
309
|
// Track usage
|
|
207
310
|
await stackbe.usage.track(customerId, 'generations');
|
|
208
311
|
|
|
209
|
-
// Do
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return NextResponse.json({ result, remaining: remaining! - 1 });
|
|
312
|
+
// Do work...
|
|
313
|
+
return NextResponse.json({ success: true, remaining: remaining! - 1 });
|
|
213
314
|
}
|
|
214
315
|
```
|
|
215
316
|
|
|
216
317
|
### Server Actions
|
|
217
318
|
|
|
218
319
|
```typescript
|
|
219
|
-
// app/actions.ts
|
|
220
320
|
'use server';
|
|
221
321
|
|
|
222
322
|
import { StackBE } from '@stackbe/sdk';
|
|
@@ -227,57 +327,143 @@ const stackbe = new StackBE({
|
|
|
227
327
|
});
|
|
228
328
|
|
|
229
329
|
export async function exportData(customerId: string) {
|
|
230
|
-
// Check feature access
|
|
231
330
|
const { hasAccess } = await stackbe.entitlements.check(customerId, 'data_export');
|
|
232
|
-
|
|
233
331
|
if (!hasAccess) {
|
|
234
332
|
throw new Error('Upgrade to Pro to export data');
|
|
235
333
|
}
|
|
236
|
-
|
|
237
334
|
// Perform export...
|
|
238
335
|
}
|
|
239
336
|
```
|
|
240
337
|
|
|
241
338
|
## Error Handling
|
|
242
339
|
|
|
340
|
+
The SDK provides typed error codes for specific error handling:
|
|
341
|
+
|
|
243
342
|
```typescript
|
|
244
343
|
import { StackBE, StackBEError } from '@stackbe/sdk';
|
|
245
344
|
|
|
246
345
|
try {
|
|
247
|
-
await stackbe.
|
|
346
|
+
await stackbe.auth.verifyToken(token);
|
|
248
347
|
} catch (error) {
|
|
249
348
|
if (error instanceof StackBEError) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
349
|
+
// Handle specific error types
|
|
350
|
+
switch (error.code) {
|
|
351
|
+
case 'TOKEN_EXPIRED':
|
|
352
|
+
return res.redirect('/login?error=expired');
|
|
353
|
+
case 'TOKEN_ALREADY_USED':
|
|
354
|
+
return res.redirect('/login?error=used');
|
|
355
|
+
case 'SESSION_EXPIRED':
|
|
356
|
+
return res.redirect('/login');
|
|
357
|
+
case 'CUSTOMER_NOT_FOUND':
|
|
358
|
+
return res.status(404).json({ error: 'Customer not found' });
|
|
359
|
+
case 'USAGE_LIMIT_EXCEEDED':
|
|
360
|
+
return res.status(429).json({ error: 'Limit exceeded' });
|
|
361
|
+
default:
|
|
362
|
+
return res.status(500).json({ error: 'Something went wrong' });
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Or use helper methods
|
|
366
|
+
if (error.isAuthError()) {
|
|
367
|
+
return res.redirect('/login');
|
|
368
|
+
}
|
|
369
|
+
if (error.isNotFoundError()) {
|
|
370
|
+
return res.status(404).json({ error: error.message });
|
|
371
|
+
}
|
|
253
372
|
}
|
|
254
373
|
}
|
|
255
374
|
```
|
|
256
375
|
|
|
376
|
+
### Error Codes
|
|
377
|
+
|
|
378
|
+
| Category | Codes |
|
|
379
|
+
|----------|-------|
|
|
380
|
+
| Auth | `TOKEN_EXPIRED`, `TOKEN_ALREADY_USED`, `TOKEN_INVALID`, `SESSION_EXPIRED`, `SESSION_INVALID`, `UNAUTHORIZED` |
|
|
381
|
+
| Resources | `NOT_FOUND`, `CUSTOMER_NOT_FOUND`, `SUBSCRIPTION_NOT_FOUND`, `PLAN_NOT_FOUND`, `APP_NOT_FOUND` |
|
|
382
|
+
| Usage | `USAGE_LIMIT_EXCEEDED`, `METRIC_NOT_FOUND` |
|
|
383
|
+
| Entitlements | `FEATURE_NOT_AVAILABLE`, `NO_ACTIVE_SUBSCRIPTION` |
|
|
384
|
+
| Validation | `VALIDATION_ERROR`, `MISSING_REQUIRED_FIELD`, `INVALID_EMAIL` |
|
|
385
|
+
| Network | `TIMEOUT`, `NETWORK_ERROR`, `UNKNOWN_ERROR` |
|
|
386
|
+
|
|
257
387
|
## Configuration
|
|
258
388
|
|
|
259
389
|
```typescript
|
|
260
390
|
const stackbe = new StackBE({
|
|
261
|
-
// Required
|
|
262
|
-
|
|
263
|
-
|
|
391
|
+
apiKey: 'sk_live_...', // Required: Your API key
|
|
392
|
+
appId: 'app_...', // Required: Your App ID
|
|
393
|
+
baseUrl: 'https://api.stackbe.io', // Optional: API base URL
|
|
394
|
+
timeout: 30000, // Optional: Request timeout in ms
|
|
395
|
+
});
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Webhooks
|
|
264
399
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
400
|
+
Typed webhook payloads for handling StackBE events:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import type {
|
|
404
|
+
AnyWebhookEvent,
|
|
405
|
+
SubscriptionCreatedEvent,
|
|
406
|
+
SubscriptionCancelledEvent,
|
|
407
|
+
PaymentFailedEvent,
|
|
408
|
+
} from '@stackbe/sdk';
|
|
409
|
+
|
|
410
|
+
// In your webhook handler
|
|
411
|
+
app.post('/webhooks/stackbe', (req, res) => {
|
|
412
|
+
const event = req.body as AnyWebhookEvent;
|
|
413
|
+
|
|
414
|
+
switch (event.type) {
|
|
415
|
+
case 'subscription_created':
|
|
416
|
+
const sub = event as SubscriptionCreatedEvent;
|
|
417
|
+
console.log(`New subscription: ${sub.data.planName}`);
|
|
418
|
+
break;
|
|
419
|
+
|
|
420
|
+
case 'subscription_cancelled':
|
|
421
|
+
const cancelled = event as SubscriptionCancelledEvent;
|
|
422
|
+
console.log(`Cancelled: ${cancelled.data.id}`);
|
|
423
|
+
break;
|
|
424
|
+
|
|
425
|
+
case 'payment_failed':
|
|
426
|
+
const payment = event as PaymentFailedEvent;
|
|
427
|
+
console.log(`Payment failed: ${payment.data.failureReason}`);
|
|
428
|
+
// Send dunning email
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
res.json({ received: true });
|
|
268
433
|
});
|
|
269
434
|
```
|
|
270
435
|
|
|
436
|
+
### Webhook Event Types
|
|
437
|
+
|
|
438
|
+
| Event | Payload |
|
|
439
|
+
|-------|---------|
|
|
440
|
+
| `subscription_created` | `SubscriptionWebhookPayload` |
|
|
441
|
+
| `subscription_updated` | `SubscriptionWebhookPayload` |
|
|
442
|
+
| `subscription_cancelled` | `SubscriptionWebhookPayload` |
|
|
443
|
+
| `subscription_renewed` | `SubscriptionWebhookPayload` |
|
|
444
|
+
| `trial_started` | `SubscriptionWebhookPayload` |
|
|
445
|
+
| `trial_ended` | `SubscriptionWebhookPayload` |
|
|
446
|
+
| `payment_succeeded` | `PaymentWebhookPayload` |
|
|
447
|
+
| `payment_failed` | `PaymentWebhookPayload` |
|
|
448
|
+
| `customer_created` | `CustomerWebhookPayload` |
|
|
449
|
+
| `customer_updated` | `CustomerWebhookPayload` |
|
|
450
|
+
|
|
271
451
|
## TypeScript
|
|
272
452
|
|
|
273
|
-
|
|
453
|
+
Full type definitions included:
|
|
274
454
|
|
|
275
455
|
```typescript
|
|
276
456
|
import type {
|
|
277
457
|
Customer,
|
|
278
458
|
Subscription,
|
|
459
|
+
SubscriptionWithPlan,
|
|
460
|
+
CheckoutSessionResponse,
|
|
461
|
+
SessionResponse,
|
|
279
462
|
TrackUsageResponse,
|
|
280
463
|
CheckEntitlementResponse,
|
|
464
|
+
StackBEErrorCode,
|
|
465
|
+
WebhookEventType,
|
|
466
|
+
AnyWebhookEvent,
|
|
281
467
|
} from '@stackbe/sdk';
|
|
282
468
|
```
|
|
283
469
|
|