@withaevum/sdk 0.0.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 ADDED
@@ -0,0 +1,621 @@
1
+ # @withaevum/sdk
2
+
3
+ TypeScript SDK for the Aevum API - a comprehensive scheduling and booking management platform.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @withaevum/sdk
9
+ # or
10
+ yarn add @withaevum/sdk
11
+ # or
12
+ pnpm add @withaevum/sdk
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Initialization
18
+
19
+ ```typescript
20
+ import { AevumClient } from '@withaevum/sdk';
21
+
22
+ const client = new AevumClient({
23
+ apiKey: process.env.AEVUM_API_KEY,
24
+ // Optional: customize base URL (default: https://withaevum.com)
25
+ baseUrl: 'https://withaevum.com',
26
+ });
27
+ ```
28
+
29
+ The SDK automatically resolves your organization ID from the API key, so you don't need to provide it manually.
30
+
31
+ ## API Reference
32
+
33
+ ### Bookings
34
+
35
+ #### Create a booking
36
+
37
+ ```typescript
38
+ const booking = await client.bookings.create({
39
+ providerIds: ['provider_123'],
40
+ offeringIds: ['offering_456'],
41
+ startTime: '2024-01-15T10:00:00Z',
42
+ endTime: '2024-01-15T10:30:00Z',
43
+ customerEmail: 'customer@example.com',
44
+ // Optional:
45
+ // customerId: 'customer_789',
46
+ // customer: { name: 'John Doe', email: 'john@example.com', phone: '+1234567890' },
47
+ // price_cents: 5000,
48
+ // notes: 'Special request',
49
+ // status: 'pending',
50
+ // kind: 'standard',
51
+ });
52
+ ```
53
+
54
+ #### Get a booking
55
+
56
+ ```typescript
57
+ const booking = await client.bookings.get('booking_123');
58
+ ```
59
+
60
+ #### List bookings
61
+
62
+ ```typescript
63
+ const bookings = await client.bookings.list({
64
+ providerId: 'provider_123',
65
+ startDate: '2024-01-01T00:00:00Z',
66
+ endDate: '2024-01-31T23:59:59Z',
67
+ status: 'confirmed',
68
+ page: 1,
69
+ pageSize: 20,
70
+ });
71
+ ```
72
+
73
+ #### Reschedule a booking
74
+
75
+ ```typescript
76
+ const updatedBooking = await client.bookings.reschedule('booking_123', {
77
+ start_time: '2024-01-15T11:00:00Z', // Note: API uses snake_case for these fields
78
+ end_time: '2024-01-15T11:30:00Z',
79
+ sendNotification: true, // Optional, default: false
80
+ });
81
+ ```
82
+
83
+ #### Cancel a booking
84
+
85
+ ```typescript
86
+ const cancelledBooking = await client.bookings.cancel(
87
+ 'booking_123',
88
+ 'Customer requested cancellation', // Optional reason
89
+ );
90
+ ```
91
+
92
+ #### Confirm a booking
93
+
94
+ ```typescript
95
+ const confirmedBooking = await client.bookings.confirm('booking_123', {
96
+ sendNotification: true, // Optional, default: false
97
+ });
98
+ ```
99
+
100
+ #### Update a booking
101
+
102
+ ```typescript
103
+ const updatedBooking = await client.bookings.update('booking_123', {
104
+ status: 'confirmed', // Optional: update status
105
+ notes: 'Updated notes', // Optional: update notes
106
+ });
107
+ ```
108
+
109
+ ### Offerings
110
+
111
+ #### List offerings
112
+
113
+ ```typescript
114
+ const offerings = await client.offerings.list({
115
+ eventId: 'event_123', // Optional: filter by event
116
+ providerId: 'provider_123', // Optional: filter by provider
117
+ });
118
+ ```
119
+
120
+ #### Get an offering
121
+
122
+ ```typescript
123
+ const offering = await client.offerings.get('offering_123');
124
+ ```
125
+
126
+ #### Create an offering
127
+
128
+ ```typescript
129
+ const offering = await client.offerings.create({
130
+ name: '60-minute Therapy Session',
131
+ description: 'One-on-one therapy session',
132
+ price_cents: 15000, // $150.00
133
+ duration_minutes: 60,
134
+ timezone: 'America/New_York',
135
+ attendee_mode: '1:1',
136
+ providerIds: ['provider_123'], // Optional: associate with providers
137
+ // Many more optional fields available for recurrence, scheduling windows, etc.
138
+ });
139
+ ```
140
+
141
+ #### Simple Offering Creation (Recommended for most use cases)
142
+
143
+ For most clients, the helper methods below provide a simpler way to create offerings without dealing with complex recurrence patterns and availability windows.
144
+
145
+ ##### Create a Simple Offering
146
+
147
+ Creates a basic 1:1 offering that uses provider availability schedules (no fixed times or recurrence):
148
+
149
+ ```typescript
150
+ const offering = await client.offerings.createSimple({
151
+ name: 'Therapy Session',
152
+ duration_minutes: 60,
153
+ price_cents: 15000, // $150.00
154
+ description: 'One-on-one therapy session',
155
+ timezone: 'America/New_York', // Optional, defaults to organization timezone
156
+ providerIds: ['provider_123'], // Optional: associate with providers
157
+ });
158
+ ```
159
+
160
+ ##### Create a Weekly Recurring Offering
161
+
162
+ Creates a weekly recurring offering with specific days and time slots:
163
+
164
+ ```typescript
165
+ const offering = await client.offerings.createRecurringWeekly({
166
+ name: 'Weekly Therapy',
167
+ duration_minutes: 60,
168
+ days: ['monday', 'wednesday', 'friday'], // Can also use ['MO', 'WE', 'FR']
169
+ timeSlots: [
170
+ { start: '09:00', end: '12:00' },
171
+ { start: '14:00', end: '17:00' }
172
+ ],
173
+ price_cents: 15000,
174
+ description: 'Weekly therapy sessions',
175
+ timezone: 'America/New_York',
176
+ providerIds: ['provider_123'],
177
+ });
178
+ ```
179
+
180
+ ##### Create a Daily Recurring Offering
181
+
182
+ Creates a daily recurring offering with time slots:
183
+
184
+ ```typescript
185
+ const offering = await client.offerings.createRecurringDaily({
186
+ name: 'Daily Consultation',
187
+ duration_minutes: 30,
188
+ timeSlots: [
189
+ { start: '09:00', end: '12:00' },
190
+ { start: '14:00', end: '17:00' }
191
+ ],
192
+ price_cents: 5000,
193
+ description: 'Daily consultation slots',
194
+ timezone: 'America/New_York',
195
+ providerIds: ['provider_123'],
196
+ });
197
+ ```
198
+
199
+ #### Update an offering
200
+
201
+ ```typescript
202
+ const updatedOffering = await client.offerings.update('offering_123', {
203
+ price_cents: 12000, // Optional: update price
204
+ duration_minutes: 90, // Optional: update duration
205
+ // Many more optional fields available
206
+ });
207
+ ```
208
+
209
+ #### Delete an offering
210
+
211
+ ```typescript
212
+ await client.offerings.delete('offering_123');
213
+ ```
214
+
215
+ #### Create offering from simple endpoint
216
+
217
+ ```typescript
218
+ // Uses the simplified /offerings/simple endpoint with preset-based configuration
219
+ const offering = await client.offerings.createFromSimple({
220
+ name: 'Therapy Session',
221
+ duration_minutes: 60,
222
+ price_cents: 15000,
223
+ preset: 'simple_1on1', // 'simple_1on1' | 'simple_group' | 'recurring_weekly' | 'recurring_daily'
224
+ provider_ids: ['provider_123'],
225
+ // For recurring_weekly:
226
+ // weekly_days: ['monday', 'wednesday'],
227
+ // weekly_time_slots: [{ start: '09:00', end: '17:00' }],
228
+ // For recurring_daily:
229
+ // daily_time_slots: [{ start: '09:00', end: '17:00' }],
230
+ });
231
+ ```
232
+
233
+ **When to use helper methods vs. full API:**
234
+ - Use `createSimple()` for basic offerings that rely on provider availability schedules
235
+ - Use `createRecurringWeekly()` or `createRecurringDaily()` for recurring offerings with fixed time slots
236
+ - Use `createFromSimple()` for preset-based configuration via the simplified endpoint
237
+ - Use `create()` directly when you need advanced features like custom recurrence intervals, monthly/yearly patterns, windowed modes, or other complex configurations
238
+
239
+ ### Customers
240
+
241
+ #### List customers
242
+
243
+ ```typescript
244
+ const customers = await client.customers.list({
245
+ q: 'john@example.com', // Optional: search by name/email/phone
246
+ providerId: 'provider_123', // Optional: filter by provider
247
+ page: 1,
248
+ pageSize: 50,
249
+ });
250
+ ```
251
+
252
+ #### Get a customer
253
+
254
+ ```typescript
255
+ const customer = await client.customers.get('customer_123');
256
+ ```
257
+
258
+ #### Create a customer
259
+
260
+ ```typescript
261
+ const customer = await client.customers.create({
262
+ name: 'John Doe',
263
+ email: 'john@example.com',
264
+ phone: '+1234567890', // Optional
265
+ userId: 'user_123', // Optional: link to internal user
266
+ });
267
+ ```
268
+
269
+ Note: If a customer with the same email already exists, they will be merged/updated.
270
+
271
+ #### Update a customer
272
+
273
+ ```typescript
274
+ const updatedCustomer = await client.customers.update('customer_123', {
275
+ name: 'John Smith', // Optional
276
+ email: 'john.smith@example.com', // Optional
277
+ phone: '+1987654321', // Optional
278
+ });
279
+ ```
280
+
281
+ #### Delete a customer
282
+
283
+ ```typescript
284
+ await client.customers.delete('customer_123');
285
+ ```
286
+
287
+ #### Get customer history
288
+
289
+ ```typescript
290
+ const history = await client.customers.getHistory('customer_123');
291
+ // Returns analytics, booking history, favorite providers, etc.
292
+ ```
293
+
294
+ ### Providers
295
+
296
+ #### List providers
297
+
298
+ ```typescript
299
+ const providers = await client.providers.list({
300
+ query: 'Dr. Smith', // Optional: search term
301
+ page: 1,
302
+ pageSize: 20,
303
+ });
304
+ ```
305
+
306
+ #### Get a provider
307
+
308
+ ```typescript
309
+ const provider = await client.providers.get('provider_123');
310
+ ```
311
+
312
+ #### Create a provider
313
+
314
+ ```typescript
315
+ const provider = await client.providers.create({
316
+ name: 'Dr. Jane Smith',
317
+ email: 'jane@example.com',
318
+ phone: '+1234567890', // Optional
319
+ bio: 'Licensed therapist with 10 years of experience', // Optional
320
+ userId: 'user_123', // Optional: link to internal user
321
+ });
322
+ ```
323
+
324
+ #### Update a provider
325
+
326
+ ```typescript
327
+ const updatedProvider = await client.providers.update('provider_123', {
328
+ name: 'Dr. Jane Smith, PhD', // Optional
329
+ email: 'jane.smith@example.com', // Optional
330
+ phone: '+1987654321', // Optional
331
+ bio: 'Updated bio', // Optional
332
+ minimum_advance_booking_minutes: 60, // Optional: minimum advance booking time in minutes
333
+ });
334
+ ```
335
+
336
+ #### Delete a provider
337
+
338
+ ```typescript
339
+ await client.providers.delete('provider_123');
340
+ ```
341
+
342
+ #### Google Calendar integration
343
+
344
+ ```typescript
345
+ // Get Google Calendar connection status
346
+ const status = await client.providers.getGoogleCalendarStatus('provider_123');
347
+ // Returns: { connected: boolean, email?: string, lastSync?: string }
348
+
349
+ // Sync Google Calendar
350
+ const syncResult = await client.providers.syncGoogleCalendar('provider_123');
351
+ // Returns: { success: boolean, syncedEvents?: number }
352
+
353
+ // Disconnect Google Calendar
354
+ await client.providers.disconnectGoogleCalendar('provider_123');
355
+ ```
356
+
357
+ ### Calendar
358
+
359
+ #### Get calendar events
360
+
361
+ ```typescript
362
+ const events = await client.calendar.getEvents({
363
+ providerId: 'provider_123', // Optional
364
+ start: '2024-01-01T00:00:00Z', // Optional: start date
365
+ end: '2024-01-31T23:59:59Z', // Optional: end date
366
+ });
367
+ // Returns both bookings and events combined
368
+ ```
369
+
370
+ ### Analytics
371
+
372
+ #### Get revenue analytics
373
+
374
+ ```typescript
375
+ const revenue = await client.analytics.getRevenue({
376
+ providerId: 'provider_123', // Optional
377
+ startDate: '2024-01-01T00:00:00Z', // Optional
378
+ endDate: '2024-01-31T23:59:59Z', // Optional
379
+ groupBy: 'day', // Optional: 'day' | 'week' | 'month' | 'offering' | 'provider'
380
+ });
381
+ ```
382
+
383
+ #### Get payouts
384
+
385
+ ```typescript
386
+ const payouts = await client.analytics.getPayouts({
387
+ providerId: 'provider_123', // Optional
388
+ startDate: '2024-01-01T00:00:00Z', // Optional
389
+ endDate: '2024-01-31T23:59:59Z', // Optional
390
+ customerId: 'customer_123', // Optional
391
+ });
392
+ ```
393
+
394
+ ### Payments
395
+
396
+ #### Get payment intent
397
+
398
+ ```typescript
399
+ const paymentIntent = await client.payments.getIntent('pi_1234567890');
400
+ // Returns: { paymentIntentId, clientSecret, amount, status }
401
+ ```
402
+
403
+ #### Update payment intent
404
+
405
+ ```typescript
406
+ const updatedIntent = await client.payments.updateIntent({
407
+ paymentIntentId: 'pi_1234567890',
408
+ tipAmountCents: 500, // Tip amount in cents
409
+ bookingId: 'booking_123', // Optional: associate with booking
410
+ });
411
+ ```
412
+
413
+ ### Organizations
414
+
415
+ #### Get organization details
416
+
417
+ ```typescript
418
+ const org = await client.orgs.get();
419
+ // Returns: { id, name, slug, timezone, clerk_org_id }
420
+ ```
421
+
422
+ #### Get booking settings
423
+
424
+ ```typescript
425
+ const settings = await client.orgs.getBookingSettings();
426
+ // Returns booking configuration including safe period hours
427
+ ```
428
+
429
+ #### Update booking settings
430
+
431
+ ```typescript
432
+ const updatedSettings = await client.orgs.updateBookingSettings({
433
+ safe_period_hours: 24, // Minimum hours before bookings can be made
434
+ });
435
+ ```
436
+
437
+ ### Availability
438
+
439
+ #### Get available slots
440
+
441
+ ```typescript
442
+ // Enhanced version with offeringId and limit support
443
+ const availability = await client.availability.getSlots({
444
+ providerId: 'provider_123', // Optional if offeringId provided
445
+ offeringId: 'offering_123', // Optional
446
+ start: '2024-01-15T00:00:00Z',
447
+ end: '2024-01-22T23:59:59Z',
448
+ limit: 50, // Optional: max number of slots
449
+ });
450
+
451
+ // Or use the original format for backward compatibility
452
+ const availability2 = await client.availability.getSlots({
453
+ providerId: 'provider_123',
454
+ startDate: '2024-01-15T00:00:00Z',
455
+ endDate: '2024-01-22T23:59:59Z',
456
+ });
457
+ ```
458
+
459
+ #### Get availability schedules
460
+
461
+ ```typescript
462
+ const schedules = await client.availability.getSchedules({
463
+ providerId: 'provider_123', // Optional
464
+ });
465
+ ```
466
+
467
+ #### Check specific time availability
468
+
469
+ ```typescript
470
+ const isAvailable = await client.availability.check({
471
+ providerId: 'provider_123',
472
+ startTime: '2024-01-15T10:00:00Z',
473
+ duration: 30, // minutes
474
+ });
475
+ ```
476
+
477
+ #### Create an availability schedule
478
+
479
+ ```typescript
480
+ const schedule = await client.availability.createSchedule({
481
+ providerId: 'provider_123',
482
+ name: 'Business Hours',
483
+ timezone: 'America/New_York',
484
+ weekly_hours: {
485
+ monday: [{ start: '09:00', end: '17:00' }],
486
+ tuesday: [{ start: '09:00', end: '17:00' }],
487
+ wednesday: [{ start: '09:00', end: '17:00' }],
488
+ thursday: [{ start: '09:00', end: '17:00' }],
489
+ friday: [{ start: '09:00', end: '17:00' }],
490
+ },
491
+ recurrence_preset: 'weekly',
492
+ recurrence_end_mode: 'never', // or 'date' | 'count'
493
+ });
494
+ ```
495
+
496
+ #### Get an availability schedule
497
+
498
+ ```typescript
499
+ const schedule = await client.availability.getSchedule('schedule_123');
500
+ ```
501
+
502
+ #### Update an availability schedule
503
+
504
+ ```typescript
505
+ const updatedSchedule = await client.availability.updateSchedule('schedule_123', {
506
+ name: 'Updated Schedule Name', // Optional
507
+ timezone: 'America/Los_Angeles', // Optional
508
+ weekly_hours: { /* updated hours */ }, // Optional
509
+ });
510
+ ```
511
+
512
+ #### Delete an availability schedule
513
+
514
+ ```typescript
515
+ await client.availability.deleteSchedule('schedule_123');
516
+ ```
517
+
518
+ ## Error Handling
519
+
520
+ The SDK throws typed errors for different scenarios:
521
+
522
+ ```typescript
523
+ import {
524
+ AevumError,
525
+ AevumAPIError,
526
+ AevumAuthenticationError,
527
+ AevumValidationError,
528
+ AevumNotFoundError,
529
+ } from '@withaevum/sdk';
530
+
531
+ try {
532
+ const booking = await client.bookings.get('invalid_id');
533
+ } catch (error) {
534
+ if (error instanceof AevumNotFoundError) {
535
+ console.log('Booking not found');
536
+ } else if (error instanceof AevumAuthenticationError) {
537
+ console.log('Invalid API key');
538
+ } else if (error instanceof AevumValidationError) {
539
+ console.log('Validation error:', error.issues);
540
+ } else if (error instanceof AevumAPIError) {
541
+ console.log('API error:', error.message, error.status);
542
+ }
543
+ }
544
+ ```
545
+
546
+ ## TypeScript Support
547
+
548
+ The SDK is fully typed with TypeScript. All methods include type definitions for parameters and return values, providing autocomplete and type checking.
549
+
550
+ All types are exported for your convenience:
551
+
552
+ ```typescript
553
+ import type {
554
+ Booking,
555
+ Offering,
556
+ Customer,
557
+ Provider,
558
+ CalendarEvent,
559
+ RevenueResponse,
560
+ PayoutsResponse,
561
+ // ... and many more
562
+ } from '@withaevum/sdk';
563
+ ```
564
+
565
+ ## Migration Guide (from Custom Client)
566
+
567
+ If you're migrating from a custom Aevum client implementation (like mendbloom's), here's how to update:
568
+
569
+ ### Before (Custom Client)
570
+
571
+ ```typescript
572
+ import { AevumClient } from '@/lib/aevum/client';
573
+
574
+ const client = new AevumClient(apiKey, orgId);
575
+ const offerings = await client.getOfferings({ eventId: 'event_123' });
576
+ ```
577
+
578
+ ### After (SDK)
579
+
580
+ ```typescript
581
+ import { AevumClient } from '@withaevum/sdk';
582
+
583
+ const client = new AevumClient({ apiKey });
584
+ const offerings = await client.offerings.list({ eventId: 'event_123' });
585
+ ```
586
+
587
+ ### Key Changes
588
+
589
+ 1. **Installation**: `npm install @withaevum/sdk`
590
+ 2. **Initialization**: No need to pass `orgId` - it's resolved automatically
591
+ 3. **Method Names**: Use namespaced methods (e.g., `client.offerings.list()` instead of `client.getOfferings()`)
592
+ 4. **Error Handling**: Use SDK error classes instead of generic errors
593
+ 5. **Types**: Import types from SDK instead of defining your own
594
+
595
+ ### Method Mapping
596
+
597
+ | Custom Client | SDK |
598
+ |--------------|-----|
599
+ | `client.getOfferings()` | `client.offerings.list()` |
600
+ | `client.getOffering(id)` | `client.offerings.get(id)` |
601
+ | `client.createOffering()` | `client.offerings.create()` |
602
+ | `client.getCustomers()` | `client.customers.list()` |
603
+ | `client.getCustomer(id)` | `client.customers.get(id)` |
604
+ | `client.createCustomer()` | `client.customers.create()` |
605
+ | `client.getProviders()` | `client.providers.list()` |
606
+ | `client.createProvider()` | `client.providers.create()` |
607
+ | `client.getCalendarEvents()` | `client.calendar.getEvents()` |
608
+ | `client.getRevenue()` | `client.analytics.getRevenue()` |
609
+ | `client.getPayouts()` | `client.analytics.getPayouts()` |
610
+ | `client.getAvailabilitySchedules()` | `client.availability.getSchedules()` |
611
+ | `client.getAvailabilitySlots()` | `client.availability.getSlots()` |
612
+ | `client.rescheduleBooking()` | `client.bookings.reschedule()` |
613
+
614
+ ## Requirements
615
+
616
+ - Node.js 18+ or modern browser with fetch support
617
+ - Valid Aevum API key
618
+
619
+ ## License
620
+
621
+ ISC
@@ -0,0 +1,17 @@
1
+ import { AevumClient } from './client';
2
+ import type { GetRevenueParams, RevenueResponse, GetPayoutsParams, PayoutsResponse } from './types';
3
+ /**
4
+ * Analytics API methods
5
+ */
6
+ export declare class AnalyticsAPI {
7
+ private client;
8
+ constructor(client: AevumClient);
9
+ /**
10
+ * Get revenue analytics
11
+ */
12
+ getRevenue(params?: GetRevenueParams): Promise<RevenueResponse>;
13
+ /**
14
+ * Get payouts (revenue from confirmed bookings)
15
+ */
16
+ getPayouts(params?: GetPayoutsParams): Promise<PayoutsResponse>;
17
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Analytics API methods
3
+ */
4
+ export class AnalyticsAPI {
5
+ constructor(client) {
6
+ this.client = client;
7
+ }
8
+ /**
9
+ * Get revenue analytics
10
+ */
11
+ async getRevenue(params) {
12
+ const query = {};
13
+ if (params?.providerId) {
14
+ query.providerId = params.providerId;
15
+ }
16
+ if (params?.startDate) {
17
+ query.startDate = params.startDate;
18
+ }
19
+ if (params?.endDate) {
20
+ query.endDate = params.endDate;
21
+ }
22
+ if (params?.groupBy) {
23
+ query.groupBy = params.groupBy;
24
+ }
25
+ return this.client.request('GET', '/api/v1/orgs/{orgId}/analytics/revenue', { query });
26
+ }
27
+ /**
28
+ * Get payouts (revenue from confirmed bookings)
29
+ */
30
+ async getPayouts(params) {
31
+ const query = {};
32
+ if (params?.providerId) {
33
+ query.providerId = params.providerId;
34
+ }
35
+ if (params?.startDate) {
36
+ query.startDate = params.startDate;
37
+ }
38
+ if (params?.endDate) {
39
+ query.endDate = params.endDate;
40
+ }
41
+ if (params?.customerId) {
42
+ query.customerId = params.customerId;
43
+ }
44
+ return this.client.request('GET', '/api/v1/orgs/{orgId}/payouts', { query });
45
+ }
46
+ }