import {z} from 'zod' export type GetApiApiV1ReportAiCustomerProfilesCustomerProfileIdArgs = {customer_profile_id: string}; export type GetApiApiV1ReportAiCustomerProfilesCustomerProfileIdOptions = {baseUrl: string, fetch?: typeof fetch | undefined}; export const customerIdentityKind = z.enum(["person", "shared_inbox", "unclassified", "stay_guest"]); export const sourceBadgeRead = z.object({source_key: z.string(), label: z.string(), badge_hue: z.string(), external_id: z.string().nullable().optional(), first_seen_at: z.string(), last_seen_at: z.string()}); export const attentionFlag = z.object({kind: z.enum(["open_duplicate", "field_conflict", "relay_identity", "no_source"]), detail: z.string()}); export const profileConflictRead = z.object({field_name: z.string(), our_value: z.unknown(), source_value: z.unknown(), source_label: z.string()}); export const threadMessageRead = z.object({id: z.string(), tenant_id: z.string(), thread_id: z.string(), channel: z.string(), source_provider: z.string(), source_ref: z.string().nullable(), direction: z.string(), author_type: z.string(), body_text: z.string().nullable(), body_html: z.string().nullable(), sent_at: z.string(), dedupe_key: z.string(), external_refs: z.record(z.string(), z.unknown())}); export const investigationSummaryRead = z.object({id: z.string(), interaction_summary: z.string(), lifecycle_status: z.string(), ticket_category: z.string().nullable().optional(), severity: z.string().nullable().optional()}); export const customerExternalIdentifierRead = z.object({provider: z.string(), identifier_type: z.string(), identifier_value: z.string()}); export const crmRecordLinkRead = z.object({integration_key: z.string(), object_type: z.literal("contact"), record_url: z.string()}); export const customerIdentifierRead = z.object({id: z.string(), kind: z.string(), value_normalized: z.string(), value_raw: z.string(), is_primary: z.boolean(), source_key: z.string(), source_merge_id: z.string().nullable().optional(), first_seen_at: z.string(), last_seen_at: z.string()}); export const tagDefinitionRead = z.object({id: z.string(), name: z.string(), slug: z.string(), color: z.enum(["default", "neutral", "success", "error", "warning", "danger", "info", "purple", "pink", "teal", "orange", "indigo", "slate"]), icon: z.string().nullable().optional(), description: z.string().nullable(), dimension: z.string(), parent_id: z.string().nullable(), deprecated_at: z.string().nullable(), created_by_user_id: z.string().nullable(), created_at: z.string(), updated_at: z.string()}); export const conversationTagRead = z.object({id: z.string(), voice_call_id: z.string().nullable(), text_session_id: z.string().nullable(), tag_definition_id: z.string(), is_primary: z.boolean(), source: z.string(), applied_by_user_id: z.string().nullable(), confidence: z.number().nullable(), model_version: z.string().nullable(), created_at: z.string(), tag_definition: tagDefinitionRead.nullable().optional()}); export const textSessionListItem = z.object({id: z.string(), text_agent_id: z.string().nullable(), status: z.string(), visitor_name: z.string().nullable(), visitor_email: z.string().nullable(), visitor_phone: z.string().nullable(), message_count: z.number().int(), started_at: z.string().nullable(), ended_at: z.string().nullable(), created_at: z.string(), channel: z.string(), last_message_at: z.string().nullable(), session_metadata: z.record(z.string(), z.unknown()).nullable().optional(), handoff_status: z.string().nullable().optional(), is_new: z.boolean(), email_verified: z.boolean(), review_status: z.string(), applied_tags: z.array(conversationTagRead).optional(), is_after_hours: z.boolean().nullable().optional(), outcome_agent_ref: z.string().nullable().optional(), outcome: z.string().nullable().optional(), disposition: z.string().nullable().optional(), was_transferred: z.boolean().optional(), transfer_destination: z.string().nullable().optional(), transfer_mode: z.string().nullable().optional(), human_handoff_completed_at: z.string().nullable().optional(), booking_made: z.boolean().nullable().optional(), booking_intent: z.boolean().optional(), booking_status: z.string().nullable().optional(), booking_value_cents: z.number().int().nullable().optional(), booking_value_currency: z.string().nullable().optional(), attribution_bucket: z.string().nullable().optional(), contact_source: z.string().nullable().optional(), active_seconds: z.number().int().nullable().optional(), first_ai_response_at: z.string().nullable().optional(), local_hour_of_day: z.number().int().nullable().optional(), local_day_of_week: z.number().int().nullable().optional(), is_repeat_caller: z.boolean().optional(), primary_property_id: z.string().nullable().optional(), primary_property_name: z.string().nullable().optional()}); export const bookingCustomerRole = z.enum(["booker", "primary_guest", "guest", "payer", "reservation_contact"]); export const customerProfileBookingRead = z.object({id: z.string(), tenant_id: z.string(), channel: z.string(), voice_agent_id: z.string().nullable(), call_id: z.string().nullable(), voice_call_external_id: z.string().nullable().optional(), text_agent_id: z.string().nullable(), text_session_id: z.string().nullable(), customer_profile_id: z.string().nullable(), customer_profile_name: z.string().nullable().optional(), reservation_id: z.string(), property_code: z.string(), property_name: z.string(), guest_first_name: z.string().nullable(), guest_last_name: z.string().nullable(), guest_email: z.string().nullable(), guest_phone: z.string().nullable(), checkin: z.string(), checkout: z.string(), adults: z.number().int(), children: z.number().int(), rooms: z.number().int(), price: z.number(), currency: z.string(), status: z.string(), booked_at: z.string(), cancelled_at: z.string().nullable(), raw_response: z.record(z.string(), z.unknown()).nullable(), cancellation_response: z.record(z.string(), z.unknown()).nullable(), created_at: z.string(), updated_at: z.string(), customer_roles: z.array(bookingCustomerRole).optional()}); export const customerProfileVoiceCallRead = z.object({external_id: z.string(), started_at: z.string().nullable().optional(), summary: z.string().nullable().optional(), call_type: z.string(), status: z.string()}); export const customerProfileFactRead = z.object({key: z.string(), value: z.string(), investigation_id: z.string()}); export const tripCommRead = z.object({kind: z.string(), ref: z.string(), summary: z.string().nullable().optional(), message_count: z.number().int().nullable().optional()}); export const tripRead = z.object({attempt_id: z.string(), status: z.string(), is_converted: z.boolean(), property_id: z.string().nullable().optional(), property_code: z.string().nullable().optional(), requested_checkin: z.string().nullable().optional(), requested_checkout: z.string().nullable().optional(), party_size: z.number().int().nullable().optional(), episode_id: z.string().nullable().optional(), comms: z.array(tripCommRead).optional()}); export const customerProfileDetailRead = z.object({id: z.string(), tenant_id: z.string(), customer_email: z.string().nullable(), customer_name: z.string().nullable(), phone_number: z.string().nullable(), total_investigations: z.number().int(), complaints_count: z.number().int(), last_sentiment: z.string().nullable(), total_revenue_cents: z.number().int().nullable(), average_booking_value_cents: z.number().int().nullable(), loyalty_tier: z.string().nullable(), country: z.string().nullable().optional(), identity_kind: customerIdentityKind.optional(), requires_attention: z.boolean().optional(), attention_reason: z.string().nullable().optional(), business_id: z.string().nullable().optional(), first_seen_at: z.string(), last_seen_at: z.string(), sources: z.array(sourceBadgeRead).optional(), attention: z.array(attentionFlag).optional(), resolved_from_profile_id: z.string().nullable().optional(), resolved_from_merge_id: z.string().nullable().optional(), business_name: z.string().nullable().optional(), profile_field_sources: z.record(z.string(), z.string()).optional(), profile_conflicts: z.array(profileConflictRead).optional(), recent_interactions: z.array(threadMessageRead).optional(), recent_investigations: z.array(investigationSummaryRead).optional(), external_identifiers: z.array(customerExternalIdentifierRead).optional(), crm_records: z.array(crmRecordLinkRead).optional(), identifiers: z.array(customerIdentifierRead).optional(), text_sessions: z.array(textSessionListItem).optional(), bookings: z.array(customerProfileBookingRead).nullable().optional(), voice_calls: z.array(customerProfileVoiceCallRead).optional(), key_facts: z.array(customerProfileFactRead).optional(), trips: z.array(tripRead).nullable().optional()}); 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 }; /** * Get Customer Profile * * GET /api/v1/report-ai/customer-profiles/{customer_profile_id} */ export const getApiApiV1ReportAiCustomerProfilesCustomerProfileId = async (args: GetApiApiV1ReportAiCustomerProfilesCustomerProfileIdArgs, options: GetApiApiV1ReportAiCustomerProfilesCustomerProfileIdOptions) => { const {baseUrl, fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/api/v1/report-ai/customer-profiles/${encodeURIComponent(String(args.customer_profile_id))}${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(customerProfileDetailRead, await res.json()) };