@slotchain/sdk 1.1.4 → 1.2.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/dist/index.d.mts CHANGED
@@ -170,12 +170,93 @@ interface Slot {
170
170
  created_at: string;
171
171
  updated_at: string;
172
172
  }
173
+ /**
174
+ * Customer record — matches the `customers` table.
175
+ */
173
176
  interface Customer {
174
177
  id: string;
178
+ tenant_id: string;
179
+ customer_type: 'individual' | 'organization';
180
+ name: string;
181
+ email: string;
182
+ phone?: string;
183
+ address?: string;
184
+ city?: string;
185
+ state?: string;
186
+ zip_code?: string;
187
+ is_guest?: boolean;
188
+ metadata?: Record<string, unknown>;
189
+ created_at: string;
190
+ updated_at: string;
191
+ }
192
+ /**
193
+ * A row in `customer_users` — links an IDP user (Clerk userId, Auth0 sub, etc.) to a Customer.
194
+ */
195
+ interface CustomerIdentity {
196
+ id: string;
197
+ customer_id: string;
198
+ idp_id: string;
199
+ role: 'owner' | 'admin' | 'member';
200
+ is_primary: boolean;
201
+ created_at: string;
202
+ updated_at: string;
203
+ }
204
+ /**
205
+ * Customer with their associated IDP identities (from `customer_users` join).
206
+ */
207
+ interface CustomerWithIdentities extends Customer {
208
+ identities?: CustomerIdentity[];
209
+ }
210
+ /**
211
+ * Notification preferences stored in `customer.metadata.notification_preferences`.
212
+ */
213
+ interface NotificationPreferences {
214
+ email?: boolean;
215
+ sms?: boolean;
216
+ push?: boolean;
217
+ booking_confirmation?: boolean;
218
+ booking_reminder?: boolean;
219
+ booking_cancellation?: boolean;
220
+ marketing?: boolean;
221
+ [key: string]: boolean | undefined;
222
+ }
223
+ /**
224
+ * Customer with their bookings, as returned by GET /api/v1/customers/bookings.
225
+ */
226
+ interface CustomerWithBookings {
227
+ customer: Customer;
228
+ bookings: Booking[];
229
+ /** Bookings organised by slot ID → array of bookings */
230
+ groupedBySlot: Record<string, Booking[]>;
231
+ total: number;
232
+ total_slots: number;
233
+ }
234
+ /**
235
+ * Options for resolving a customer from an IDP identity or email.
236
+ * At least one of `idpId` or `email` must be provided.
237
+ */
238
+ interface ResolveCustomerOptions {
175
239
  tenantId: string;
240
+ /** IDP user ID (Clerk userId, Auth0 sub, etc.) — checked first */
241
+ idpId?: string;
242
+ /** Email address — used as fallback if idpId lookup returns nothing */
176
243
  email?: string;
244
+ }
245
+ /**
246
+ * Options for atomic customer upsert (find or create by email within a tenant).
247
+ */
248
+ interface FindOrCreateCustomerOptions {
249
+ tenant_id: string;
250
+ email: string;
177
251
  name?: string;
178
252
  phone?: string;
253
+ address?: string;
254
+ city?: string;
255
+ state?: string;
256
+ zip_code?: string;
257
+ customer_type?: 'individual' | 'organization';
258
+ is_guest?: boolean;
259
+ metadata?: Record<string, unknown>;
179
260
  }
