@billingos/sdk 0.1.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 ADDED
@@ -0,0 +1,582 @@
1
+ # BillingOS SDK
2
+
3
+ Official React SDK for BillingOS - A comprehensive billing, subscriptions, and payments platform.
4
+
5
+ ## Features
6
+
7
+ - ✅ **React Hooks** - Powerful hooks for subscriptions, entitlements, usage tracking, and more
8
+ - ✅ **TypeScript Support** - Full type safety with auto-generated types
9
+ - ✅ **React Query Integration** - Automatic caching, refetching, and state management
10
+ - ✅ **API Client** - Comprehensive API client with error handling
11
+ - ✅ **Money Utilities** - Currency formatting and conversion helpers
12
+ - ✅ **Date Utilities** - Date formatting and manipulation
13
+ - ✅ **Next.js Compatible** - Works seamlessly with Next.js App Router and Pages Router
14
+ - ✅ **Framework Agnostic Core** - Can be extended to other frameworks in the future
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ # npm
20
+ npm install @billingos/sdk
21
+
22
+ # pnpm
23
+ pnpm add @billingos/sdk
24
+
25
+ # yarn
26
+ yarn add @billingos/sdk
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ### 1. Wrap your app with BillingOSProvider
32
+
33
+ ```tsx
34
+ // app/layout.tsx (Next.js App Router)
35
+ import { BillingOSProvider } from '@billingos/sdk'
36
+ import '@billingos/sdk/styles.css'
37
+
38
+ export default function RootLayout({ children }) {
39
+ return (
40
+ <html lang="en">
41
+ <body>
42
+ <BillingOSProvider
43
+ apiKey={process.env.NEXT_PUBLIC_BILLINGOS_API_KEY}
44
+ customerId="cus_123" // Optional: current user's customer ID
45
+ >
46
+ {children}
47
+ </BillingOSProvider>
48
+ </body>
49
+ </html>
50
+ )
51
+ }
52
+ ```
53
+
54
+ ### 2. Use hooks in your components
55
+
56
+ ```tsx
57
+ 'use client' // Next.js App Router
58
+
59
+ import { useSubscriptions, useHasFeature } from '@billingos/sdk'
60
+
61
+ export default function SubscriptionsPage() {
62
+ const { data: subscriptions, isLoading } = useSubscriptions({
63
+ customer_id: 'cus_123'
64
+ })
65
+
66
+ const hasAdvancedAnalytics = useHasFeature('cus_123', 'advanced_analytics')
67
+
68
+ if (isLoading) return <div>Loading...</div>
69
+
70
+ return (
71
+ <div>
72
+ <h1>Your Subscriptions</h1>
73
+ {subscriptions?.data.map(subscription => (
74
+ <SubscriptionCard key={subscription.id} subscription={subscription} />
75
+ ))}
76
+
77
+ {hasAdvancedAnalytics && (
78
+ <AdvancedAnalyticsDashboard />
79
+ )}
80
+ </div>
81
+ )
82
+ }
83
+ ```
84
+
85
+ ## API Reference
86
+
87
+ ### BillingOSProvider
88
+
89
+ The root provider component that wraps your app.
90
+
91
+ **Props:**
92
+ - `apiKey` (string, required) - Your BillingOS API key
93
+ - `customerId` (string, optional) - Current user's customer ID
94
+ - `organizationId` (string, optional) - Current organization ID
95
+ - `options` (object, optional) - Client configuration options
96
+ - `baseUrl` (string) - Custom API base URL
97
+ - `environment` ('production' | 'sandbox') - Environment
98
+ - `version` (string) - API version
99
+ - `headers` (object) - Additional headers
100
+ - `timeout` (number) - Request timeout in milliseconds
101
+
102
+ ### Subscription Hooks
103
+
104
+ #### `useSubscription(id, options?)`
105
+
106
+ Fetch a single subscription by ID.
107
+
108
+ ```tsx
109
+ const { data: subscription, isLoading, error } = useSubscription('sub_123')
110
+ ```
111
+
112
+ #### `useSubscriptions(params?, options?)`
113
+
114
+ List all subscriptions with pagination.
115
+
116
+ ```tsx
117
+ const { data, isLoading } = useSubscriptions({
118
+ customer_id: 'cus_123',
119
+ page: 1,
120
+ page_size: 10
121
+ })
122
+ ```
123
+
124
+ #### `useCreateSubscription(options?)`
125
+
126
+ Create a new subscription.
127
+
128
+ ```tsx
129
+ const createSubscription = useCreateSubscription()
130
+
131
+ const handleSubscribe = () => {
132
+ createSubscription.mutate({
133
+ customer_id: 'cus_123',
134
+ price_id: 'price_pro_plan',
135
+ trial_days: 14
136
+ })
137
+ }
138
+ ```
139
+
140
+ #### `useUpdateSubscription(subscriptionId, options?)`
141
+
142
+ Update an existing subscription (upgrade/downgrade).
143
+
144
+ ```tsx
145
+ const updateSubscription = useUpdateSubscription('sub_123')
146
+
147
+ const handleUpgrade = () => {
148
+ updateSubscription.mutate({
149
+ price_id: 'price_enterprise_plan'
150
+ })
151
+ }
152
+ ```
153
+
154
+ #### `useCancelSubscription(subscriptionId, options?)`
155
+
156
+ Cancel a subscription.
157
+
158
+ ```tsx
159
+ const cancelSubscription = useCancelSubscription('sub_123')
160
+
161
+ const handleCancel = () => {
162
+ cancelSubscription.mutate({ immediately: false }) // Cancel at period end
163
+ }
164
+ ```
165
+
166
+ #### `useReactivateSubscription(subscriptionId, options?)`
167
+
168
+ Reactivate a canceled subscription.
169
+
170
+ ```tsx
171
+ const reactivateSubscription = useReactivateSubscription('sub_123')
172
+
173
+ const handleReactivate = () => {
174
+ reactivateSubscription.mutate()
175
+ }
176
+ ```
177
+
178
+ #### `useSubscriptionPreview(subscriptionId, input, options?)`
179
+
180
+ Preview subscription changes before applying.
181
+
182
+ ```tsx
183
+ const { data: preview } = useSubscriptionPreview('sub_123', {
184
+ price_id: 'price_pro_plan'
185
+ })
186
+
187
+ console.log(`Proration: $${preview?.proration_amount / 100}`)
188
+ console.log(`Next invoice: $${preview?.next_invoice_amount / 100}`)
189
+ ```
190
+
191
+ ### Entitlement Hooks
192
+
193
+ #### `useCheckEntitlement(customerId, featureKey, options?)`
194
+
195
+ Check if a customer has access to a feature.
196
+
197
+ ```tsx
198
+ const { data: entitlement } = useCheckEntitlement('cus_123', 'advanced_analytics')
199
+
200
+ if (entitlement?.has_access) {
201
+ // Show premium feature
202
+ }
203
+ ```
204
+
205
+ #### `useHasFeature(customerId, featureKey, options?)`
206
+
207
+ Simplified hook that returns a boolean.
208
+
209
+ ```tsx
210
+ const hasAccess = useHasFeature('cus_123', 'advanced_analytics')
211
+ ```
212
+
213
+ #### `useEntitlements(customerId, options?)`
214
+
215
+ Get all entitlements for a customer.
216
+
217
+ ```tsx
218
+ const { data: entitlements } = useEntitlements('cus_123')
219
+ ```
220
+
221
+ #### `useTrackUsage(options?)`
222
+
223
+ Track usage events.
224
+
225
+ ```tsx
226
+ const trackUsage = useTrackUsage()
227
+
228
+ const handleAPICall = async () => {
229
+ await makeAPICall()
230
+
231
+ trackUsage.mutate({
232
+ customer_id: 'cus_123',
233
+ feature_key: 'api_calls',
234
+ quantity: 1
235
+ })
236
+ }
237
+ ```
238
+
239
+ #### `useUsageMetrics(customerId, featureKey, options?)`
240
+
241
+ Get usage metrics for a feature.
242
+
243
+ ```tsx
244
+ const { data: metrics } = useUsageMetrics('cus_123', 'api_calls')
245
+
246
+ console.log(`Usage: ${metrics?.current_usage} / ${metrics?.limit}`)
247
+ ```
248
+
249
+ #### `useIsApproachingLimit(customerId, featureKey, threshold?, options?)`
250
+
251
+ Check if usage is approaching the limit.
252
+
253
+ ```tsx
254
+ const isApproachingLimit = useIsApproachingLimit('cus_123', 'api_calls', 80)
255
+
256
+ if (isApproachingLimit) {
257
+ // Show warning message
258
+ }
259
+ ```
260
+
261
+ ### API Client
262
+
263
+ You can also use the API client directly for custom requests.
264
+
265
+ ```tsx
266
+ import { useBillingOS } from '@billingos/sdk'
267
+
268
+ function MyComponent() {
269
+ const { client } = useBillingOS()
270
+
271
+ const handleCustomRequest = async () => {
272
+ const subscription = await client.getSubscription('sub_123')
273
+ const customer = await client.getCustomer('cus_123')
274
+ }
275
+ }
276
+ ```
277
+
278
+ **Available Methods:**
279
+ - `createCustomer(input)` - Create customer
280
+ - `getCustomer(id)` - Get customer
281
+ - `listCustomers(params)` - List customers
282
+ - `updateCustomer(id, input)` - Update customer
283
+ - `deleteCustomer(id)` - Delete customer
284
+ - `createSubscription(input)` - Create subscription
285
+ - `getSubscription(id)` - Get subscription
286
+ - `listSubscriptions(params)` - List subscriptions
287
+ - `updateSubscription(id, input)` - Update subscription
288
+ - `cancelSubscription(id, immediately)` - Cancel subscription
289
+ - `reactivateSubscription(id)` - Reactivate subscription
290
+ - `previewSubscription(id, input)` - Preview changes
291
+ - `checkEntitlement(input)` - Check feature access
292
+ - `listEntitlements(customerId)` - List entitlements
293
+ - `trackUsage(event)` - Track usage
294
+ - `getUsageMetrics(customerId, featureKey)` - Get metrics
295
+ - `getInvoice(id)` - Get invoice
296
+ - `listInvoices(params)` - List invoices
297
+ - `listPaymentMethods(customerId)` - List payment methods
298
+ - `removePaymentMethod(id)` - Remove payment method
299
+ - `setDefaultPaymentMethod(id)` - Set default payment method
300
+
301
+ ### Utilities
302
+
303
+ #### Money Utilities
304
+
305
+ ```tsx
306
+ import { Money, formatCurrencyAndAmount, getCentsInDollarString } from '@billingos/sdk'
307
+
308
+ // Format currency with symbol
309
+ Money.format(1050, 'USD') // "$10.50"
310
+ Money.formatCompact(1200000, 'USD') // "$12K"
311
+ Money.formatWhole(1050, 'USD') // "$10"
312
+
313
+ // Convert between cents and dollars
314
+ Money.fromCents(1050) // 10.5
315
+ Money.toCents(10.5) // 1050
316
+
317
+ // Get currency symbol
318
+ Money.getSymbol('USD') // "$"
319
+ Money.getSymbol('EUR') // "€"
320
+
321
+ // Calculations
322
+ Money.calculatePercentage(10000, 20) // 2000 (20% of $100)
323
+ Money.add(1000, 2000, 3000) // 6000 ($60)
324
+ ```
325
+
326
+ #### Date Utilities
327
+
328
+ ```tsx
329
+ import { DateUtils, formatDate, formatRelativeTime } from '@billingos/sdk'
330
+
331
+ // Format dates
332
+ DateUtils.format('2024-01-15T10:30:00Z', 'PPP') // "January 15th, 2024"
333
+ DateUtils.format(new Date(), 'yyyy-MM-dd') // "2024-01-15"
334
+
335
+ // Relative time
336
+ DateUtils.formatRelative('2024-01-15T08:30:00Z') // "2 hours ago"
337
+
338
+ // Check dates
339
+ DateUtils.isPast('2024-01-01') // true
340
+ DateUtils.isFuture('2025-01-01') // true
341
+ ```
342
+
343
+ ## Examples
344
+
345
+ ### Complete Subscription Management Page
346
+
347
+ ```tsx
348
+ 'use client'
349
+
350
+ import {
351
+ useSubscriptions,
352
+ useUpdateSubscription,
353
+ useCancelSubscription,
354
+ useSubscriptionPreview
355
+ } from '@billingos/sdk'
356
+
357
+ export default function SubscriptionsPage() {
358
+ const { data, isLoading } = useSubscriptions({ customer_id: 'cus_123' })
359
+
360
+ if (isLoading) return <div>Loading...</div>
361
+
362
+ return (
363
+ <div>
364
+ <h1>Your Subscriptions</h1>
365
+ {data?.data.map(subscription => (
366
+ <SubscriptionCard key={subscription.id} subscription={subscription} />
367
+ ))}
368
+ </div>
369
+ )
370
+ }
371
+
372
+ function SubscriptionCard({ subscription }) {
373
+ const updateSubscription = useUpdateSubscription(subscription.id)
374
+ const cancelSubscription = useCancelSubscription(subscription.id)
375
+ const { data: preview } = useSubscriptionPreview(subscription.id, {
376
+ price_id: 'price_pro_plan'
377
+ })
378
+
379
+ const handleUpgrade = () => {
380
+ if (confirm(`Upgrade for $${preview?.proration_amount / 100}?`)) {
381
+ updateSubscription.mutate({ price_id: 'price_pro_plan' })
382
+ }
383
+ }
384
+
385
+ const handleCancel = () => {
386
+ if (confirm('Cancel subscription?')) {
387
+ cancelSubscription.mutate({ immediately: false })
388
+ }
389
+ }
390
+
391
+ return (
392
+ <div className="border p-4 rounded-lg">
393
+ <h2>Status: {subscription.status}</h2>
394
+ <p>Period: {subscription.current_period_start} - {subscription.current_period_end}</p>
395
+
396
+ <div className="mt-4 flex gap-2">
397
+ <button onClick={handleUpgrade}>Upgrade</button>
398
+ <button onClick={handleCancel}>Cancel</button>
399
+ </div>
400
+ </div>
401
+ )
402
+ }
403
+ ```
404
+
405
+ ### Feature Gating
406
+
407
+ ```tsx
408
+ 'use client'
409
+
410
+ import { useHasFeature } from '@billingos/sdk'
411
+
412
+ export default function DashboardPage() {
413
+ const hasAnalytics = useHasFeature('cus_123', 'advanced_analytics')
414
+ const hasExport = useHasFeature('cus_123', 'data_export')
415
+
416
+ return (
417
+ <div>
418
+ <h1>Dashboard</h1>
419
+
420
+ {hasAnalytics ? (
421
+ <AdvancedAnalytics />
422
+ ) : (
423
+ <UpgradePrompt feature="Advanced Analytics" />
424
+ )}
425
+
426
+ {hasExport && <ExportButton />}
427
+ </div>
428
+ )
429
+ }
430
+ ```
431
+
432
+ ### Usage Tracking
433
+
434
+ ```tsx
435
+ 'use client'
436
+
437
+ import { useTrackUsage, useUsageMetrics } from '@billingos/sdk'
438
+
439
+ export default function APICallButton() {
440
+ const trackUsage = useTrackUsage()
441
+ const { data: metrics } = useUsageMetrics('cus_123', 'api_calls')
442
+
443
+ const handleAPICall = async () => {
444
+ try {
445
+ // Make API call
446
+ await fetch('/api/data')
447
+
448
+ // Track usage
449
+ trackUsage.mutate({
450
+ customer_id: 'cus_123',
451
+ feature_key: 'api_calls',
452
+ quantity: 1
453
+ })
454
+ } catch (error) {
455
+ console.error('API call failed:', error)
456
+ }
457
+ }
458
+
459
+ return (
460
+ <div>
461
+ <p>Usage: {metrics?.current_usage} / {metrics?.limit} calls</p>
462
+ <button onClick={handleAPICall}>Make API Call</button>
463
+ </div>
464
+ )
465
+ }
466
+ ```
467
+
468
+ ## Error Handling
469
+
470
+ The SDK includes typed error classes for better error handling:
471
+
472
+ ```tsx
473
+ import {
474
+ isValidationError,
475
+ isUnauthorizedError,
476
+ isNotFoundError
477
+ } from '@billingos/sdk'
478
+
479
+ try {
480
+ await client.getSubscription('sub_123')
481
+ } catch (error) {
482
+ if (isUnauthorizedError(error)) {
483
+ console.error('Invalid API key')
484
+ } else if (isNotFoundError(error)) {
485
+ console.error('Subscription not found')
486
+ } else if (isValidationError(error)) {
487
+ console.error('Validation failed:', error.data)
488
+ }
489
+ }
490
+ ```
491
+
492
+ ## TypeScript
493
+
494
+ The SDK is built with TypeScript and includes full type definitions.
495
+
496
+ ```tsx
497
+ import type {
498
+ Subscription,
499
+ Customer,
500
+ Entitlement,
501
+ CreateSubscriptionInput,
502
+ UpdateSubscriptionInput
503
+ } from '@billingos/sdk'
504
+
505
+ const subscription: Subscription = {
506
+ id: 'sub_123',
507
+ customer_id: 'cus_123',
508
+ price_id: 'price_pro',
509
+ status: 'active',
510
+ // ... other fields
511
+ }
512
+ ```
513
+
514
+ ## Next.js Integration
515
+
516
+ ### App Router
517
+
518
+ ```tsx
519
+ // app/layout.tsx
520
+ import { BillingOSProvider } from '@billingos/sdk'
521
+ import '@billingos/sdk/styles.css'
522
+
523
+ export default function RootLayout({ children }) {
524
+ return (
525
+ <html>
526
+ <body>
527
+ <BillingOSProvider apiKey={process.env.NEXT_PUBLIC_BILLINGOS_API_KEY}>
528
+ {children}
529
+ </BillingOSProvider>
530
+ </body>
531
+ </html>
532
+ )
533
+ }
534
+
535
+ // app/subscriptions/page.tsx
536
+ 'use client'
537
+
538
+ import { useSubscriptions } from '@billingos/sdk'
539
+
540
+ export default function SubscriptionsPage() {
541
+ const { data } = useSubscriptions()
542
+ return <div>{/* ... */}</div>
543
+ }
544
+ ```
545
+
546
+ ### Pages Router
547
+
548
+ ```tsx
549
+ // pages/_app.tsx
550
+ import { BillingOSProvider } from '@billingos/sdk'
551
+ import '@billingos/sdk/styles.css'
552
+
553
+ export default function App({ Component, pageProps }) {
554
+ return (
555
+ <BillingOSProvider apiKey={process.env.NEXT_PUBLIC_BILLINGOS_API_KEY}>
556
+ <Component {...pageProps} />
557
+ </BillingOSProvider>
558
+ )
559
+ }
560
+
561
+ // pages/subscriptions.tsx
562
+ import { useSubscriptions } from '@billingos/sdk'
563
+
564
+ export default function SubscriptionsPage() {
565
+ const { data } = useSubscriptions()
566
+ return <div>{/* ... */}</div>
567
+ }
568
+ ```
569
+
570
+ ## Contributing
571
+
572
+ We welcome contributions! Please see our contributing guidelines for more information.
573
+
574
+ ## License
575
+
576
+ MIT
577
+
578
+ ## Support
579
+
580
+ - Documentation: https://docs.billingos.com
581
+ - Issues: https://github.com/billingos/sdk/issues
582
+ - Email: support@billingos.com