@withaevum/sdk 1.0.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,436 @@
1
+ # @aevum/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 @aevum/sdk
9
+ # or
10
+ yarn add @aevum/sdk
11
+ # or
12
+ pnpm add @aevum/sdk
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Initialization
18
+
19
+ ```typescript
20
+ import { AevumClient } from '@aevum/sdk';
21
+
22
+ const client = new AevumClient({
23
+ apiKey: process.env.AEVUM_API_KEY,
24
+ // Optional: customize base URL (default: https://api.withaevum.com)
25
+ baseUrl: 'https://api.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',
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
+ ### Offerings
93
+
94
+ #### List offerings
95
+
96
+ ```typescript
97
+ const offerings = await client.offerings.list({
98
+ eventId: 'event_123', // Optional: filter by event
99
+ providerId: 'provider_123', // Optional: filter by provider
100
+ });
101
+ ```
102
+
103
+ #### Get an offering
104
+
105
+ ```typescript
106
+ const offering = await client.offerings.get('offering_123');
107
+ ```
108
+
109
+ #### Create an offering
110
+
111
+ ```typescript
112
+ const offering = await client.offerings.create({
113
+ name: '60-minute Therapy Session',
114
+ description: 'One-on-one therapy session',
115
+ price_cents: 15000, // $150.00
116
+ duration_minutes: 60,
117
+ timezone: 'America/New_York',
118
+ attendee_mode: '1:1',
119
+ providerIds: ['provider_123'], // Optional: associate with providers
120
+ // Many more optional fields available for recurrence, scheduling windows, etc.
121
+ });
122
+ ```
123
+
124
+ #### Simple Offering Creation (Recommended for most use cases)
125
+
126
+ For most clients, the helper methods below provide a simpler way to create offerings without dealing with complex recurrence patterns and availability windows.
127
+
128
+ ##### Create a Simple Offering
129
+
130
+ Creates a basic 1:1 offering that uses provider availability schedules (no fixed times or recurrence):
131
+
132
+ ```typescript
133
+ const offering = await client.offerings.createSimple({
134
+ name: 'Therapy Session',
135
+ duration_minutes: 60,
136
+ price_cents: 15000, // $150.00
137
+ description: 'One-on-one therapy session',
138
+ timezone: 'America/New_York', // Optional, defaults to organization timezone
139
+ providerIds: ['provider_123'], // Optional: associate with providers
140
+ });
141
+ ```
142
+
143
+ ##### Create a Weekly Recurring Offering
144
+
145
+ Creates a weekly recurring offering with specific days and time slots:
146
+
147
+ ```typescript
148
+ const offering = await client.offerings.createRecurringWeekly({
149
+ name: 'Weekly Therapy',
150
+ duration_minutes: 60,
151
+ days: ['monday', 'wednesday', 'friday'], // Can also use ['MO', 'WE', 'FR']
152
+ timeSlots: [
153
+ { start: '09:00', end: '12:00' },
154
+ { start: '14:00', end: '17:00' }
155
+ ],
156
+ price_cents: 15000,
157
+ description: 'Weekly therapy sessions',
158
+ timezone: 'America/New_York',
159
+ providerIds: ['provider_123'],
160
+ });
161
+ ```
162
+
163
+ ##### Create a Daily Recurring Offering
164
+
165
+ Creates a daily recurring offering with time slots:
166
+
167
+ ```typescript
168
+ const offering = await client.offerings.createRecurringDaily({
169
+ name: 'Daily Consultation',
170
+ duration_minutes: 30,
171
+ timeSlots: [
172
+ { start: '09:00', end: '12:00' },
173
+ { start: '14:00', end: '17:00' }
174
+ ],
175
+ price_cents: 5000,
176
+ description: 'Daily consultation slots',
177
+ timezone: 'America/New_York',
178
+ providerIds: ['provider_123'],
179
+ });
180
+ ```
181
+
182
+ **When to use helper methods vs. full API:**
183
+ - Use `createSimple()` for basic offerings that rely on provider availability schedules
184
+ - Use `createRecurringWeekly()` or `createRecurringDaily()` for recurring offerings with fixed time slots
185
+ - Use `create()` directly when you need advanced features like custom recurrence intervals, monthly/yearly patterns, windowed modes, or other complex configurations
186
+
187
+ ### Customers
188
+
189
+ #### List customers
190
+
191
+ ```typescript
192
+ const customers = await client.customers.list({
193
+ q: 'john@example.com', // Optional: search by name/email/phone
194
+ providerId: 'provider_123', // Optional: filter by provider
195
+ page: 1,
196
+ pageSize: 50,
197
+ });
198
+ ```
199
+
200
+ #### Get a customer
201
+
202
+ ```typescript
203
+ const customer = await client.customers.get('customer_123');
204
+ ```
205
+
206
+ #### Create a customer
207
+
208
+ ```typescript
209
+ const customer = await client.customers.create({
210
+ name: 'John Doe',
211
+ email: 'john@example.com',
212
+ phone: '+1234567890', // Optional
213
+ userId: 'user_123', // Optional: link to internal user
214
+ });
215
+ ```
216
+
217
+ Note: If a customer with the same email already exists, they will be merged/updated.
218
+
219
+ #### Get customer history
220
+
221
+ ```typescript
222
+ const history = await client.customers.getHistory('customer_123');
223
+ // Returns analytics, booking history, favorite providers, etc.
224
+ ```
225
+
226
+ ### Providers
227
+
228
+ #### List providers
229
+
230
+ ```typescript
231
+ const providers = await client.providers.list({
232
+ query: 'Dr. Smith', // Optional: search term
233
+ page: 1,
234
+ pageSize: 20,
235
+ });
236
+ ```
237
+
238
+ #### Get a provider
239
+
240
+ ```typescript
241
+ const provider = await client.providers.get('provider_123');
242
+ ```
243
+
244
+ #### Create a provider
245
+
246
+ ```typescript
247
+ const provider = await client.providers.create({
248
+ name: 'Dr. Jane Smith',
249
+ email: 'jane@example.com',
250
+ phone: '+1234567890', // Optional
251
+ bio: 'Licensed therapist with 10 years of experience', // Optional
252
+ userId: 'user_123', // Optional: link to internal user
253
+ });
254
+ ```
255
+
256
+ ### Calendar
257
+
258
+ #### Get calendar events
259
+
260
+ ```typescript
261
+ const events = await client.calendar.getEvents({
262
+ providerId: 'provider_123', // Optional
263
+ start: '2024-01-01T00:00:00Z', // Optional: start date
264
+ end: '2024-01-31T23:59:59Z', // Optional: end date
265
+ });
266
+ // Returns both bookings and events combined
267
+ ```
268
+
269
+ ### Analytics
270
+
271
+ #### Get revenue analytics
272
+
273
+ ```typescript
274
+ const revenue = await client.analytics.getRevenue({
275
+ providerId: 'provider_123', // Optional
276
+ startDate: '2024-01-01T00:00:00Z', // Optional
277
+ endDate: '2024-01-31T23:59:59Z', // Optional
278
+ groupBy: 'day', // Optional: 'day' | 'week' | 'month' | 'offering' | 'provider'
279
+ });
280
+ ```
281
+
282
+ #### Get payouts
283
+
284
+ ```typescript
285
+ const payouts = await client.analytics.getPayouts({
286
+ providerId: 'provider_123', // Optional
287
+ startDate: '2024-01-01T00:00:00Z', // Optional
288
+ endDate: '2024-01-31T23:59:59Z', // Optional
289
+ customerId: 'customer_123', // Optional
290
+ });
291
+ ```
292
+
293
+ ### Availability
294
+
295
+ #### Get available slots
296
+
297
+ ```typescript
298
+ // Enhanced version with offeringId and limit support
299
+ const availability = await client.availability.getSlots({
300
+ providerId: 'provider_123', // Optional if offeringId provided
301
+ offeringId: 'offering_123', // Optional
302
+ start: '2024-01-15T00:00:00Z',
303
+ end: '2024-01-22T23:59:59Z',
304
+ limit: 50, // Optional: max number of slots
305
+ });
306
+
307
+ // Or use the original format for backward compatibility
308
+ const availability2 = await client.availability.getSlots({
309
+ providerId: 'provider_123',
310
+ startDate: '2024-01-15T00:00:00Z',
311
+ endDate: '2024-01-22T23:59:59Z',
312
+ });
313
+ ```
314
+
315
+ #### Get availability schedules
316
+
317
+ ```typescript
318
+ const schedules = await client.availability.getSchedules({
319
+ providerId: 'provider_123', // Optional
320
+ });
321
+ ```
322
+
323
+ #### Check specific time availability
324
+
325
+ ```typescript
326
+ const isAvailable = await client.availability.check({
327
+ providerId: 'provider_123',
328
+ startTime: '2024-01-15T10:00:00Z',
329
+ duration: 30, // minutes
330
+ });
331
+ ```
332
+
333
+ ## Error Handling
334
+
335
+ The SDK throws typed errors for different scenarios:
336
+
337
+ ```typescript
338
+ import {
339
+ AevumError,
340
+ AevumAPIError,
341
+ AevumAuthenticationError,
342
+ AevumValidationError,
343
+ AevumNotFoundError,
344
+ } from '@aevum/sdk';
345
+
346
+ try {
347
+ const booking = await client.bookings.get('invalid_id');
348
+ } catch (error) {
349
+ if (error instanceof AevumNotFoundError) {
350
+ console.log('Booking not found');
351
+ } else if (error instanceof AevumAuthenticationError) {
352
+ console.log('Invalid API key');
353
+ } else if (error instanceof AevumValidationError) {
354
+ console.log('Validation error:', error.issues);
355
+ } else if (error instanceof AevumAPIError) {
356
+ console.log('API error:', error.message, error.status);
357
+ }
358
+ }
359
+ ```
360
+
361
+ ## TypeScript Support
362
+
363
+ The SDK is fully typed with TypeScript. All methods include type definitions for parameters and return values, providing autocomplete and type checking.
364
+
365
+ All types are exported for your convenience:
366
+
367
+ ```typescript
368
+ import type {
369
+ Booking,
370
+ Offering,
371
+ Customer,
372
+ Provider,
373
+ CalendarEvent,
374
+ RevenueResponse,
375
+ PayoutsResponse,
376
+ // ... and many more
377
+ } from '@aevum/sdk';
378
+ ```
379
+
380
+ ## Migration Guide (from Custom Client)
381
+
382
+ If you're migrating from a custom Aevum client implementation (like mendbloom's), here's how to update:
383
+
384
+ ### Before (Custom Client)
385
+
386
+ ```typescript
387
+ import { AevumClient } from '@/lib/aevum/client';
388
+
389
+ const client = new AevumClient(apiKey, orgId);
390
+ const offerings = await client.getOfferings({ eventId: 'event_123' });
391
+ ```
392
+
393
+ ### After (SDK)
394
+
395
+ ```typescript
396
+ import { AevumClient } from '@aevum/sdk';
397
+
398
+ const client = new AevumClient({ apiKey });
399
+ const offerings = await client.offerings.list({ eventId: 'event_123' });
400
+ ```
401
+
402
+ ### Key Changes
403
+
404
+ 1. **Installation**: `npm install @aevum/sdk`
405
+ 2. **Initialization**: No need to pass `orgId` - it's resolved automatically
406
+ 3. **Method Names**: Use namespaced methods (e.g., `client.offerings.list()` instead of `client.getOfferings()`)
407
+ 4. **Error Handling**: Use SDK error classes instead of generic errors
408
+ 5. **Types**: Import types from SDK instead of defining your own
409
+
410
+ ### Method Mapping
411
+
412
+ | Custom Client | SDK |
413
+ |--------------|-----|
414
+ | `client.getOfferings()` | `client.offerings.list()` |
415
+ | `client.getOffering(id)` | `client.offerings.get(id)` |
416
+ | `client.createOffering()` | `client.offerings.create()` |
417
+ | `client.getCustomers()` | `client.customers.list()` |
418
+ | `client.getCustomer(id)` | `client.customers.get(id)` |
419
+ | `client.createCustomer()` | `client.customers.create()` |
420
+ | `client.getProviders()` | `client.providers.list()` |
421
+ | `client.createProvider()` | `client.providers.create()` |
422
+ | `client.getCalendarEvents()` | `client.calendar.getEvents()` |
423
+ | `client.getRevenue()` | `client.analytics.getRevenue()` |
424
+ | `client.getPayouts()` | `client.analytics.getPayouts()` |
425
+ | `client.getAvailabilitySchedules()` | `client.availability.getSchedules()` |
426
+ | `client.getAvailabilitySlots()` | `client.availability.getSlots()` |
427
+ | `client.rescheduleBooking()` | `client.bookings.reschedule()` |
428
+
429
+ ## Requirements
430
+
431
+ - Node.js 18+ or modern browser with fetch support
432
+ - Valid Aevum API key
433
+
434
+ ## License
435
+
436
+ 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
+ }
@@ -0,0 +1,23 @@
1
+ import { AevumClient } from './client';
2
+ import type { GetSlotsParams, GetSlotsResponse, CheckAvailabilityParams, CheckAvailabilityResponse, GetAvailabilitySchedulesParams, AvailabilitySchedule, GetAvailabilitySlotsParams } from './types';
3
+ /**
4
+ * Availability API methods
5
+ */
6
+ export declare class AvailabilityAPI {
7
+ private client;
8
+ constructor(client: AevumClient);
9
+ /**
10
+ * Get available time slots for a provider within a date range
11
+ * Enhanced version that supports offeringId and limit
12
+ */
13
+ getSlots(params: GetSlotsParams | GetAvailabilitySlotsParams): Promise<GetSlotsResponse>;
14
+ /**
15
+ * Get availability schedules
16
+ */
17
+ getSchedules(params?: GetAvailabilitySchedulesParams): Promise<AvailabilitySchedule[]>;
18
+ /**
19
+ * Check if a specific time slot is available
20
+ * This is a client-side implementation that uses getSlots()
21
+ */
22
+ check(params: CheckAvailabilityParams): Promise<CheckAvailabilityResponse>;
23
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Availability API methods
3
+ */
4
+ export class AvailabilityAPI {
5
+ constructor(client) {
6
+ this.client = client;
7
+ }
8
+ /**
9
+ * Get available time slots for a provider within a date range
10
+ * Enhanced version that supports offeringId and limit
11
+ */
12
+ async getSlots(params) {
13
+ const query = {};
14
+ // Support both old and new parameter formats
15
+ if ('providerId' in params && params.providerId) {
16
+ query.providerId = params.providerId;
17
+ }
18
+ if ('offeringId' in params && params.offeringId) {
19
+ query.offeringId = params.offeringId;
20
+ }
21
+ if ('start' in params && params.start) {
22
+ query.start = params.start;
23
+ }
24
+ else if ('startDate' in params && params.startDate) {
25
+ query.start = params.startDate;
26
+ }
27
+ if ('end' in params && params.end) {
28
+ query.end = params.end;
29
+ }
30
+ else if ('endDate' in params && params.endDate) {
31
+ query.end = params.endDate;
32
+ }
33
+ if ('limit' in params && params.limit !== undefined) {
34
+ query.limit = params.limit;
35
+ }
36
+ // For backward compatibility with GetSlotsParams
37
+ if ('startDate' in params && 'endDate' in params) {
38
+ if (!params.startDate || !params.endDate) {
39
+ throw new Error('startDate and endDate are required');
40
+ }
41
+ }
42
+ else if (!query.start || !query.end) {
43
+ throw new Error('start/startDate and end/endDate are required');
44
+ }
45
+ try {
46
+ return await this.client.request('GET', '/api/v1/orgs/{orgId}/availability/slots', { query });
47
+ }
48
+ catch (error) {
49
+ // Handle 404 gracefully - endpoint might not exist yet
50
+ if (error?.status === 404 || error?.message?.includes('404')) {
51
+ console.warn('Availability slots endpoint not found, returning empty slots');
52
+ return { slots: [] };
53
+ }
54
+ throw error;
55
+ }
56
+ }
57
+ /**
58
+ * Get availability schedules
59
+ */
60
+ async getSchedules(params) {
61
+ const query = {};
62
+ if (params?.providerId) {
63
+ query.providerId = params.providerId;
64
+ }
65
+ try {
66
+ const response = await this.client.request('GET', '/api/v1/orgs/{orgId}/availability/schedules', { query });
67
+ return response || [];
68
+ }
69
+ catch (error) {
70
+ // Handle 404 gracefully - endpoint might not exist yet
71
+ if (error?.status === 404 || error?.message?.includes('404')) {
72
+ console.warn('Availability schedules endpoint not found, returning empty array');
73
+ return [];
74
+ }
75
+ throw error;
76
+ }
77
+ }
78
+ /**
79
+ * Check if a specific time slot is available
80
+ * This is a client-side implementation that uses getSlots()
81
+ */
82
+ async check(params) {
83
+ const { providerId, startTime, duration } = params;
84
+ // Parse start time
85
+ const start = new Date(startTime);
86
+ if (isNaN(start.getTime())) {
87
+ throw new Error('Invalid startTime format. Expected ISO 8601 datetime with timezone');
88
+ }
89
+ // Calculate end time
90
+ const end = new Date(start.getTime() + duration * 60 * 1000);
91
+ // Get slots for a window around the requested time (1 day before and after)
92
+ const windowStart = new Date(start.getTime() - 24 * 60 * 60 * 1000);
93
+ const windowEnd = new Date(end.getTime() + 24 * 60 * 60 * 1000);
94
+ // Format as ISO strings with timezone
95
+ const startDate = windowStart.toISOString();
96
+ const endDate = windowEnd.toISOString();
97
+ // Get available slots
98
+ const { slots } = await this.getSlots({
99
+ providerId,
100
+ startDate,
101
+ endDate,
102
+ });
103
+ // Check if requested time falls within any available slot
104
+ const requestedStart = start.getTime();
105
+ const requestedEnd = end.getTime();
106
+ const isAvailable = slots.some((slot) => {
107
+ const slotStart = new Date(slot.start_time_utc).getTime();
108
+ const slotEnd = new Date(slot.end_time_utc).getTime();
109
+ // Check if requested time is completely within the slot
110
+ return requestedStart >= slotStart && requestedEnd <= slotEnd;
111
+ });
112
+ return { available: isAvailable };
113
+ }
114
+ }
@@ -0,0 +1,29 @@
1
+ import { AevumClient } from './client';
2
+ import type { Booking, CreateBookingParams, ListBookingsParams, ListBookingsResponse, RescheduleBookingParams } from './types';
3
+ /**
4
+ * Bookings API methods
5
+ */
6
+ export declare class BookingsAPI {
7
+ private client;
8
+ constructor(client: AevumClient);
9
+ /**
10
+ * Create a new booking
11
+ */
12
+ create(params: CreateBookingParams): Promise<Booking>;
13
+ /**
14
+ * Get a booking by ID
15
+ */
16
+ get(bookingId: string): Promise<Booking>;
17
+ /**
18
+ * List bookings with optional filters
19
+ */
20
+ list(params?: ListBookingsParams): Promise<ListBookingsResponse>;
21
+ /**
22
+ * Cancel a booking
23
+ */
24
+ cancel(bookingId: string, reason?: string): Promise<Booking>;
25
+ /**
26
+ * Reschedule a booking
27
+ */
28
+ reschedule(bookingId: string, params: RescheduleBookingParams): Promise<Booking>;
29
+ }