import {z} from 'zod' export type ParameterBoolean = boolean; export type ParameterLimit = number; export type ParameterInteger = number; export type ParameterOrderListPromotionTiersClientSide = 'created_at' | '-created_at' | 'updated_at' | '-updated_at'; export type ParameterOrigin = string; export type GetApiClientV1PromotionsTiersArgs = {is_available?: ParameterBoolean | undefined, limit?: ParameterLimit | undefined, page?: ParameterInteger | undefined, order?: ParameterOrderListPromotionTiersClientSide | undefined, origin: ParameterOrigin}; export type GetApiClientV1PromotionsTiersOptions = {baseUrl?: string | undefined, XClientApplicationId?: string | undefined, XClientToken?: string | undefined, fetch?: typeof fetch | undefined}; export const discountAmountVouchersEffectTypes = z.enum(["APPLY_TO_ORDER", "APPLY_TO_ITEMS", "APPLY_TO_ITEMS_PROPORTIONALLY", "APPLY_TO_ITEMS_PROPORTIONALLY_BY_QUANTITY", "APPLY_TO_ITEMS_BY_QUANTITY"]); export const discountUnitVouchersEffectTypes = z.enum(["ADD_MISSING_ITEMS", "ADD_NEW_ITEMS", "ADD_MANY_ITEMS", "ADD_SAME_ITEMS"]); export const simpleProductDiscountUnit = z.object({id: z.string(), source_id: z.string().optional(), name: z.string()}); export const simpleSkuDiscountUnit = z.object({id: z.string(), source_id: z.string().optional(), name: z.string()}); export const discountUnitMultipleOneUnit = z.object({unit_off: z.number().optional(), unit_off_formula: z.string().optional(), effect: z.enum(["ADD_NEW_ITEMS", "ADD_MISSING_ITEMS"]), unit_type: z.string(), product: simpleProductDiscountUnit.optional(), sku: simpleSkuDiscountUnit.optional()}); export const discountPercentVouchersEffectTypes = z.enum(["APPLY_TO_ORDER", "APPLY_TO_ITEMS"]); export const discountFixedVouchersEffectTypes = z.enum(["APPLY_TO_ORDER", "APPLY_TO_ITEMS"]); export const discount = z.union([z.object({type: z.literal("AMOUNT"), amount_off: z.number(), amount_off_formula: z.string().optional(), aggregated_amount_limit: z.number().int().optional(), effect: discountAmountVouchersEffectTypes.optional(), is_dynamic: z.boolean().optional()}), z.object({type: z.literal("UNIT"), unit_off: z.number().int().optional(), unit_off_formula: z.string().optional(), effect: discountUnitVouchersEffectTypes.optional(), unit_type: z.string(), product: simpleProductDiscountUnit.optional(), sku: simpleSkuDiscountUnit.optional(), is_dynamic: z.boolean().optional()}), z.object({type: z.literal("UNIT"), effect: z.literal("ADD_MANY_ITEMS").optional(), units: z.array(discountUnitMultipleOneUnit)}), z.object({type: z.literal("PERCENT"), percent_off: z.number(), percent_off_formula: z.string().optional(), amount_limit: z.number().optional(), aggregated_amount_limit: z.number().int().optional(), effect: discountPercentVouchersEffectTypes.optional(), is_dynamic: z.boolean().optional()}), z.object({type: z.literal("FIXED"), fixed_amount: z.number(), fixed_amount_formula: z.string().optional(), effect: discountFixedVouchersEffectTypes.optional(), is_dynamic: z.boolean().optional()})]); export const validityTimeframe = z.object({duration: z.string().optional(), interval: z.string().optional()}); export const validityDayOfWeek = z.array(z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3), z.literal(4), z.literal(5), z.literal(6)])); export const validityHours = z.object({daily: z.array(z.object({start_time: z.string().optional(), days_of_week: z.array(z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3), z.literal(4), z.literal(5), z.literal(6)])).optional(), expiration_time: z.string().optional()})).optional()}); export const validationRuleAssignment = z.object({id: z.string(), rule_id: z.string(), related_object_id: z.string(), related_object_type: z.enum(["voucher", "campaign", "earning_rule", "reward_assignment", "promotion_tier", "distribution"]), created_at: z.string(), object: z.literal("validation_rules_assignment")}); export const validationRuleAssignmentsList = z.object({object: z.string(), data_ref: z.string(), data: z.array(validationRuleAssignment), total: z.number().int()}); export const category = z.object({id: z.string(), name: z.string(), hierarchy: z.number().int().gte(0), object: z.literal("category"), created_at: z.string(), updated_at: z.string().optional()}); export const promotionTier = z.object({id: z.string().optional(), created_at: z.string().optional(), updated_at: z.string().optional(), name: z.string().optional(), banner: z.string().optional(), action: z.object({discount: discount.optional()}).optional(), metadata: z.object({}).optional(), hierarchy: z.number().int().optional(), promotion_id: z.string().optional(), campaign: z.object({id: z.string().optional(), start_date: z.string().optional(), expiration_date: z.string().optional(), validity_timeframe: validityTimeframe.optional(), validity_day_of_week: validityDayOfWeek.optional(), validity_hours: validityHours.optional(), active: z.boolean().optional(), category_id: z.string().optional(), object: z.string().optional()}).optional(), campaign_id: z.string().optional(), active: z.boolean().optional(), start_date: z.string().optional(), expiration_date: z.string().optional(), validity_timeframe: validityTimeframe.optional(), validity_day_of_week: validityDayOfWeek.optional(), validity_hours: validityHours.optional(), summary: z.object({redemptions: z.object({total_redeemed: z.number().int().optional()}).optional(), orders: z.object({total_amount: z.number().int().optional(), total_discount_amount: z.number().int().optional()}).optional()}).optional(), object: z.string().optional(), validation_rule_assignments: validationRuleAssignmentsList.optional(), category_id: z.string().optional(), categories: z.array(category).optional()}); export const clientPromotionsTiersListResponseBody = z.object({object: z.string().optional(), data_ref: z.string().optional(), tiers: z.array(promotionTier).optional(), total: z.number().int().optional(), has_more: z.boolean().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 }; /** * List Promotion Tiers (client-side) * * GET /client/v1/promotions/tiers * * Also accepts auth: X-Voucherify-OAuth */ export const getApiClientV1PromotionsTiers = async (args: GetApiClientV1PromotionsTiersArgs, options?: GetApiClientV1PromotionsTiersOptions) => { const {baseUrl = "https://api.voucherify.io", fetch: fetchFn = fetch, XClientApplicationId, XClientToken} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.is_available != null) query.append("is_available", String(args.is_available)) if (args.limit != null) query.append("limit", String(args.limit)) if (args.page != null) query.append("page", String(args.page)) if (args.order != null) query.append("order", String(args.order)) if (args.origin != null) headers.set("origin", String(args.origin)) if (XClientApplicationId !== undefined) headers.set("X-Client-Application-Id", XClientApplicationId) if (XClientToken !== undefined) headers.set("X-Client-Token", XClientToken) const url = `${baseUrl.replace(/\/+$/, '')}/client/v1/promotions/tiers${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(clientPromotionsTiersListResponseBody, await res.json()) };