import {z} from 'zod' export type CustomFieldFilter = {key: string, operator: 'exact' | 'partial', value: string | Array}; export type PromoterFilters = {revenue_amount?: ({from?: number | undefined, to?: number | undefined}) | undefined, customers_count?: ({from?: number | undefined, to?: number | undefined}) | undefined, referrals_count?: ({from?: number | undefined, to?: number | undefined}) | undefined, clicks_count?: ({from?: number | undefined, to?: number | undefined}) | undefined, joined_at?: ({from?: string | undefined, to?: string | undefined}) | undefined, last_login_at?: ({from?: string | undefined, to?: string | undefined}) | undefined, campaign_id?: (number | Array) | undefined, state?: ('pending' | 'accepted' | 'rejected' | 'blocked' | 'inactive' | 'not_set') | undefined, has_wform?: ('yes' | 'no') | undefined, parent_promoter_id?: number | undefined, archived?: ('true' | 'false' | '`true`' | '`false`' | '`yes`' | '`no`') | undefined, subscribed_to_email?: ('true' | 'false' | '`true`' | '`false`' | '`yes`' | '`no`') | undefined, custom_field1?: CustomFieldFilter | undefined, custom_field2?: CustomFieldFilter | undefined, fraud_suspicions?: (Array<'same_ip_suspicion' | 'same_promoter_email' | 'ad_source' | 'no_suspicion'>) | undefined, inactivity?: ({metric?: ('referral' | 'customer' | 'click' | 'sale') | undefined, days?: number | undefined}) | undefined, invoice_details_status?: ('approved' | 'pending' | 'rejected' | 'not_submitted') | undefined}; export type GetApiPromotersArgs = {'Account-ID': string, q?: string | undefined, 'ids[]'?: Array | undefined, filters?: PromoterFilters | undefined, sorting?: ({clicks_count?: ('asc' | 'desc') | undefined, referrals_count?: ('asc' | 'desc') | undefined, customers_count?: ('asc' | 'desc') | undefined, revenue_amount?: ('asc' | 'desc') | undefined, joined_at?: ('asc' | 'desc') | undefined}) | undefined}; export type GetApiPromotersOptions = {baseUrl?: string | undefined, BearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const promoterProfile = z.object({id: z.number().int().optional(), first_name: z.string().optional(), last_name: z.string().optional(), website: z.string().nullable().optional(), company_name: z.string().nullable().optional(), company_number: z.string().nullable().optional(), phone_number: z.string().nullable().optional(), vat_id: z.string().nullable().optional(), country: z.string().nullable().optional(), address: z.string().nullable().optional(), avatar: z.string().optional(), w8_form_url: z.string().nullable().optional(), w9_form_url: z.string().nullable().optional(), description: z.string().nullable().optional(), invoice_details_validation_errors: z.object({}).nullable().optional(), should_validate_invoice_details: z.boolean().optional(), instagram_url: z.string().nullable().optional(), youtube_url: z.string().nullable().optional(), linkedin_url: z.string().nullable().optional(), facebook_url: z.string().nullable().optional(), twitter_url: z.string().nullable().optional(), twitch_url: z.string().nullable().optional(), tiktok_url: z.string().nullable().optional()}); export const promoterListItem = z.object({id: z.number().int().optional(), email: z.string().optional(), name: z.string().optional(), cust_id: z.string().nullable().optional(), note: z.string().nullable().optional(), stats: z.object({clicks_count: z.number().int().optional(), referrals_count: z.number().int().optional(), sales_count: z.number().int().optional(), customers_count: z.number().int().optional(), revenue_amount: z.number().int().optional(), active_customers_count: z.number().int().optional()}).optional(), is_customized: z.boolean().optional(), fraud_suspicions: z.array(z.string()).optional(), is_confirmed: z.boolean().optional(), invoice_details_status: z.enum(["pending", "approved", "denied"]).optional(), profile: promoterProfile.optional(), joined_at: z.string().optional(), last_login_at: z.string().nullable().optional(), archived_at: z.string().nullable().optional(), custom_fields: z.object({}).nullable().optional(), password_setup_url: z.string().nullable().optional(), first_event_at: z.string().optional(), promoter_campaigns: z.array(z.object({id: z.number().int().optional(), campaign_id: z.number().int().optional(), promoter_id: z.number().int().optional(), state: z.enum(["pending", "accepted", "rejected", "blocked", "inactive", "not_set"]).optional(), created_at: z.string().optional(), campaign: z.object({id: z.number().int().optional(), name: z.string().optional(), color: z.string().optional()}).optional(), coupon: z.string().optional(), ref_token: z.string().optional(), ref_link: z.string().optional()})).optional(), balances: z.object({cash: z.number().nullable().optional(), credits: z.number().nullable().optional(), points: z.number().nullable().optional(), free_months: z.number().nullable().optional(), discount: z.number().nullable().optional()}).optional(), track_ad_traffic: z.boolean().nullable().optional(), auth_provider: z.string().nullable().optional(), selected_payout_method: z.object({id: z.number().int().optional(), method: z.string().optional(), date_added: z.string().optional(), is_disabled: z.boolean().optional()}).nullable().optional()}); export const getApiPromotersResponse = z.object({data: z.array(promoterListItem).optional(), meta: z.object({pending_count: z.number().int().optional()}).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 available promoters * * GET /promoters */ export const getApiPromoters = async (args: GetApiPromotersArgs, options?: GetApiPromotersOptions) => { const {baseUrl = "https://api.firstpromoter.com/api/v2/company", fetch: fetchFn = fetch, BearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args['Account-ID'] != null) headers.set("Account-ID", String(args['Account-ID'])) if (args.q != null) query.append("q", String(args.q)) for (const item of args['ids[]'] ?? []) query.append("ids[]", String(item)) if (args.filters != null) query.append("filters", JSON.stringify(args.filters)) if (args.sorting != null) query.append("sorting", JSON.stringify(args.sorting)) if (BearerAuth !== undefined) headers.set('authorization', `Bearer ${BearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/promoters${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(getApiPromotersResponse, await res.json()) };