import {z} from 'zod' export type StrategyDuration = {use_campaign_start?: boolean | undefined, use_campaign_end?: boolean | undefined, start_date?: (string | null) | undefined, end_date?: (string | null) | undefined}; export type StrategyBudget = {budget?: (number | null) | undefined, currency_code?: string | undefined, margin_pct?: (number | null) | undefined}; export type StrategyFrequency = {frequency_type?: ('even' | 'asap' | 'no-limit' | 't1-optimized' | 'frequency_goal') | undefined, frequency_interval?: ('hour' | 'day' | 'week' | 'month' | 'not-applicable' | null) | undefined, frequency_amount?: (number | null) | undefined, frequency_optimization?: boolean | undefined}; export type StrategyConcepts = {weighting?: ('NONE' | 'BUDGET' | 'IMPRESSION') | undefined, creative_groups?: Array<{concept_id: number, percent: number}> | undefined}; export type StrategyGoals = {goal_type?: ('spend' | 'reach' | 'cpc' | 'cpe' | 'cpa' | 'roi' | 'ctr' | 'vcr' | 'viewability_rate' | 'vcpm') | undefined, goal_value?: number | undefined, min_bid?: number | undefined, max_bid?: number | undefined, roi_target?: (number | null) | undefined, bid_min_devices?: (number | null) | undefined, bid_aggressiveness?: number | undefined, bid_price_is_media_only?: boolean | undefined, max_bid_wm?: (number | null) | undefined, use_bid_shading?: boolean | undefined, flat_rate_cpm?: (number | null) | undefined}; export type StrategyPacing = {impression_pacing_type?: ('even' | 'asap' | 'no-limit') | undefined, impression_pacing_amount?: (number | null) | undefined, impression_pacing_interval?: ('hour' | 'day') | undefined, pacing_type?: ('even' | 'asap') | undefined, pacing_amount?: number | undefined, pacing_interval?: ('hour' | 'day') | undefined, pacing_optimization_type?: ('monetary' | 'impression') | undefined, pacing_optimization_amount?: (number | null) | undefined, use_dba_strategy_pacing?: ('always' | 'never' | 'custom') | undefined, use_dba_strategy_pacing_after_date?: (string | null) | undefined}; export type DomainRestriction = {domain: string, target_type: 'DOMAIN' | 'APP'}; export type SiteList = {site_list_id: number, assigned: boolean}; export type Deal = {deal_id: number}; export type DealGroup = {deal_group_id: number}; export type SupplySource = {supply_source_id: number}; export type StrategyInventory = {supply_type?: ('RTB' | 'RMX_API' | 'T1_RMX' | 'MKT' | 'BATCH') | undefined, run_on_all_pmp?: boolean | undefined, run_on_all_exchanges?: boolean | undefined, site_restriction_transparent_urls?: boolean | undefined, domain_restrictions?: ({include?: Array | undefined, exclude?: Array | undefined}) | undefined, site_lists?: Array | undefined, campaign_site_lists?: Array | undefined, deals?: Array | undefined, deal_groups?: Array | undefined, supply_sources?: Array | undefined}; export type StrategyAudienceSegment = {audience_segment_id: number, user_cpm?: (number | null) | undefined}; export type StrategyContextualSegment = {targeting_segment_id: number, user_cpm?: (number | null) | undefined}; export type StrategySegmentGroup = {operator: 'AND', segment_groups: Array<{segment_group_id?: number | undefined}>}; export type StrategyGeofence = {operator?: ('AND' | 'OR') | undefined, segments?: (Array<{geofence_segment_id?: number | undefined, geofence_segment_factual_id?: string | undefined, place_list_id?: number | undefined}>) | undefined}; export type StrategyMyData = {operator?: ('AND' | 'OR') | undefined, pixels: Array<{pixel_id: number}>}; export type StrategyLocation = {operator?: ('AND' | 'OR') | undefined, target_value_id: number, code: 'DMAX' | 'REGN' | 'CITY' | 'COUNTRY'}; export type StrategyTechnology = {operator?: ('AND' | 'OR') | undefined, code: 'BSER' | 'CSPD' | 'DVCE' | 'ISPX' | 'OSXX' | 'INVT' | 'VPSZ' | 'VLIN' | 'VCON' | 'VAUD' | 'VSKP' | 'VPLC' | 'DVMD' | 'BRLG' | 'IPTA' | 'HYPL', target_value_id: number}; export type DayPart = {user_time?: boolean | undefined, start_hour: number, end_hour: number, days: Array<'M' | 'T' | 'W' | 'R' | 'F' | 'S' | 'U'>}; export type TargetingRecencyElementRequest = {pixel_id: number, from_hour: number, to_hour: number}; export type CreateApiBulkUpdateStrategiesArgs = {body: {update?: (Array<{id: number, name?: string | undefined, description?: string | undefined, status?: boolean | undefined, archived?: boolean | undefined, is_programmatic_guaranteed?: boolean | undefined, media_type?: ('DISPLAY' | 'VIDEO') | undefined, use_optimization?: boolean | undefined, ads_txt_verified?: ('ANY' | 'AUTHORIZED_ONLY' | 'AUTHORIZED_DIRECT_ONLY' | 'NONE' | null) | undefined, type?: ('REM' | 'GBO' | 'AUD') | undefined, feature_compatibility?: (string | null) | undefined, device_graph_only?: boolean | undefined, mfa_avoidance?: ('INHERIT' | 'ALLOW_ALL' | 'EXCLUDE_MFA') | undefined, zone_name?: string | undefined, created_on?: string | undefined, updated_on?: string | undefined, duration?: StrategyDuration | undefined, budget?: StrategyBudget | undefined, frequency?: StrategyFrequency | undefined, concepts?: StrategyConcepts | undefined, groups?: (Array | null) | undefined, strategy_group_id?: (number | null) | undefined, entity_type?: string | undefined, version?: number | undefined, goals?: StrategyGoals | undefined, pacing?: StrategyPacing | undefined, inventory?: StrategyInventory | undefined, targeting?: ({fold_position?: (Array<'ABOVE' | 'BELOW' | 'UNCATEGORIZED' | 'HEADER' | 'FOOTER' | 'SIDEBAR' | 'FULLSCREEN'> | null) | undefined, audience?: ({include?: (Array<{operator?: ('AND' | 'OR') | undefined, segments?: Array | undefined}>) | undefined, exclude?: ({operator?: ('AND' | 'OR') | undefined, segments?: Array | undefined}) | undefined}) | undefined, contextual?: ({include?: (Array<{code?: string | undefined, operator?: ('AND' | 'OR') | undefined, segments?: Array | undefined}>) | undefined, exclude?: ({code?: string | undefined, operator?: ('AND' | 'OR') | undefined, segments: Array}) | undefined}) | undefined, audience_groups?: ({include?: Array | undefined, exclude?: Record | undefined}) | undefined, contextual_groups?: ({include?: Array | undefined, exclude?: Record | undefined}) | undefined, geofence?: ({include?: StrategyGeofence | undefined, exclude?: StrategyGeofence | undefined}) | undefined, my_data?: ({include?: StrategyMyData | undefined, exclude?: StrategyMyData | undefined}) | undefined, location?: ({include?: Array | undefined, exclude?: Array | undefined}) | undefined, technology?: ({include?: Array | undefined, exclude?: Array | undefined}) | undefined, day_parts?: Array | undefined, language_codes?: Array | undefined, recency?: Array | undefined}) | undefined}>) | undefined}}; export type CreateApiBulkUpdateStrategiesOptions = {baseUrl?: string | undefined, Auth0?: string | undefined, fetch?: typeof fetch | undefined}; export const strategyDuration = z.object({use_campaign_start: z.boolean().optional(), use_campaign_end: z.boolean().optional(), start_date: z.string().nullable().optional(), end_date: z.string().nullable().optional()}); export const strategyBudget = z.object({budget: z.number().nullable().optional(), currency_code: z.string().optional(), margin_pct: z.number().gte(0).lte(9999999.9999).nullable().optional()}); export const strategyFrequency = z.object({frequency_type: z.enum(["even", "asap", "no-limit", "t1-optimized", "frequency_goal"]).optional(), frequency_interval: z.enum(["hour", "day", "week", "month", "not-applicable"]).nullable().optional(), frequency_amount: z.number().int().nullable().optional(), frequency_optimization: z.boolean().optional()}); export const strategyConcepts = z.object({weighting: z.enum(["NONE", "BUDGET", "IMPRESSION"]).optional(), creative_groups: z.array(z.object({concept_id: z.number().int(), percent: z.number().gte(0).lte(100)})).optional()}); export const strategyGoals = z.object({goal_type: z.enum(["spend", "reach", "cpc", "cpe", "cpa", "roi", "ctr", "vcr", "viewability_rate", "vcpm"]).optional(), goal_value: z.number().gte(0).lte(9999999.9999).optional(), min_bid: z.number().gte(0).lte(9999999.99).optional(), max_bid: z.number().gte(0.01).lte(9999999.99).optional(), roi_target: z.number().gte(0).lte(9999999.99).nullable().optional(), bid_min_devices: z.number().int().gte(-32768).lte(32767).nullable().optional(), bid_aggressiveness: z.number().int().gte(0).lte(100).optional(), bid_price_is_media_only: z.boolean().optional(), max_bid_wm: z.number().gte(0).lte(9999999.99).nullable().optional(), use_bid_shading: z.boolean().optional(), flat_rate_cpm: z.number().gte(0.01).lte(9999999.99).nullable().optional()}); export const strategyPacing = z.object({impression_pacing_type: z.enum(["even", "asap", "no-limit"]).optional(), impression_pacing_amount: z.number().int().gte(1).nullable().optional(), impression_pacing_interval: z.enum(["hour", "day"]).optional(), pacing_type: z.enum(["even", "asap"]).optional(), pacing_amount: z.number().gte(0.01).lte(9999999.99).optional(), pacing_interval: z.enum(["hour", "day"]).optional(), pacing_optimization_type: z.enum(["monetary", "impression"]).optional(), pacing_optimization_amount: z.number().gte(0).lte(9999999.99).nullable().optional(), use_dba_strategy_pacing: z.enum(["always", "never", "custom"]).optional(), use_dba_strategy_pacing_after_date: z.string().nullable().optional()}); export const domainRestriction = z.object({domain: z.string(), target_type: z.enum(["DOMAIN", "APP"])}); export const siteList = z.object({site_list_id: z.number().int(), assigned: z.boolean()}); export const deal = z.object({deal_id: z.number().int()}); export const dealGroup = z.object({deal_group_id: z.number().int()}); export const supplySource = z.object({supply_source_id: z.number().int()}); export const strategyInventory = z.object({supply_type: z.enum(["RTB", "RMX_API", "T1_RMX", "MKT", "BATCH"]).optional(), run_on_all_pmp: z.boolean().optional(), run_on_all_exchanges: z.boolean().optional(), site_restriction_transparent_urls: z.boolean().optional(), domain_restrictions: z.object({include: z.array(domainRestriction).optional(), exclude: z.array(domainRestriction).optional()}).optional(), site_lists: z.array(siteList).optional(), campaign_site_lists: z.array(siteList).optional(), deals: z.array(deal).optional(), deal_groups: z.array(dealGroup).optional(), supply_sources: z.array(supplySource).optional()}); export const strategyAudienceSegment = z.object({audience_segment_id: z.number().int(), user_cpm: z.number().nullable().optional()}); export const strategyContextualSegment = z.object({targeting_segment_id: z.number().int(), user_cpm: z.number().nullable().optional()}); export const strategySegmentGroup = z.object({operator: z.literal("AND"), segment_groups: z.array(z.object({segment_group_id: z.number().int().optional()}))}); export const strategyGeofence = z.object({operator: z.enum(["AND", "OR"]).optional(), segments: z.array(z.object({geofence_segment_id: z.number().int().optional(), geofence_segment_factual_id: z.string().optional(), place_list_id: z.number().int().gte(1).lte(2147483647).optional()})).optional()}); export const strategyMyData = z.object({operator: z.enum(["AND", "OR"]).optional(), pixels: z.array(z.object({pixel_id: z.number().int()}))}); export const strategyLocation = z.object({operator: z.enum(["AND", "OR"]).optional(), target_value_id: z.number().int(), code: z.enum(["DMAX", "REGN", "CITY", "COUNTRY"])}); export const strategyTechnology = z.object({operator: z.enum(["AND", "OR"]).optional(), code: z.enum(["BSER", "CSPD", "DVCE", "ISPX", "OSXX", "INVT", "VPSZ", "VLIN", "VCON", "VAUD", "VSKP", "VPLC", "DVMD", "BRLG", "IPTA", "HYPL"]), target_value_id: z.number().int()}); export const dayPart = z.object({user_time: z.boolean().optional(), start_hour: z.number().int().gte(0).lte(23), end_hour: z.number().int().gte(0).lte(23), days: z.array(z.enum(["M", "T", "W", "R", "F", "S", "U"]))}); export const targetingIpAddressesResponse = z.object({restriction: z.enum(["INCLUDE", "EXCLUDE", ""]).optional(), count: z.number().int().optional()}); export const targetingPostalCodesResponse = z.object({restriction: z.string().optional(), count: z.number().int().optional()}); export const targetingRecencyElementResponse = z.object({pixel_id: z.number().int().optional(), from_hour: z.number().int().optional(), to_hour: z.number().int().optional()}); export const strategyFullResponse = z.object({name: z.string().max(128).optional(), description: z.string().max(1024).optional(), status: z.boolean().optional(), archived: z.boolean().optional(), is_programmatic_guaranteed: z.boolean().optional(), media_type: z.enum(["DISPLAY", "VIDEO"]).optional(), use_optimization: z.boolean().optional(), ads_txt_verified: z.enum(["ANY", "AUTHORIZED_ONLY", "AUTHORIZED_DIRECT_ONLY", "NONE"]).nullable().optional(), type: z.enum(["REM", "GBO", "AUD"]).optional(), feature_compatibility: z.string().max(1024).nullable().optional(), device_graph_only: z.boolean().optional(), mfa_avoidance: z.enum(["INHERIT", "ALLOW_ALL", "EXCLUDE_MFA"]).optional(), zone_name: z.string().optional(), created_on: z.string().optional(), updated_on: z.string().optional(), duration: strategyDuration.optional(), budget: strategyBudget.optional(), frequency: strategyFrequency.optional(), concepts: strategyConcepts.optional(), groups: z.array(z.string()).nullable().optional(), strategy_group_id: z.number().int().gte(1).nullable().optional(), entity_type: z.string().optional(), version: z.number().int().optional(), goals: strategyGoals.optional(), pacing: strategyPacing.optional(), inventory: strategyInventory.optional(), id: z.number().int().optional(), campaign_id: z.number().int().optional(), targeting: z.object({fold_position: z.array(z.enum(["ABOVE", "BELOW", "UNCATEGORIZED", "HEADER", "FOOTER", "SIDEBAR", "FULLSCREEN"])).nullable().optional(), audience: z.object({include: z.array(z.object({operator: z.enum(["AND", "OR"]).optional(), segments: z.array(strategyAudienceSegment).optional()})).optional(), exclude: z.object({operator: z.enum(["AND", "OR"]).optional(), segments: z.array(strategyAudienceSegment).optional()}).optional()}).optional(), contextual: z.object({include: z.array(z.object({code: z.string().optional(), operator: z.enum(["AND", "OR"]).optional(), segments: z.array(strategyContextualSegment).optional()})).optional(), exclude: z.object({code: z.string().optional(), operator: z.enum(["AND", "OR"]).optional(), segments: z.array(strategyContextualSegment)}).optional()}).optional(), audience_groups: z.object({include: z.array(strategySegmentGroup).optional(), exclude: z.object({}).optional()}).optional(), contextual_groups: z.object({include: z.array(strategySegmentGroup).optional(), exclude: z.object({}).optional()}).optional(), geofence: z.object({include: strategyGeofence.optional(), exclude: strategyGeofence.optional()}).optional(), my_data: z.object({include: strategyMyData.optional(), exclude: strategyMyData.optional()}).optional(), location: z.object({include: z.array(strategyLocation).optional(), exclude: z.array(strategyLocation).optional()}).optional(), technology: z.object({include: z.array(strategyTechnology).optional(), exclude: z.array(strategyTechnology).optional()}).optional(), day_parts: z.array(dayPart).optional(), language_codes: z.array(z.object({code: z.string().optional(), name: z.string().optional()})).optional(), ip_addresses: targetingIpAddressesResponse.optional(), postal_codes: targetingPostalCodesResponse.optional(), recency: z.array(targetingRecencyElementResponse).optional()}).optional()}); export const listMetadata = z.object({status: z.string(), count: z.number().int(), total_count: z.number().int().optional(), offset: z.number().int().optional(), next_page: z.string().optional(), prev_page: z.string().optional()}); export const createApiBulkUpdateStrategiesResponse = z.object({data: z.array(strategyFullResponse).optional(), meta: listMetadata.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 }; /** * Bulk Update Strategies * * POST /bulk_update/strategies */ export const createApiBulkUpdateStrategies = async (args: CreateApiBulkUpdateStrategiesArgs, options?: CreateApiBulkUpdateStrategiesOptions) => { const {baseUrl = "https://api.mediamath.com/api/v3.0", fetch: fetchFn = fetch, Auth0} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (Auth0 !== undefined) headers.set('authorization', `Bearer ${Auth0}`) const url = `${baseUrl.replace(/\/+$/, '')}/bulk_update/strategies${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(createApiBulkUpdateStrategiesResponse, await res.json()) };