180
261
  interface Flow {
181
262
  id: string;
@@ -237,6 +318,63 @@ interface GetOrganizationOptions {
237
318
  limit?: number;
238
319
  is_public?: boolean;
239
320
  }
321
+ /**
322
+ * Artifact / document attached to a customer or booking
323
+ */
324
+ type ArtifactEntityType = 'customer' | 'booking' | 'slot' | 'service' | 'tenant';
325
+ type ArtifactMimeCategory = 'pdf' | 'document' | 'image' | 'spreadsheet' | 'video' | 'audio' | 'other';
326
+ interface Artifact {
327
+ id: string;
328
+ tenant_id: string;
329
+ /** The Slotly entity this file is attached to */
330
+ related_entity_type: ArtifactEntityType;
331
+ related_entity_id: string;
332
+ /** Original filename supplied by the uploader */
333
+ original_filename: string;
334
+ /** Storage path within the tenant bucket (opaque — use url/signed_url to access) */
335
+ storage_path: string;
336
+ /** MIME category, derived server-side */
337
+ mime_category: ArtifactMimeCategory;
338
+ mime_type?: string;
339
+ size_bytes?: number;
340
+ /** Optional label, e.g. "CV", "Invoice", "Contract" */
341
+ label?: string;
342
+ metadata?: Record<string, unknown>;
343
+ uploaded_by_user_id?: string;
344
+ created_at: string;
345
+ updated_at: string;
346
+ }
347
+ /**
348
+ * Artifact with a short-lived signed download URL (returned from getUrl / list with signed=true)
349
+ */
350
+ interface ArtifactWithUrl extends Artifact {
351
+ signed_url: string;
352
+ /** Unix timestamp (seconds) when the signed_url expires */
353
+ signed_url_expires_at: number;
354
+ }
355
+ interface ListArtifactsOptions {
356
+ related_entity_type?: ArtifactEntityType;
357
+ related_entity_id?: string;
358
+ /** Include signed download URLs in each result (adds latency) */
359
+ signed?: boolean;
360
+ mime_category?: ArtifactMimeCategory;
361
+ label?: string;
362
+ page?: number;
363
+ limit?: number;
364
+ }
365
+ interface UploadArtifactOptions {
366
+ /** The file binary */
367
+ file: Blob | Buffer | ArrayBuffer;
368
+ /** Original filename */
369
+ filename: string;
370
+ /** The entity this artifact belongs to */
371
+ related_entity_type: ArtifactEntityType;
372
+ related_entity_id: string;
373
+ /** Optional label for the UI, e.g. "CV", "Invoice" */
374
+ label?: string;
375
+ mime_type?: string;
376
+ metadata?: Record<string, unknown>;
377
+ }
240
378
  /**
241
379
  * Full tenant configuration including branding, services, and service items
242
380
  * Service items are nested within each service object (not as a separate top-level array)
@@ -837,11 +975,12 @@ declare class CustomerClient {
837
975
  /**
838
976
  * Create a new customer
839
977
  * POST /api/v1/customers
840
- *
841
- * @param data - Customer creation data (tenant_id, name, email required)
842
- * @returns Created customer
843
978
  */
844
- create(data: Partial<Customer>): Promise<ApiResponse<Customer>>;
979
+ create(data: Partial<Customer> & {
980
+ tenant_id: string;
981
+ name: string;
982
+ email: string;
983
+ }): Promise<ApiResponse<Customer>>;
845
984
  /**
846
985
  * Update customer by ID
847
986
  * PUT /api/v1/customers/:id
@@ -871,30 +1010,67 @@ declare class CustomerClient {
871
1010
  tenantId: string;
872
1011
  }): Promise<ApiResponse<Customer | null>>;
873
1012
  /**
874
- * Get autocomplete data from existing customers and bookings
875
- * GET /api/v1/customers/autocomplete
876
- *
877
- * @param tenantId - Tenant ID (required)
878
- * @returns Autocomplete data
1013
+ * Get autocomplete data from existing customers and bookings.
1014
+ * GET /api/v1/customers/autocomplete?tenantId=:tenantId
879
1015
  */
880
- autocomplete(tenantId: string): Promise<ApiResponse<any>>;
1016
+ autocomplete(tenantId: string): Promise<ApiResponse<{
1017
+ companies: string[];
1018
+ jobTitles: string[];
1019
+ experienceLevels: string[];
1020
+ cities: string[];
1021
+ states: string[];
1022
+ zipCodes: string[];
1023
+ }>>;
881
1024
  /**
882
- * Get all bookings for a customer
883
- * GET /api/v1/customers/bookings
884
- *
885
- * @param params - Query parameters (email optional, userId optional, tenantId required)
886
- * @returns Customer bookings data
1025
+ * Get all bookings for a customer, grouped by slot.
1026
+ * GET /api/v1/customers/bookings?tenantId=:id
887
1027
  */
888
1028
  getBookings(params: {
889
1029
  email?: string;
890
1030
  userId?: string;
891
1031
  tenantId: string;
892
- }): Promise<ApiResponse<{
893
- customer: Customer | null;
894
- bookings: Booking[];
895
- groupedBySlot: Record<string, Booking[]>;
896
- total: number;
1032
+ }): Promise<ApiResponse<CustomerWithBookings>>;
1033
+ /**
1034
+ * Atomic upsert: find an existing customer by email within a tenant, or create one.
1035
+ * POST /api/v1/customers/find-or-create
1036
+ */
1037
+ findOrCreate(options: FindOrCreateCustomerOptions): Promise<ApiResponse<Customer & {
1038
+ created: boolean;
897
1039
  }>>;
