import {z} from 'zod' export type GetApiBatchesCardEnrichmentBatchIdResultsOptions = {baseUrl?: string | undefined, ApiKeyAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const thirdParty = z.object({id: z.string().optional(), name: z.string().max(64).optional(), type: z.enum(["bnpl", "delivery_service", "marketplace", "payment_processor", "platform"]).optional(), logo: z.string().max(128).nullable().optional(), website: z.string().max(256).nullable().optional()}); export const industryCategoryLevel = z.object({id: z.string().max(15).optional(), name: z.string().max(64).optional(), icon: z.string().max(128).nullable().optional()}); export const responseLocation = z.object({id: z.string().nullable().optional(), address: z.string().max(64).nullable().optional(), addressLine1: z.string().max(64).nullable().optional(), addressLine2: z.string().max(32).nullable().optional(), city: z.string().max(64).nullable().optional(), region: z.string().max(64).nullable().optional(), country: z.string().max(3).nullable().optional(), postalCode: z.string().max(12).nullable().optional(), latitude: z.number().nullable().optional(), longitude: z.number().nullable().optional(), phoneNumber: z.string().max(24).nullable().optional(), matchScore: z.number().nullable().optional()}); export const counterparty = z.object({id: z.string().nullable().optional(), name: z.string().max(64).nullable().optional(), legalName: z.string().max(128).nullable().optional(), industry: z.array(industryCategoryLevel).optional(), matchScore: z.number().nullable().optional(), location: z.array(responseLocation).optional(), logo: z.string().max(128).nullable().optional(), phoneNumber: z.string().max(24).nullable().optional(), website: z.string().max(256).nullable().optional(), possibleCounterpartyAlternate: z.object({id: z.string().optional(), similarity: z.number().optional()}).nullable().optional()}); export const mobileAppInfo = z.object({id: z.string().optional(), name: z.string().max(512).optional(), url: z.string().nullable().optional(), logo: z.string().nullable().optional(), developerName: z.string().max(256).optional(), developerId: z.string().optional(), category: z.enum(["Auto and Transportation", "Creative and Design", "Education and Parenting", "Entertainment and Media", "Finance and Business", "Games", "Health and Lifestyle", "Shopping and Marketplaces", "Social and Communication", "Travel and Events", "Utility and Tools"]).optional(), hasGamblingOrRewards: z.boolean().optional(), hasSimulatedGambling: z.boolean().optional(), ageRating: z.enum(["Children", "Teen", "Adult", "Unknown"]).optional()}).nullable(); export const customAttributesResponseField = z.record(z.string(), z.string()); export const triggeredActionResponse = z.object({id: z.string().max(512).optional(), type: z.enum(["merchant_trigger", "category_trigger"]).optional(), action: z.object({authRecommendation: z.enum(["ALLOW", "BLOCK"]).optional()}).and(z.record(z.string(), z.unknown())).optional(), scope: z.enum(["account", "program", "user", "card"]).optional(), source: z.enum(["counterparty", "third_party", "null"]).nullable().optional(), categoryId: z.string().optional(), categoryName: z.string().optional()}); export const batchCardEnrichmentResponse = z.object({transactionInfo: z.object({transferInfo: z.object({direction: z.enum(["outgoing", "incoming"]).max(12).optional(), transferMethod: z.enum(["ach", "cash", "check", "intrabank", "rtp", "unknown", "wire"]).max(12).optional(), transferType: z.enum(["external", "internal", "unknown"]).max(12).optional(), isAdjustmentOrRefund: z.boolean().optional()}).nullable().optional(), isAccountVerification: z.boolean().nullable().optional(), isPeerToPeer: z.boolean().nullable().optional(), isDigitalWallet: z.boolean().nullable().optional(), type: z.enum(["account_verification", "atm", "debt", "fee", "income", "other_money_movement", "reimbursement", "spending"]).optional(), subType: z.enum(["alimony_or_child_support", "atm", "bnpl", "business", "cash_advance", "deposit", "disbursements", "earned_income", "government_benefits", "insurance", "investment", "nsf", "other", "overdraft", "payment", "payout", "rental", "retirement", "tax_refund", "transfer", "withdrawal"]).nullable().optional(), display: z.object({name: z.string().max(64).optional(), categoryName: z.string().max(64).nullable().optional(), graphic: z.string().max(128).nullable().optional(), graphicSource: z.enum(["counterparty", "third_party", "category"]).max(16).nullable().optional()}).nullable().optional(), thirdParties: z.array(thirdParty).optional(), spendingInfo: z.object({channel: z.object({value: z.enum(["digital", "physical", "null"]).nullable().optional()}).optional()}).nullable().optional(), atmInfo: z.object({sponsorName: z.string().max(64).optional(), ownerName: z.string().max(64).optional()}).nullable().optional(), transactionId: z.string().max(512).optional(), recurrenceInfo: z.object({intervalType: z.enum(["weekly", "biweekly", "semi_monthly", "monthly", "quarterly", "annually"]).max(12).nullable().optional(), intervalDays: z.number().int().nullable().optional(), nextPaymentExpected: z.string().max(10).nullable().optional(), recentRecurrences: z.array(z.array(z.unknown())).nullable().optional()}).nullable().optional(), riskInsights: z.object({irregularWebPresenceDetected: z.boolean().nullable().optional(), negativeOnlineSentiment: z.boolean().nullable().optional(), highRiskEntity: z.boolean().nullable().optional(), riskyIndustry: z.boolean().nullable().optional(), cardAcceptanceHistory: z.enum(["extensive", "established", "stable", "limited", "very_limited", "null"]).nullable().optional()}).nullable().optional()}).optional(), enrichmentId: z.string().optional(), counterparty: z.array(counterparty).optional(), mobileAppInfo: mobileAppInfo.optional(), customAttributes: customAttributesResponseField.optional(), actions: z.array(triggeredActionResponse).nullable().optional(), statusCode: z.number().int().optional(), errors: z.object({}).optional()}); export const getApiBatchesCardEnrichmentBatchIdResultsResponse = z.object({results: z.array(batchCardEnrichmentResponse).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 the results of a batch card enrichment job * * GET /batches/{cardEnrichmentBatchId}/results */ export const getApiBatchesCardEnrichmentBatchIdResults = async (options?: GetApiBatchesCardEnrichmentBatchIdResultsOptions) => { const {baseUrl = "https://east.sandbox.spade.com", fetch: fetchFn = fetch, ApiKeyAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (ApiKeyAuth !== undefined) headers.set("X-Api-Key", ApiKeyAuth) const url = `${baseUrl.replace(/\/+$/, '')}/batches/${encodeURIComponent(String(args.cardEnrichmentBatchId))}/results${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(getApiBatchesCardEnrichmentBatchIdResultsResponse, await res.json()) };