import {z} from 'zod' export type PinterestLibPaginationOrder = 'ASCENDING' | 'DESCENDING'; export type ScheduleStatus = 'DRAFT' | 'CREATED' | 'SCHEDULED' | 'ACTIVE' | 'COMPLETED' | 'FAILED' | 'CANCELED'; export type ScheduleType = 'CAMPAIGN_BUDGET_CHANGE' | 'CAMPAIGN_BID_MULTIPLIERS'; export type EntityId = string; export type GetApiAdAccountsAdAccountIdSchedulesArgs = {ad_account_id: string, bookmark?: string | undefined, page_size?: number | undefined, order?: PinterestLibPaginationOrder | undefined, schedule_statuses?: Array | undefined, schedule_type?: ScheduleType | undefined, entity_ids: Array}; export type GetApiAdAccountsAdAccountIdSchedulesOptions = {baseUrl?: string | undefined, pinterestOauth2?: string | undefined, fetch?: typeof fetch | undefined}; export const bidOptionsAgeBucketMultipliers = z.object({"18-24": z.number().optional(), "25-34": z.number().optional(), "35-44": z.number().optional(), "45-49": z.number().optional(), "50-54": z.number().optional(), "55-64": z.number().optional(), "65+": z.number().optional()}); export const bidOptionsAppTypeMultipliers = z.object({android_mobile: z.number().optional(), android_tablet: z.number().optional(), ipad: z.number().optional(), iphone: z.number().optional(), web: z.number().optional(), web_mobile: z.number().optional()}); export const bidOptionsAudienceMultipliers = z.object({audience_id: z.string(), multiplier: z.number()}); export const bidOptionsGenderMultipliers = z.object({female: z.number().optional(), male: z.number().optional()}); export const bidOptionsPlacementMultipliers = z.object({browse: z.number().optional(), related_pins: z.number().optional(), search: z.number().optional()}); export const scheduleBidMultipliers = z.object({age_bucket_multipliers: bidOptionsAgeBucketMultipliers.optional(), app_type_multipliers: bidOptionsAppTypeMultipliers.optional(), audience_multipliers: z.array(bidOptionsAudienceMultipliers).optional(), gender_multipliers: bidOptionsGenderMultipliers.optional(), placement_multipliers: bidOptionsPlacementMultipliers.optional()}); export const entityId = z.string(); export const adAccountEntityType = z.enum(["ADVERTISER", "CAMPAIGN", "AD_GROUP", "AD"]); export const scheduleAction = z.enum(["INCREASE_BY_VALUE", "INCREASE_BY_PERCENT"]); export const scheduleStatus = z.enum(["DRAFT", "CREATED", "SCHEDULED", "ACTIVE", "COMPLETED", "FAILED", "CANCELED"]); export const scheduleType = z.enum(["CAMPAIGN_BUDGET_CHANGE", "CAMPAIGN_BID_MULTIPLIERS"]); export const schedule = z.object({delta_value: z.union([z.string(), scheduleBidMultipliers]).optional(), end_timestamp: z.number().int().optional(), entity_id: entityId, entity_type: adAccountEntityType.optional(), name: z.string().optional(), schedule_action: scheduleAction.optional(), schedule_id: z.string(), schedule_status: scheduleStatus.optional(), schedule_type: scheduleType.optional(), start_timestamp: z.number().int().optional()}); export const getApiAdAccountsAdAccountIdSchedulesResponse = z.object({bookmark: z.string().nullable().optional(), items: z.array(schedule)}); 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 Schedules * * GET /ad_accounts/{ad_account_id}/schedules */ export const getApiAdAccountsAdAccountIdSchedules = async (args: GetApiAdAccountsAdAccountIdSchedulesArgs, options?: GetApiAdAccountsAdAccountIdSchedulesOptions) => { const {baseUrl = "https://api.pinterest.com/v5", fetch: fetchFn = fetch, pinterestOauth2} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.bookmark != null) query.append("bookmark", String(args.bookmark)) if (args.page_size != null) query.append("page_size", String(args.page_size)) if (args.order != null) query.append("order", String(args.order)) for (const item of args.schedule_statuses ?? []) query.append("schedule_statuses", String(item)) if (args.schedule_type != null) query.append("schedule_type", String(args.schedule_type)) for (const item of args.entity_ids ?? []) query.append("entity_ids", String(item)) if (pinterestOauth2 !== undefined) headers.set('authorization', `Bearer ${pinterestOauth2}`) const url = `${baseUrl.replace(/\/+$/, '')}/ad_accounts/${encodeURIComponent(String(args.ad_account_id))}/schedules${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(getApiAdAccountsAdAccountIdSchedulesResponse, await res.json()) };