import {z} from 'zod' export type Interval = 'Hour' | 'Day' | 'Week' | 'Month'; export type GroupingOptions = 'Company' | 'CompanyNumbers' | 'Users' | 'Queues' | 'IVRs' | 'SharedLines' | 'UserGroups' | 'Sites' | 'Departments'; export type DirectGrouping = {groupBy: GroupingOptions, keys?: Array | undefined}; export type MembersGroupingOptions = 'Department' | 'UserGroup' | 'Queue' | 'Site'; export type GroupingByMembers = {groupByMembers: MembersGroupingOptions, keys?: Array | undefined}; export type Grouping = DirectGrouping | GroupingByMembers; export type TimeRange = {timeFrom: string, timeTo: string}; export type DayOfWeek = 'Sunday' | 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday'; export type HoursInterval = {from: string, to: string}; export type AdvancedTimeSettings = {includeDays?: Array | undefined, includeHours?: Array | undefined}; export type TimeSettings = {timeZone: string, timeRange: TimeRange, advancedTimeSettings?: AdvancedTimeSettings | undefined}; export type ExtensionFilters = {fromIds?: Array | undefined, toIds?: Array | undefined}; export type Direction = 'Inbound' | 'Outbound'; export type Origin = 'Internal' | 'External'; export type CallResponse = 'Answered' | 'NotAnswered' | 'Connected' | 'NotConnected'; export type CallResult = 'Completed' | 'Abandoned' | 'Voicemail' | 'Unknown' | 'Missed' | 'Accepted'; export type CallSegmentOptions = 'Ringing' | 'LiveTalk' | 'Hold' | 'Park' | 'Transfer' | 'IvrPrompt' | 'Voicemail' | 'VmGreeting' | 'Setup'; export type CallSegmentLengthFilter = {minSeconds?: number | undefined, maxSeconds?: number | undefined}; export type CallSegmentFilter = {segment: CallSegmentOptions, length?: CallSegmentLengthFilter | undefined}; export type CallAction = 'HoldOff' | 'HoldOn' | 'ParkOn' | 'ParkOff' | 'BlindTransfer' | 'WarmTransfer' | 'DTMFTransfer'; export type CompanyHoursOptions = 'BusinessHours' | 'AfterHours'; export type CallDurationFilter = {minSeconds?: number | undefined, maxSeconds?: number | undefined}; export type TimeSpentFilter = {minSeconds?: number | undefined, maxSeconds?: number | undefined}; export type QueueSlaOptions = 'InSla' | 'OutSla'; export type CallType = 'Direct' | 'FromQueue' | 'ParkRetrieval' | 'Transferred' | 'Outbound' | 'Overflow'; export type CallFilters = {extensionFilters?: ExtensionFilters | undefined, queues?: Array | undefined, calledNumbers?: Array | undefined, directions?: Array | undefined, origins?: Array | undefined, callResponses?: Array | undefined, callResults?: Array | undefined, callSegments?: Array | undefined, callActions?: Array | undefined, companyHours?: Array | undefined, callDuration?: CallDurationFilter | undefined, timeSpent?: TimeSpentFilter | undefined, queueSla?: Array | undefined, callTypes?: Array | undefined}; export type TimelineResponseOptionsCounters = {allCalls?: boolean | undefined, callsByDirection?: boolean | undefined, callsByOrigin?: boolean | undefined, callsByResponse?: boolean | undefined, callsSegments?: boolean | undefined, callsByResult?: boolean | undefined, callsByCompanyHours?: boolean | undefined, callsByQueueSla?: boolean | undefined, callsByActions?: boolean | undefined, callsByType?: boolean | undefined, queueOpportunities?: boolean | undefined}; export type TimelineResponseOptionsTimers = {allCallsDuration?: boolean | undefined, callsDurationByDirection?: boolean | undefined, callsDurationByOrigin?: boolean | undefined, callsDurationByResponse?: boolean | undefined, callsSegmentsDuration?: boolean | undefined, callsDurationByResult?: boolean | undefined, callsDurationByCompanyHours?: boolean | undefined, callsDurationByQueueSla?: boolean | undefined, callsDurationByType?: boolean | undefined}; export type TimelineResponseOptions = {counters?: TimelineResponseOptionsCounters | undefined, timers?: TimelineResponseOptionsTimers | undefined}; export type TimelineRequest = {grouping: Grouping, timeSettings: TimeSettings, callFilters?: CallFilters | undefined, responseOptions: TimelineResponseOptions}; export type CreateApiAnalyticsCallsV1AccountsAccountIdTimelineFetchArgs = {accountId: string, interval: Interval, page?: number | undefined, perPage?: number | undefined, body: TimelineRequest}; export type CreateApiAnalyticsCallsV1AccountsAccountIdTimelineFetchOptions = {baseUrl?: string | undefined, OAuth2?: string | undefined, fetch?: typeof fetch | undefined}; export const responsePaging = z.object({page: z.number().int(), perPage: z.number().int(), totalPages: z.number().int(), totalElements: z.number().int()}); export const groupingOptions = z.enum(["Company", "CompanyNumbers", "Users", "Queues", "IVRs", "SharedLines", "UserGroups", "Sites", "Departments"]); export const keyInfo = z.object({extensionNumber: z.string().optional(), name: z.string().optional()}); export const valueType = z.enum(["Percent", "Seconds", "Instances"]); export const allCalls = z.object({valueType: valueType, values: z.number()}); export const callsByDirectionBreakdown = z.object({inbound: z.number(), outbound: z.number()}); export const callsByDirection = z.object({valueType: valueType, values: callsByDirectionBreakdown}); export const callsByOriginBreakdown = z.object({internal: z.number(), external: z.number()}); export const callsByOrigin = z.object({valueType: valueType, values: callsByOriginBreakdown}); export const callsByResponseBreakdown = z.object({answered: z.number(), notAnswered: z.number(), connected: z.number(), notConnected: z.number()}); export const callsByResponse = z.object({valueType: valueType, values: callsByResponseBreakdown}); export const callsBySegmentsBreakdown = z.object({ringing: z.number(), liveTalk: z.number(), hold: z.number(), park: z.number(), transfer: z.number(), ivrPrompt: z.number(), voicemail: z.number(), vmGreeting: z.number(), setup: z.number()}); export const callsBySegments = z.object({valueType: valueType, values: callsBySegmentsBreakdown}); export const callsByResultBreakdown = z.object({completed: z.number(), abandoned: z.number(), voicemail: z.number(), missed: z.number(), accepted: z.number(), unknown: z.number()}); export const callsByResult = z.object({valueType: valueType, values: callsByResultBreakdown}); export const callsByCompanyHoursBreakdown = z.object({businessHours: z.number(), afterHours: z.number()}); export const callsByCompanyHours = z.object({valueType: valueType, values: callsByCompanyHoursBreakdown}); export const callsByQueueSlaBreakdown = z.object({inSla: z.number(), outOfSla: z.number()}); export const callsByQueueSla = z.object({valueType: valueType, values: callsByQueueSlaBreakdown}); export const callsByTypeBreakdown = z.object({direct: z.number(), fromQueue: z.number(), parkRetrieval: z.number(), transferred: z.number(), outbound: z.number(), overflow: z.number()}); export const callsByType = z.object({valueType: valueType, values: callsByTypeBreakdown}); export const callsTimers = z.object({allCalls: allCalls.optional(), callsByDirection: callsByDirection.optional(), callsByOrigin: callsByOrigin.optional(), callsByResponse: callsByResponse.optional(), callsSegments: callsBySegments.optional(), callsByResult: callsByResult.optional(), callsByCompanyHours: callsByCompanyHours.optional(), callsByQueueSla: callsByQueueSla.optional(), callsByType: callsByType.optional()}); export const callsByActionsBreakdown = z.object({parkOn: z.number(), parkOff: z.number(), holdOn: z.number(), holdOff: z.number(), blindTransfer: z.number(), warmTransfer: z.number(), dtmfTransfer: z.number()}); export const callsByActions = z.object({valueType: valueType, values: callsByActionsBreakdown}); export const queueOpportunities = z.object({valueType: valueType, values: z.number()}); export const callsCounters = z.object({allCalls: allCalls.optional(), callsByDirection: callsByDirection.optional(), callsByOrigin: callsByOrigin.optional(), callsByResponse: callsByResponse.optional(), callsSegments: callsBySegments.optional(), callsByResult: callsByResult.optional(), callsActions: callsByActions.optional(), callsByCompanyHours: callsByCompanyHours.optional(), callsByQueueSla: callsByQueueSla.optional(), callsByType: callsByType.optional(), queueOpportunities: queueOpportunities.optional()}); export const timelineResponsePoint = z.object({time: z.string(), timers: callsTimers.optional(), counters: callsCounters.optional()}); export const timelineResponseRecord = z.object({key: z.string(), info: keyInfo.optional(), points: z.array(timelineResponsePoint).optional()}); export const timelineResponseData = z.object({groupedBy: groupingOptions, records: z.array(timelineResponseRecord).optional()}); export const timelineResponse = z.object({paging: responsePaging, data: timelineResponseData}); 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 }; /** * Calls Timeline Data * * POST /analytics/calls/v1/accounts/{accountId}/timeline/fetch */ export const createApiAnalyticsCallsV1AccountsAccountIdTimelineFetch = async (args: CreateApiAnalyticsCallsV1AccountsAccountIdTimelineFetchArgs, options?: CreateApiAnalyticsCallsV1AccountsAccountIdTimelineFetchOptions) => { const {baseUrl = "https://platform.ringcentral.com", fetch: fetchFn = fetch, OAuth2} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args.interval != null) query.append("interval", String(args.interval)) if (args.page != null) query.append("page", String(args.page)) if (args.perPage != null) query.append("perPage", String(args.perPage)) if (OAuth2 !== undefined) headers.set('authorization', `Bearer ${OAuth2}`) const url = `${baseUrl.replace(/\/+$/, '')}/analytics/calls/v1/accounts/${encodeURIComponent(String(args.accountId))}/timeline/fetch${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(timelineResponse, await res.json()) };