1040
+ /**
1041
+ * Resolve a customer from an IDP identity or email.
1042
+ * Tries idpId lookup (customer_users) first, then falls back to email.
1043
+ * POST /api/v1/customers/resolve
1044
+ */
1045
+ resolve(options: ResolveCustomerOptions): Promise<ApiResponse<Customer | null>>;
1046
+ /**
1047
+ * Get a customer with their linked IDP identities (customer_users rows).
1048
+ * GET /api/v1/customers/:id?include_identities=true
1049
+ */
1050
+ getWithIdentities(id: string): Promise<ApiResponse<CustomerWithIdentities>>;
1051
+ /**
1052
+ * Link an IDP user ID to a customer (creates a customer_users row).
1053
+ * POST /api/v1/customers/:id/users
1054
+ */
1055
+ linkUser(customerId: string, idpId: string, options?: {
1056
+ role?: CustomerIdentity['role'];
1057
+ is_primary?: boolean;
1058
+ }): Promise<ApiResponse<CustomerIdentity>>;
1059
+ /**
1060
+ * Unlink an IDP user from a customer (deletes the customer_users row).
1061
+ * DELETE /api/v1/customers/:id/users/:idpId
1062
+ */
1063
+ unlinkUser(customerId: string, idpId: string): Promise<ApiResponse<void>>;
1064
+ /**
1065
+ * Get notification preferences for a customer.
1066
+ * GET /api/v1/customers/:id/preferences/notifications
1067
+ */
1068
+ getNotificationPreferences(customerId: string): Promise<ApiResponse<NotificationPreferences>>;
1069
+ /**
1070
+ * Update notification preferences for a customer (partial merge).
1071
+ * PATCH /api/v1/customers/:id/preferences/notifications
1072
+ */
1073
+ updateNotificationPreferences(customerId: string, preferences: Partial<NotificationPreferences>): Promise<ApiResponse<NotificationPreferences>>;
898
1074
  }
899
1075
 
