import {z} from 'zod' export type GetApiV1AppointmentsArgs = {center_id: string, start_date: string, end_date: string, include_no_show_cancel?: boolean | undefined, therapist_id?: string | undefined}; export type GetApiV1AppointmentsOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const getApiV1AppointmentsResponse = z.union([z.array(z.object({appointment_id: z.string().optional(), appointment_segment_id: z.unknown(), appointment_group_id: z.string().optional(), invoice_id: z.string().optional(), service: z.object({id: z.string().optional(), name: z.string().optional(), is_addon: z.boolean().optional(), has_addons: z.boolean().optional(), parent_appointment_id: z.unknown(), business_unit: z.object({guid: z.string().optional(), name: z.string().optional(), id: z.number().int().optional()}).optional(), category: z.object({id: z.string().optional(), name: z.string().optional()}).optional(), sub_category: z.object({id: z.string().optional(), name: z.string().optional()}).optional(), override_product_consumption: z.boolean().optional(), override_default_product_consumption: z.boolean().optional()}).optional(), start_time: z.string().optional(), start_time_utc: z.string().optional(), end_time: z.string().optional(), end_time_utc: z.string().optional(), status: z.number().int().optional(), source: z.number().int().optional(), progress: z.number().int().optional(), locked: z.boolean().optional(), invoice_locked: z.boolean().optional(), has_active_membership_for_auto_pay: z.boolean().optional(), guest: z.object({id: z.string().optional(), first_name: z.string().optional(), last_name: z.string().optional(), gender: z.number().int().optional(), mobile: z.object({country_id: z.number().int().optional(), number: z.unknown(), display_number: z.string().optional()}).optional(), email: z.string().optional(), indicator: z.string().optional(), lp_tier_info: z.string().optional(), GuestIndicatorValue: z.unknown()}).optional(), therapist: z.object({id: z.string().optional(), first_name: z.string().optional(), last_name: z.string().optional(), nick_name: z.unknown(), display_name: z.unknown(), email: z.string().optional(), gender: z.number().int().optional(), vanity_image_url: z.string().optional()}).optional(), room: z.unknown(), equipment: z.unknown(), service_custom_data_indicator: z.string().optional(), notes: z.unknown(), price: z.unknown(), actual_start_time: z.unknown(), actual_completed_time: z.unknown(), checkin_time: z.unknown(), therapist_preference_type: z.number().int().optional(), form_id: z.string().optional(), blockout: z.unknown(), creation_date: z.string().optional(), creation_date_utc: z.string().optional(), created_by_id: z.string().optional(), closed_by_id: z.unknown(), show_in_calender: z.number().int().optional(), available_therapists: z.unknown(), available_rooms: z.unknown(), available_times: z.unknown(), selected_therapist_id: z.unknown(), selected_room_id: z.unknown(), selected_time: z.string().optional(), requested_alternative: z.number().int().optional(), group_invoice_id: z.unknown(), error: z.unknown()})), z.array(z.object({appointment_id: z.string().optional(), appointment_segment_id: z.unknown(), parent_service_name: z.string().optional(), appointment_group_id: z.string().optional(), invoice_id: z.string().optional(), service: z.object({id: z.string().optional(), segment_id: z.string().optional(), name: z.string().optional(), is_addon: z.boolean().optional(), has_addons: z.boolean().optional(), parent_appointment_id: z.unknown(), business_unit: z.object({guid: z.string().optional(), name: z.string().optional(), id: z.number().int().optional()}).optional(), category: z.object({id: z.string().optional(), name: z.string().optional()}).optional(), sub_category: z.object({id: z.string().optional(), name: z.string().optional()}).optional(), override_product_consumption: z.boolean().optional(), override_default_product_consumption: z.boolean().optional(), is_virtual_service: z.boolean().optional()}).optional(), start_time: z.string().optional(), start_time_utc: z.string().optional(), end_time: z.string().optional(), end_time_utc: z.string().optional(), status: z.number().int().optional(), source: z.number().int().optional(), progress: z.number().int().optional(), locked: z.boolean().optional(), invoice_locked: z.boolean().optional(), has_active_membership_for_auto_pay: z.boolean().optional(), auto_pay_authorize_status: z.number().int().optional(), has_unexpired_packages: z.boolean().optional(), guest: z.object({id: z.string().optional(), first_name: z.string().optional(), last_name: z.string().optional(), gender: z.number().int().optional(), mobile: z.object({country_id: z.number().int().optional(), number: z.unknown(), display_number: z.string().optional()}).optional(), email: z.unknown(), indicator: z.string().optional(), lp_tier_info: z.string().optional(), is_virtual_user: z.boolean().optional(), preferred_pronoun: z.string().optional(), GuestIndicatorValue: z.object({HighSpender: z.unknown(), Member: z.number().int().optional(), LowFeedback: z.unknown(), RegularGuest: z.unknown(), FirstTimer: z.unknown(), ReturningCustomer: z.unknown(), NoShow: z.unknown(), HasActivePackages: z.unknown(), HasProfileAlerts: z.unknown(), OtherCenterGuest: z.unknown(), HasCTA: z.unknown(), Dues: z.boolean().optional(), CardOnFile: z.unknown(), AutoPayEnabled: z.unknown(), RecurrenceAppointment: z.unknown(), RebookedAppointment: z.boolean().optional(), hasAddOns: z.unknown(), LpTier: z.unknown(), IsSurpriseVisit: z.unknown(), CustomDataIndicator: z.unknown(), IsGuestBirthday: z.unknown(), showGuestNotes: z.unknown(), NonExpirePackages: z.unknown(), NonExpireandNotClosedPackages: z.unknown(), HasFrozenPackages: z.unknown(), GuestIconInformation: z.unknown(), IsMinor: z.unknown()}).optional()}).optional(), therapist: z.object({id: z.string().optional(), first_name: z.string().optional(), last_name: z.string().optional(), nick_name: z.unknown(), display_name: z.unknown(), email: z.string().optional(), gender: z.number().int().optional(), vanity_image_url: z.string().optional()}).optional(), room: z.object({id: z.string().optional(), name: z.string().optional()}).optional(), equipment: z.unknown(), service_custom_data_indicator: z.string().optional(), notes: z.unknown(), group_notes: z.unknown(), price: z.object({currency_id: z.number().int().optional(), sales: z.number().int().optional(), tax: z.number().int().optional(), final: z.number().int().optional(), final1: z.number().int().optional(), discount: z.number().int().optional(), tip: z.number().int().optional(), ssg: z.unknown(), rounding_correction: z.number().int().optional()}).optional(), actual_start_time: z.unknown(), actual_completed_time: z.unknown(), checkin_time: z.unknown(), therapist_preference_type: z.number().int().optional(), form_id: z.unknown(), blockout: z.unknown(), creation_date: z.string().optional(), creation_date_utc: z.string().optional(), created_by_id: z.string().optional(), closed_by_id: z.unknown(), show_in_calender: z.number().int().optional(), cancel_or_no_show_status: z.number().int().optional(), email_link: z.unknown(), sms_link: z.unknown(), appointment_category_id: z.unknown(), invoice_processed_in_integrations: z.number().int().optional(), parallel_group_id: z.unknown(), is_single_appointment: z.boolean().optional(), available_therapists: z.unknown(), available_rooms: z.unknown(), available_times: z.unknown(), selected_therapist_id: z.unknown(), selected_room_id: z.unknown(), selected_time: z.string().optional(), requested_alternative: z.number().int().optional(), group_invoice_id: z.unknown(), group_name: z.unknown(), canUpdateTherapist: z.boolean().optional(), package_id: z.string().optional(), virtual_room_link: z.unknown(), invoice_item_id: z.string().optional(), quantity: z.number().int().optional(), is_feedback_filled: z.boolean().optional(), is_product_consumption_updated: z.boolean().optional(), are_custom_fields_filled: z.unknown(), are_package_targets_required: z.boolean().optional(), are_package_targets_filled: z.boolean().optional(), is_prescription_signed: z.unknown(), is_educator_rating_filled: z.boolean().optional(), app_count: z.number().int().optional(), error: z.unknown(), appointment_type: z.number().int().optional(), package_name: z.unknown()}))]); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Retrieve the list of appointments of a center * * GET /v1/appointments */ export const getApiV1Appointments = async (args: GetApiV1AppointmentsArgs, options?: GetApiV1AppointmentsOptions) => { const {baseUrl = "https://api.zenoti.com", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.center_id != null) query.append("center_id", String(args.center_id)) if (args.start_date != null) query.append("start_date", String(args.start_date)) if (args.end_date != null) query.append("end_date", String(args.end_date)) if (args.include_no_show_cancel != null) query.append("include_no_show_cancel", String(args.include_no_show_cancel)) if (args.therapist_id != null) query.append("therapist_id", String(args.therapist_id)) const url = `${baseUrl.replace(/\/+$/, '')}/v1/appointments${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(getApiV1AppointmentsResponse, await res.json()) };