import {z} from 'zod' export type CardExpiry = {month: string, year: string}; export type NetworkTokenExpiry = {month: string, year: string}; export type ExternalCustomerReference = string; export type CreateApiInsightsCardsArgs = {body: {card?: ({number: string, expiry?: CardExpiry | undefined, cvv?: string | undefined}) | undefined, networkToken?: ({number: string, cryptogram: string, expiry: NetworkTokenExpiry, transactionIdentifier?: string | undefined, brand?: ('visa' | 'mastercard' | 'amex' | 'discover') | undefined, funding?: ('credit' | 'debit' | 'prepaid') | undefined, eci?: string | undefined}) | undefined, extensions?: (Array<'capabilities' | 'fees' | 'cvv' | 'cardholder' | 'address' | 'email' | 'phone' | 'paymentAccountReference'>) | undefined, cardholder?: ({firstName?: string | undefined, lastName?: string | undefined, middleName?: string | undefined, suffix?: string | undefined, ownerType?: ('primary' | 'secondary') | undefined}) | undefined, email?: string | undefined, phone?: string | undefined, address?: ({postalCode: string, line1?: string | undefined, line2?: string | undefined, city?: string | undefined, state?: unknown | undefined, country?: unknown | undefined}) | undefined, externalCustomerReference?: ExternalCustomerReference | undefined}}; export type CreateApiInsightsCardsOptions = {baseUrl?: string | undefined, ApiKey?: {username: string, password: string} | undefined, fetch?: typeof fetch | undefined}; export const cardBrand = z.enum(["visa", "mastercard", "american-express", "discover", "diners-club", "jcb", "unionpay"]); export const cardFunding = z.enum(["debit", "credit", "prepaid", "deferred-debit", "charge"]); export const cardSegment = z.enum(["consumer", "commercial", "business", "government", "payouts", "all"]); export const cardFastFunds = z.object({domestic: z.boolean().optional(), crossBorder: z.boolean().optional()}); export const cardThreeDSMetadata = z.object({supportedVersions: z.object({accessControlServer: z.array(z.string()).optional(), directoryServer: z.array(z.string()).optional()}), acsInfoIndicators: z.array(z.object({code: z.string().optional(), indicator: z.string(), description: z.string().optional()})).optional()}); export const cardInsightCapabilities = z.object({enabled: z.boolean().optional(), network: z.string().optional(), type: z.string().optional(), availability: z.enum(["immediate", "next-day", "next-few"]).optional(), regulated: z.boolean().optional(), currency: z.object({alphaCode: z.string(), numericCode: z.string()}).optional(), country: z.object({alphaCode: z.string(), numericCode: z.string()}).optional()}); export const cardInsightCardholder = z.object({result: z.object({value: z.enum(["M", "N", "U"]), code: z.enum(["match-performed", "no-match-performed", "unsupported"])}).optional(), fullName: z.object({value: z.enum(["M", "P", "N", "U"]), code: z.enum(["match", "partial-match", "no-match", "unsupported"])}).optional(), firstName: z.object({value: z.enum(["M", "P", "N", "U"]), code: z.enum(["match", "partial-match", "no-match", "unsupported"])}).optional(), lastName: z.object({value: z.enum(["M", "P", "N", "U"]), code: z.enum(["match", "partial-match", "no-match", "unsupported"])}).optional()}); export const cardInsightAddress = z.object({networkIdentifier: z.string().optional(), networkResponseCode: z.object({code: z.string().nullable().optional(), value: z.string().optional()}).optional(), result: z.object({value: z.string(), address: z.enum(["match", "no-match", "unknown", "unavailable"]), zip: z.enum(["match", "no-match", "unknown", "unavailable"])}).optional()}); export const cardInsight = z.object({id: z.string(), fingerprint: z.string().optional(), bin: z.object({brand: cardBrand.optional(), funding: cardFunding.optional(), segment: cardSegment.optional(), country: z.string().optional(), currency: z.string().optional(), issuer: z.string().optional(), type: z.enum(["null", "card", "network-token"]).nullable().optional(), productName: z.string().optional(), fastFunds: cardFastFunds.optional(), matchPrecision: z.number().optional(), threeDS: cardThreeDSMetadata.optional()}).optional(), capabilities: z.object({push: cardInsightCapabilities.optional(), pull: cardInsightCapabilities.optional()}).optional(), fees: z.unknown(), cardholder: cardInsightCardholder.optional(), address: cardInsightAddress.optional(), cvv: z.object({value: z.string(), code: z.string()}).optional(), email: z.object({value: z.enum(["1", "2", "3", "U"]), code: z.enum(["match", "no-match", "not-performed", "unable-to-verify"])}).optional(), phone: z.object({value: z.enum(["1", "2", "3", "U"]), code: z.enum(["match", "no-match", "not-performed", "unable-to-verify"])}).optional(), paymentAccountReference: z.string().optional(), createdAt: z.number().int()}); 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 }; /** * Card Insights * * POST /insights/cards */ export const createApiInsightsCards = async (args: CreateApiInsightsCardsArgs, options?: CreateApiInsightsCardsOptions) => { const {baseUrl = "https://api.evervault.com", fetch: fetchFn = fetch, ApiKey} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (ApiKey !== undefined) headers.set('authorization', `Basic ${btoa(`${ApiKey.username}:${ApiKey.password}`)}`) const url = `${baseUrl.replace(/\/+$/, '')}/insights/cards${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(cardInsight, await res.json()) };