900
1076
  declare class FlowClient {
@@ -1185,6 +1361,68 @@ declare class OrganizationClient {
1185
1361
  getBySlug(slug: string, options?: GetOrganizationOptions): Promise<ApiResponse<Organization | OrganizationFullConfig>>;
1186
1362
  }
1187
1363
 
1364
+ /**
1365
+ * DocumentClient — manage file artifacts attached to Slotly entities.
1366
+ *
1367
+ * Artifacts are tenant-scoped files (CVs, invoices, images, etc.) linked
1368
+ * to a customer, booking, slot, service, or tenant record.
1369
+ *
1370
+ * @example Upload a CV for a customer
1371
+ * ```ts
1372
+ * const artifact = await slotly.document.upload({
1373
+ * file: buffer,
1374
+ * filename: 'cv-2024.pdf',
1375
+ * related_entity_type: 'customer',
1376
+ * related_entity_id: customerId,
1377
+ * label: 'CV',
1378
+ * });
1379
+ * ```
1380
+ *
1381
+ * @example List all CVs for a customer
1382
+ * ```ts
1383
+ * const { data } = await slotly.document.listByEntity('customer', customerId, { signed: true });
1384
+ * ```
1385
+ */
1386
+ declare class DocumentClient {
1387
+ private readonly client;
1388
+ private readonly base;
1389
+ constructor(client: AxiosInstance);
1390
+ /**
1391
+ * Upload a file artifact.
1392
+ * Sends as multipart/form-data.
1393
+ */
1394
+ upload(options: UploadArtifactOptions): Promise<Artifact>;
1395
+ /**
1396
+ * List artifacts for a specific entity.
1397
+ * Pass `signed: true` to get download URLs in each result.
1398
+ */
1399
+ listByEntity(entityType: ArtifactEntityType, entityId: string, options?: Omit<ListArtifactsOptions, 'related_entity_type' | 'related_entity_id'>): Promise<ApiResponse<(Artifact | ArtifactWithUrl)[]>>;
1400
+ /**
1401
+ * List artifacts with full filter options.
1402
+ */
1403
+ list(options: ListArtifactsOptions): Promise<ApiResponse<(Artifact | ArtifactWithUrl)[]>>;
1404
+ /**
1405
+ * Get a single artifact by ID.
1406
+ */
1407
+ get(id: string, signed?: boolean): Promise<Artifact | ArtifactWithUrl>;
1408
+ /**
1409
+ * Get a signed download URL for an artifact.
1410
+ * Returns the full ArtifactWithUrl including `signed_url` and `signed_url_expires_at`.
1411
+ */
1412
+ getUrl(id: string): Promise<ArtifactWithUrl>;
1413
+ /**
1414
+ * Delete an artifact and its stored file.
1415
+ */
1416
+ delete(id: string): Promise<void>;
1417
+ /**
1418
+ * Update artifact label or metadata.
1419
+ */
1420
+ update(id: string, patch: {
1421
+ label?: string;
1422
+ metadata?: Record<string, unknown>;
1423
+ }): Promise<Artifact>;
1424
+ }
1425
+
1188
1426
  /**
1189
1427
  * Custom error classes for Slotly SDK
1190
1428
  */
@@ -1347,6 +1585,8 @@ interface SlotlyApi {
1347
1585
  notification: NotificationClient;
1348
1586
  dataQuality: DataQualityClient;
1349
1587
  organization: OrganizationClient;
1588
+ /** Upload and retrieve file artifacts (CVs, invoices, images) linked to any Slotly entity */
1589
+ document: DocumentClient;
1350
1590
  }
1351
1591
  /**
1352
1592
  * Initialize and configure a new Slotly API client with dual authentication.
@@ -1411,4 +1651,4 @@ interface SlotlyApi {
1411
1651
  */
1412
1652
  declare const useSlotly: (options: SlotlyClientOptions) => SlotlyApi;
1413
1653
 
1414
- export { type ApiResponse, type Booking, type BookingWithSlot, type Category, type Customer, type DataQualityIssue, type Flow, type FlowStep, type GetOrganizationOptions, type ListBookingsOptions, type Notification, type Organization, type OrganizationFullConfig, type Service, type ServiceItem, type ServiceItemWithService, type ServiceWithItems, type Slot, type SlotServiceWithItems, type SlotlyApi, SlotlyApiError, type SlotlyAuthContext, SlotlyAuthError, type SlotlyClientOptions, SlotlyConfigurationError, SlotlyNetworkError, type SlotlyRequest, type Studio, type Tenant, type TenantBranding, type TenantFullConfig, useSlotly as default, getSlotlyContext, useSlotly, validateSlotlyRequest };
1654
+ export { type ApiResponse, type Artifact, type ArtifactEntityType, type ArtifactMimeCategory, type ArtifactWithUrl, type Booking, type BookingWithSlot, type Category, type Customer, type CustomerIdentity, type CustomerWithBookings, type CustomerWithIdentities, type DataQualityIssue, type FindOrCreateCustomerOptions, type Flow, type FlowStep, type GetOrganizationOptions, type ListArtifactsOptions, type ListBookingsOptions, type Notification, type NotificationPreferences, type Organization, type OrganizationFullConfig, type ResolveCustomerOptions, type Service, type ServiceItem, type ServiceItemWithService, type ServiceWithItems, type Slot, type SlotServiceWithItems, type SlotlyApi, SlotlyApiError, type SlotlyAuthContext, SlotlyAuthError, type SlotlyClientOptions, SlotlyConfigurationError, SlotlyNetworkError, type SlotlyRequest, type Studio, type Tenant, type TenantBranding, type TenantFullConfig, type UploadArtifactOptions, useSlotly as default, getSlotlyContext, useSlotly, validateSlotlyRequest };
package/dist/index.d.ts CHANGED
@@ -170,12 +170,93 @@ interface Slot {
170
170
  created_at: string;
171
171
  updated_at: string;
172
172
  }
173
+ /**
174
+ * Customer record — matches the `customers` table.
175
+ */
173
176
  interface Customer {
174
177
  id: string;
178
+ tenant_id: string;
179
+ customer_type: 'individual' | 'organization';
180
+ name: string;
181
+ email: string;
182
+ phone?: string;
183
+ address?: string;
184
+ city?: string;
185
+ state?: string;
186
+ zip_code?: string;
187
+ is_guest?: boolean;
188
+ metadata?: Record<string, unknown>;
189
+ created_at: string;
190
+ updated_at: string;
191
+ }
192
+ /**
193
+ * A row in `customer_users` — links an IDP user (Clerk userId, Auth0 sub, etc.) to a Customer.
194
+ */
195
+ interface CustomerIdentity {
196
+ id: string;
197
+ customer_id: string;
198
+ idp_id: string;
199
+ role: 'owner' | 'admin' | 'member';
200
+ is_primary: boolean;
201
+ created_at: string;
202
+ updated_at: string;
203
+ }
204
+ /**
205
+ * Customer with their associated IDP identities (from `customer_users` join).
206
+ */
207
+ interface CustomerWithIdentities extends Customer {
208
+ identities?: CustomerIdentity[];
209
+ }
210
+ /**
211
+ * Notification preferences stored in `customer.metadata.notification_preferences`.
212
+ */
213
+ interface NotificationPreferences {
214
+ email?: boolean;
215
+ sms?: boolean;
216
+ push?: boolean;
217
+ booking_confirmation?: boolean;
218
+ booking_reminder?: boolean;
219
+ booking_cancellation?: boolean;
220
+ marketing?: boolean;
221
+ [key: string]: boolean | undefined;
222
+ }
223
+ /**
224
+ * Customer with their bookings, as returned by GET /api/v1/customers/bookings.
225
+ */
226
+ interface CustomerWithBookings {
227
+ customer: Customer;
228
+ bookings: Booking[];
229
+ /** Bookings organised by slot ID → array of bookings */
230
+ groupedBySlot: Record<string, Booking[]>;
231
+ total: number;
232
+ total_slots: number;
233
+ }
234
+ /**
235
+ * Options for resolving a customer from an IDP identity or email.
236
+ * At least one of `idpId` or `email` must be provided.
237
+ */
238
+ interface ResolveCustomerOptions {
175
239
  tenantId: string;
240
+ /** IDP user ID (Clerk userId, Auth0 sub, etc.) — checked first */
241
+ idpId?: string;
242
+ /** Email address — used as fallback if idpId lookup returns nothing */
176
243
  email?: string;
244
+ }
245
+ /**
246
+ * Options for atomic customer upsert (find or create by email within a tenant).
247
+ */
248
+ interface FindOrCreateCustomerOptions {
249
+ tenant_id: string;
250
+ email: string;
177
251
  name?: string;
178
252
  phone?: string;
253
+ address?: string;
254
+ city?: string;
255
+ state?: string;
256
+ zip_code?: string;
257
+ customer_type?: 'individual' | 'organization';
258
+ is_guest?: boolean;
259
+ metadata?: Record<string, unknown>;
179
260
  }
180
261
  interface Flow {
181
262
  id: string;
@@ -237,6 +318,63 @@ interface GetOrganizationOptions {
237
318
  limit?: number;
238
319
  is_public?: boolean;
239
320
  }
321
+ /**
322
+ * Artifact / document attached to a customer or booking
323
+ */
324
+ type ArtifactEntityType = 'customer' | 'booking' | 'slot' | 'service' | 'tenant';
325
+ type ArtifactMimeCategory = 'pdf' | 'document' | 'image' | 'spreadsheet' | 'video' | 'audio' | 'other';
326
+ interface Artifact {
327
+ id: string;
328
+ tenant_id: string;
329
+ /** The Slotly entity this file is attached to */
330
+ related_entity_type: ArtifactEntityType;
331
+ related_entity_id: string;
332
+ /** Original filename supplied by the uploader */
333
+ original_filename: string;
334
+ /** Storage path within the tenant bucket (opaque — use url/signed_url to access) */
335
+ storage_path: string;
336
+ /** MIME category, derived server-side */
337
+ mime_category: ArtifactMimeCategory;
338
+ mime_type?: string;
339
+ size_bytes?: number;
340
+ /** Optional label, e.g. "CV", "Invoice", "Contract" */
341
+ label?: string;
342
+ metadata?: Record<string, unknown>;
343
+ uploaded_by_user_id?: string;
344
+ created_at: string;
345
+ updated_at: string;
346
+ }
347
+ /**
348
+ * Artifact with a short-lived signed download URL (returned from getUrl / list with signed=true)
349
+ */
350
+ interface ArtifactWithUrl extends Artifact {
351
+ signed_url: string;
352
+ /** Unix timestamp (seconds) when the signed_url expires */
353
+ signed_url_expires_at: number;
354
+ }
355
+ interface ListArtifactsOptions {
356
+ related_entity_type?: ArtifactEntityType;
357
+ related_entity_id?: string;
358
+ /** Include signed download URLs in each result (adds latency) */
359
+ signed?: boolean;
360
+ mime_category?: ArtifactMimeCategory;
361
+ label?: string;
362
+ page?: number;
363
+ limit?: number;
364
+ }
365
+ interface UploadArtifactOptions {
366
+ /** The file binary */
367
+ file: Blob | Buffer | ArrayBuffer;
368
+ /** Original filename */
369
+ filename: string;
370
+ /** The entity this artifact belongs to */
371
+ related_entity_type: ArtifactEntityType;
372
+ related_entity_id: string;
373
+ /** Optional label for the UI, e.g. "CV", "Invoice" */
374
+ label?: string;
375
+ mime_type?: string;
376
+ metadata?: Record<string, unknown>;
377
+ }
240
378
  /**
241
379
  * Full tenant configuration including branding, services, and service items
242
380
  * Service items are nested within each service object (not as a separate top-level array)
@@ -837,11 +975,12 @@ declare class CustomerClient {
837
975
  /**
838
976
  * Create a new customer
839
977
  * POST /api/v1/customers
840
- *
841
- * @param data - Customer creation data (tenant_id, name, email required)
842
- * @returns Created customer
843
978
  */
844
- create(data: Partial<Customer>): Promise<ApiResponse<Customer>>;
979
+ create(data: Partial<Customer> & {
980
+ tenant_id: string;
981
+ name: string;
982
+ email: string;
983
+ }): Promise<ApiResponse<Customer>>;
845
984
  /**
846
985
  * Update customer by ID
847
986
  * PUT /api/v1/customers/:id
@@ -871,30 +1010,67 @@ declare class CustomerClient {
871
1010
  tenantId: string;
872
1011
  }): Promise<ApiResponse<Customer | null>>;
873
1012
  /**
874
- * Get autocomplete data from existing customers and bookings
875
- * GET /api/v1/customers/autocomplete
876
- *
877
- * @param tenantId - Tenant ID (required)
878
- * @returns Autocomplete data
1013
+ * Get autocomplete data from existing customers and bookings.
1014
+ * GET /api/v1/customers/autocomplete?tenantId=:tenantId
879
1015
  */
880
- autocomplete(tenantId: string): Promise<ApiResponse<any>>;
1016
+ autocomplete(tenantId: string): Promise<ApiResponse<{
1017
+ companies: string[];
1018
+ jobTitles: string[];
1019
+ experienceLevels: string[];
1020
+ cities: string[];
1021
+ states: string[];
1022
+ zipCodes: string[];
1023
+ }>>;
881
1024
  /**
882
- * Get all bookings for a customer
883
- * GET /api/v1/customers/bookings
884
- *
885
- * @param params - Query parameters (email optional, userId optional, tenantId required)
886
- * @returns Customer bookings data
1025
+ * Get all bookings for a customer, grouped by slot.
1026
+ * GET /api/v1/customers/bookings?tenantId=:id
887
1027
  */
888
1028
  getBookings(params: {
889
1029
  email?: string;
890
1030
  userId?: string;
891
1031
  tenantId: string;
892
- }): Promise<ApiResponse<{
893
- customer: Customer | null;
894
- bookings: Booking[];
895
- groupedBySlot: Record<string, Booking[]>;
896
- total: number;
1032
+ }): Promise<ApiResponse<CustomerWithBookings>>;
1033
+ /**
1034
+ * Atomic upsert: find an existing customer by email within a tenant, or create one.
1035
+ * POST /api/v1/customers/find-or-create
1036
+ */
1037
+ findOrCreate(options: FindOrCreateCustomerOptions): Promise<ApiResponse<Customer & {
1038
+ created: boolean;
897
1039
  }>>;
1040
+ /**
1041
+ * Resolve a customer from an IDP identity or email.
1042
+ * Tries idpId lookup (customer_users) first, then falls back to email.
1043
+ * POST /api/v1/customers/resolve
1044
+ */
1045
+ resolve(options: ResolveCustomerOptions): Promise<ApiResponse<Customer | null>>;
1046
+ /**
1047
+ * Get a customer with their linked IDP identities (customer_users rows).
1048
+ * GET /api/v1/customers/:id?include_identities=true
1049
+ */
1050
+ getWithIdentities(id: string): Promise<ApiResponse<CustomerWithIdentities>>;
1051
+ /**
1052
+ * Link an IDP user ID to a customer (creates a customer_users row).
1053
+ * POST /api/v1/customers/:id/users
1054
+ */
1055
+ linkUser(customerId: string, idpId: string, options?: {
1056
+ role?: CustomerIdentity['role'];
1057
+ is_primary?: boolean;
1058
+ }): Promise<ApiResponse<CustomerIdentity>>;
1059
+ /**
1060
+ * Unlink an IDP user from a customer (deletes the customer_users row).
1061
+ * DELETE /api/v1/customers/:id/users/:idpId
1062
+ */
1063
+ unlinkUser(customerId: string, idpId: string): Promise<ApiResponse<void>>;
1064
+ /**
1065
+ * Get notification preferences for a customer.
1066
+ * GET /api/v1/customers/:id/preferences/notifications
1067
+ */
1068
+ getNotificationPreferences(customerId: string): Promise<ApiResponse<NotificationPreferences>>;
1069
+ /**
1070
+ * Update notification preferences for a customer (partial merge).
1071
+ * PATCH /api/v1/customers/:id/preferences/notifications
1072
+ */
1073
+ updateNotificationPreferences(customerId: string, preferences: Partial<NotificationPreferences>): Promise<ApiResponse<NotificationPreferences>>;
898
1074
  }
