import {z} from 'zod' export type UUID = string; export type GetApiV0AccountTransactionsArgs = {accountId: UUID, transactionType?: ('deposit' | 'withdrawal' | 'transfer' | 'yield') | undefined, direction?: ('asc' | 'desc') | undefined, limit?: string | undefined, cursor?: string | undefined, search?: string | undefined}; export type GetApiV0AccountTransactionsOptions = {baseUrl?: string | undefined, basicAuth?: {username: string, password: string} | undefined, fetch?: typeof fetch | undefined}; export const uUID = z.string(); export const shareClassSymbol = z.enum(["EUTBL", "USTBL", "eurUSTBL", "SPKCC", "eurSPKCC", "UKTBL", "eurUKTBL", "SAFO", "SAFOd", "eurSAFO", "eurSAFOd", "gbpSAFO", "gbpSAFOd", "chfSAFO", "sekSAFO", "nokSAFO", "dkkSAFO", "plnSAFO", "hufSAFO", "czkSAFO"]); export const currencyCode = z.enum(["EUR", "USD", "GBP", "CHF", "JPY", "SGD", "SEK", "NOK", "DKK", "PLN", "HUF", "CZK"]); export const nonNegativeAmount = z.object({value: z.string(), currency: currencyCode}); export const day = z.string(); export const amount = z.object({value: z.string(), currency: currencyCode}); export const getApiV0AccountTransactionsResponse = z.object({items: z.array(z.union([z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string().nullable(), netAssetValue: nonNegativeAmount.nullable(), amount: nonNegativeAmount.nullable(), confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, orderType: z.literal("Redemption"), scheduled: z.string().nullable(), shareClassNetAssetValueAtCreation: nonNegativeAmount, exchangeRateAtCreation: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}).nullable(), payoutCurrency: currencyCode.nullable(), bankAccountName: z.string().nullable(), bankAccountNumber: z.string().nullable(), bankAccountBic: z.string().nullable(), recurringWithdrawalScheduleId: uUID.nullable(), status: z.enum(["scheduled-in-shares", "scheduled", "canceled", "created-on-app", "pending-valuation"]), amountAtCreation: nonNegativeAmount, estimatedPayout: nonNegativeAmount.nullable()}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string().nullable(), netAssetValue: nonNegativeAmount, amount: nonNegativeAmount, confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, orderType: z.literal("Redemption"), scheduled: z.string().nullable(), shareClassNetAssetValueAtCreation: nonNegativeAmount, exchangeRateAtCreation: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}).nullable(), payoutCurrency: currencyCode.nullable(), bankAccountName: z.string().nullable(), bankAccountNumber: z.string().nullable(), bankAccountBic: z.string().nullable(), recurringWithdrawalScheduleId: uUID.nullable(), status: z.enum(["pending-execution", "executed"])}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string().nullable(), netAssetValue: nonNegativeAmount.nullable(), amount: nonNegativeAmount, confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, status: z.enum(["pending", "canceled", "executed"]), orderType: z.literal("InstantRedemption"), bankAccountName: z.string().nullable(), bankAccountNumber: z.string().nullable(), bankAccountBic: z.string().nullable()}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string().nullable(), netAssetValue: nonNegativeAmount.nullable(), amount: nonNegativeAmount, confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, status: z.enum(["pending-wire", "canceled", "pending-valuation", "pending-execution", "executed"]), orderType: z.literal("Subscription"), method: z.literal("collection").optional(), wireReference: z.string().nullable(), accountNumber: z.string(), bic: z.string(), intermediaryBic: z.string().nullable(), intermerdiaryBic: z.string().nullable(), bankAccountName: z.string().nullable(), bankAccountNumber: z.string().nullable(), bankAccountBic: z.string().nullable()}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string(), netAssetValue: nonNegativeAmount.nullable(), amount: nonNegativeAmount, confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, status: z.enum(["created-on-app", "pending-execution", "executed", "canceled", "failed"]), orderType: z.literal("TransferFrom"), toInvestorName: z.string()}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string(), netAssetValue: nonNegativeAmount.nullable(), amount: nonNegativeAmount, confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, status: z.enum(["created-on-app", "pending-execution", "executed", "canceled", "failed"]), orderType: z.literal("TransferTo"), fromInvestorName: z.string()}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string().nullable(), netAssetValue: nonNegativeAmount.nullable(), amount: nonNegativeAmount.nullable(), confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, orderType: z.literal("FundSwapTransferFrom"), status: z.enum(["pending-redemption", "pending-subscription", "pending-subscription-execution", "executed", "canceled"]), toAccountName: z.string(), toAccountId: uUID, toShareClassId: uUID, fundSwapFields: z.object({sourceAmount: nonNegativeAmount, targetAmount: nonNegativeAmount})}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string().nullable(), netAssetValue: nonNegativeAmount.nullable(), amount: nonNegativeAmount.nullable(), confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, orderType: z.literal("FundSwapTransferTo"), status: z.enum(["pending-redemption", "pending-subscription", "pending-subscription-execution", "executed", "canceled"]), fromAccountName: z.string(), fromAccountId: uUID, fromShareClassId: uUID, fundSwapFields: z.object({sourceAmount: nonNegativeAmount, targetAmount: nonNegativeAmount})}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string(), netAssetValue: nonNegativeAmount.nullable(), amount: nonNegativeAmount.nullable(), confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, status: z.enum(["created", "pending-execution", "executed", "canceled"]), orderType: z.literal("SharesWithdrawal")}), z.object({createdAt: z.string(), shareClassId: uUID, shareClassSymbol: shareClassSymbol, shareDecimals: z.number().int().gte(-9007199254740991).lte(9007199254740991), accountId: uUID, sharesAmount: z.string().nullable(), netAssetValue: nonNegativeAmount.nullable(), amount: amount, confirmedAt: z.string().nullable(), applicableExchangeRateConversion: z.object({exchangeRate: z.object({fundId: uUID, day: day, baseCurrency: currencyCode, quoteCurrency: currencyCode, fxRate: z.string()}), convertedAmount: nonNegativeAmount}).nullable(), id: uUID, orderType: z.literal("Yield"), status: z.literal("executed"), yieldNavId: uUID, yieldDay: day})])), nextCursor: z.string().nullable(), hasMore: z.boolean()}); 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 account transaction history * * GET /v0/account-transactions/ */ export const getApiV0AccountTransactions = async (args: GetApiV0AccountTransactionsArgs, options?: GetApiV0AccountTransactionsOptions) => { const {baseUrl = "https://distributor-api.spiko.io", fetch: fetchFn = fetch, basicAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.accountId != null) query.append("accountId", String(args.accountId)) if (args.transactionType != null) query.append("transactionType", String(args.transactionType)) if (args.direction != null) query.append("direction", String(args.direction)) if (args.limit != null) query.append("limit", String(args.limit)) if (args.cursor != null) query.append("cursor", String(args.cursor)) if (args.search != null) query.append("search", String(args.search)) if (basicAuth !== undefined) headers.set('authorization', `Basic ${btoa(`${basicAuth.username}:${basicAuth.password}`)}`) const url = `${baseUrl.replace(/\/+$/, '')}/v0/account-transactions/${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(getApiV0AccountTransactionsResponse, await res.json()) };