899
1075
 
900
1076
  declare class FlowClient {
@@ -1185,6 +1361,68 @@ declare class OrganizationClient {
1185
1361
  getBySlug(slug: string, options?: GetOrganizationOptions): Promise<ApiResponse<Organization | OrganizationFullConfig>>;
1186
1362
  }
1187
1363
 
1364
+ /**
1365
+ * DocumentClient — manage file artifacts attached to Slotly entities.
1366
+ *
1367
+ * Artifacts are tenant-scoped files (CVs, invoices, images, etc.) linked
1368
+ * to a customer, booking, slot, service, or tenant record.
1369
+ *
1370
+ * @example Upload a CV for a customer
1371
+ * ```ts
1372
+ * const artifact = await slotly.document.upload({
1373
+ * file: buffer,
1374
+ * filename: 'cv-2024.pdf',
1375
+ * related_entity_type: 'customer',
1376
+ * related_entity_id: customerId,
1377
+ * label: 'CV',
1378
+ * });
1379
+ * ```
1380
+ *
1381
+ * @example List all CVs for a customer
1382
+ * ```ts
1383
+ * const { data } = await slotly.document.listByEntity('customer', customerId, { signed: true });
1384
+ * ```
1385
+ */
1386
+ declare class DocumentClient {
1387
+ private readonly client;
1388
+ private readonly base;
1389
+ constructor(client: AxiosInstance);
1390
+ /**
1391
+ * Upload a file artifact.
1392
+ * Sends as multipart/form-data.
1393
+ */
1394
+ upload(options: UploadArtifactOptions): Promise<Artifact>;
1395
+ /**
1396
+ * List artifacts for a specific entity.
1397
+ * Pass `signed: true` to get download URLs in each result.
1398
+ */
1399
+ listByEntity(entityType: ArtifactEntityType, entityId: string, options?: Omit<ListArtifactsOptions, 'related_entity_type' | 'related_entity_id'>): Promise<ApiResponse<(Artifact | ArtifactWithUrl)[]>>;
1400
+ /**
1401
+ * List artifacts with full filter options.
1402
+ */
1403
+ list(options: ListArtifactsOptions): Promise<ApiResponse<(Artifact | ArtifactWithUrl)[]>>;
1404
+ /**
1405
+ * Get a single artifact by ID.
1406
+ */
1407
+ get(id: string, signed?: boolean): Promise<Artifact | ArtifactWithUrl>;
1408
+ /**
1409
+ * Get a signed download URL for an artifact.
1410
+ * Returns the full ArtifactWithUrl including `signed_url` and `signed_url_expires_at`.
1411
+ */
1412
+ getUrl(id: string): Promise<ArtifactWithUrl>;
1413
+ /**
1414
+ * Delete an artifact and its stored file.
1415
+ */
1416
+ delete(id: string): Promise<void>;
1417
+ /**
1418
+ * Update artifact label or metadata.
1419
+ */
1420
+ update(id: string, patch: {
1421
+ label?: string;
1422
+ metadata?: Record<string, unknown>;
1423
+ }): Promise<Artifact>;
1424
+ }
1425
+
1188
1426
  /**
1189
1427
  * Custom error classes for Slotly SDK
1190
1428
  */
@@ -1347,6 +1585,8 @@ interface SlotlyApi {
1347
1585
  notification: NotificationClient;
1348
1586
  dataQuality: DataQualityClient;
1349
1587
  organization: OrganizationClient;
1588
+ /** Upload and retrieve file artifacts (CVs, invoices, images) linked to any Slotly entity */
1589
+ document: DocumentClient;
1350
1590
  }
1351
1591
  /**
1352
1592
  * Initialize and configure a new Slotly API client with dual authentication.
@@ -1411,4 +1651,4 @@ interface SlotlyApi {
1411
1651
  */
1412
1652
  declare const useSlotly: (options: SlotlyClientOptions) => SlotlyApi;
1413
1653
 
1414
- export { type ApiResponse, type Booking, type BookingWithSlot, type Category, type Customer, type DataQualityIssue, type Flow, type FlowStep, type GetOrganizationOptions, type ListBookingsOptions, type Notification, type Organization, type OrganizationFullConfig, type Service, type ServiceItem, type ServiceItemWithService, type ServiceWithItems, type Slot, type SlotServiceWithItems, type SlotlyApi, SlotlyApiError, type SlotlyAuthContext, SlotlyAuthError, type SlotlyClientOptions, SlotlyConfigurationError, SlotlyNetworkError, type SlotlyRequest, type Studio, type Tenant, type TenantBranding, type TenantFullConfig, useSlotly as default, getSlotlyContext, useSlotly, validateSlotlyRequest };
1654
+ export { type ApiResponse, type Artifact, type ArtifactEntityType, type ArtifactMimeCategory, type ArtifactWithUrl, type Booking, type BookingWithSlot, type Category, type Customer, type CustomerIdentity, type CustomerWithBookings, type CustomerWithIdentities, type DataQualityIssue, type FindOrCreateCustomerOptions, type Flow, type FlowStep, type GetOrganizationOptions, type ListArtifactsOptions, type ListBookingsOptions, type Notification, type NotificationPreferences, type Organization, type OrganizationFullConfig, type ResolveCustomerOptions, type Service, type ServiceItem, type ServiceItemWithService, type ServiceWithItems, type Slot, type SlotServiceWithItems, type SlotlyApi, SlotlyApiError, type SlotlyAuthContext, SlotlyAuthError, type SlotlyClientOptions, SlotlyConfigurationError, SlotlyNetworkError, type SlotlyRequest, type Studio, type Tenant, type TenantBranding, type TenantFullConfig, type UploadArtifactOptions, useSlotly as default, getSlotlyContext, useSlotly, validateSlotlyRequest };