import {z} from 'zod' export type SearchTransactionResourceType = 'company' | 'employee' | 'wallet' | 'card' | 'subscription' | 'onlineAd' | 'purchase'; export type SearchTransactionDateType = 'TRANSACTION' | 'SETTLEMENT' | 'UPDATE' | 'REVIEW_TIME' | 'CUSTOM_EXPORT_TIME'; export type SearchTransactionCategory = 'Billing' | 'Chargeback' | 'Conversion' | 'Fee' | 'FeeReversal' | 'InboundFasterPayment' | 'InboundFasterPaymentReversal' | 'Load' | 'LoadReversal' | 'MileageReimbursement' | 'NotRecognized' | 'Payment' | 'Rebalance' | 'RecurringBilling' | 'Refund' | 'SoldoActivity' | 'SoldoCreditOperation' | 'SoldoDebitOperation' | 'Transfer' | 'Wiretransfer' | 'Withdrawal' | 'InterAccountTransferWithdrawalRecurringBilling' | 'InterAccountTransferWithdrawal' | 'InterAccountTransferDeposit' | 'InterAccountTransferDepositRecurringBilling'; export type TransactionStatus = 'Authorised' | 'Settled' | 'Cancelled' | 'Declined' | 'DisputeFailed' | 'DisputeOpened' | 'DisputeWon' | 'Moved' | 'Unknown'; export type SearchTransactionPaymentMethod = 'USER' | 'COMPANY' | 'PURCHASE' | 'SUBSCRIPTION' | 'ONLINE_ADS' | 'OUT_OF_PLATFORM_COMPANY' | 'OUT_OF_PLATFORM_PERSONAL' | 'WIRETRANSFER' | 'IATS'; export type ExpenseType = 'COMPANY' | 'PERSONAL' | 'TRAVEL_AND_ENTERTAINMENT'; export type ExpenseStatus = 'APPROVED' | 'PARTIALLY_APPROVED' | 'DENIED' | 'TO_REVIEW'; export type ExportStatus = 'EXPORTED' | 'NOT_EXPORTED'; export type SearchTransactionRequiredInformation = 'COMPLETE' | 'NOT_COMPLETE'; export type Direction = 'ASC' | 'DESC'; export type GetApiBusinessV2TransactionsArgs = {type?: SearchTransactionResourceType | undefined, hasAttachment?: boolean | undefined, publicId?: string | undefined, customreferenceId?: string | undefined, fromDate?: string | undefined, toDate?: string | undefined, dateType?: SearchTransactionDateType | undefined, groupId?: string | undefined, category?: Array | undefined, status?: Array | undefined, paymentMethod?: Array | undefined, tagId?: string | undefined, metadataId?: string | undefined, text?: string | undefined, expenseType?: Array | undefined, expenseStatus?: Array | undefined, expenseCategoryId?: Array | undefined, expenseReportId?: Array | undefined, exportStatus?: ExportStatus | undefined, taxRateId?: Array | undefined, businessTripId?: Array | undefined, requiredInformation?: SearchTransactionRequiredInformation | undefined, isSplit?: boolean | undefined, customExportedProduct?: string | undefined, customExported?: boolean | undefined, p?: number | undefined, s?: number | undefined, d?: Direction | undefined, props?: Array | undefined, 'X-Soldo-Fingerprint': string, 'X-Soldo-Fingerprint-Signature': string}; export type GetApiBusinessV2TransactionsOptions = {baseUrl?: string | undefined, standardAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const transactionStatus = z.enum(["Authorised", "Settled", "Cancelled", "Declined", "DisputeFailed", "DisputeOpened", "DisputeWon", "Moved", "Unknown"]); export const transactionCategory = z.enum(["Billing", "Chargeback", "Conversion", "Fee", "FeeReversal", "InboundFasterPayment", "InboundFasterPaymentReversal", "Load", "LoadReversal", "MileageReimbursement", "NotRecognized", "P2P", "Payment", "Rebalance", "RecurringBilling", "Refund", "SoldoActivity", "SoldoCreditOperation", "SoldoDebitOperation", "Transfer", "Wiretransfer", "Withdrawal", "InterAccountTransferWithdrawalRecurringBilling", "InterAccountTransferWithdrawal", "InterAccountTransferDeposit", "InterAccountTransferDepositRecurringBilling"]); export const transactionSign = z.enum(["Negative", "Positive", "None"]); export const iSO4217Currency = z.enum(["AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", "CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MRU", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLE", "SLL", "SOS", "SRD", "SSP", "STD", "STN", "SVC", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "USN", "UYI", "UYU", "UYW", "UZS", "VED", "VEF", "VES", "VND", "VUV", "WST", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XOF", "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX", "YER", "ZAR", "ZMW", "ZWL"]); export const expenseStatus = z.enum(["APPROVED", "PARTIALLY_APPROVED", "DENIED", "TO_REVIEW"]); export const expenseType = z.enum(["COMPANY", "PERSONAL", "TRAVEL_AND_ENTERTAINMENT"]); export const transactionMerchant = z.object({id: z.string().optional(), name: z.string().optional(), raw_name: z.string().optional(), code: z.string().optional(), address: z.string().optional()}); export const transactionMerchantCategory = z.object({description: z.string().optional(), mcc: z.string().optional(), mcc_description: z.string().optional(), code: z.string().optional(), sub_category: z.string().optional()}); export const transactionTag = z.object({id: z.string().optional(), dictionary_id: z.string().optional(), dictionary: z.string().optional(), tag: z.string().optional(), code: z.string().optional(), visible: z.boolean().optional(), description: z.string().optional()}); export const transactionOwnerType = z.enum(["employee", "company"]); export const fuelType = z.enum(["PETROL", "DIESEL", "METHANE", "LPG", "LNG", "ELECTRIC", "UNKNOWN"]); export const transactionFuelDetails = z.object({vehicle_id: z.string().optional(), plate: z.string().optional(), vehicle_fuel_type: fuelType.optional(), vat_deductibility_percentage: z.string().optional(), mileage: z.number().int().optional(), quantity: z.number().optional(), unit_price: z.number().optional(), tx_fuel_type: fuelType.optional(), invoice_id: z.number().int().optional(), invoice_number: z.string().optional(), invoice_date: z.string().optional(), invoice_total_amount: z.number().optional(), invoice_row: z.number().int().optional(), invoice_row_amount: z.number().optional(), supplier_vat_id: z.string().optional(), dri: z.string().optional(), to_be_ignored: z.boolean().optional()}); export const transactionPaymentMethod = z.enum(["USER", "COMPANY", "PURCHASE", "SUBSCRIPTION", "ONLINE_ADS", "OUT_OF_PLATFORM_COMPANY", "OUT_OF_PLATFORM_PERSONAL", "IATS", "WIRETRANSFER"]); export const merchantCategory = z.enum(["Advertising", "Entertainment", "Utilities", "Food_Cocktail_Bar", "Food_Restaurant", "Food_Store", "Food_Wine", "Services_Business", "Services_Cleaning", "Services_Contracted", "Services_Delivery", "Services_Educational", "Services_Financial", "Services_Gambling", "Services_Government", "Services_Health", "Services_Insurance", "Services_Legal", "Services_Museum", "Services_Organisation", "Services_Personal", "Services_Repair", "Services_Social", "Services_Stationery", "Services_Telecommunication", "Services_Veterinary", "Services_Warehouse", "Services_Wholesale", "Shopping_Accessories", "Shopping_Airline", "Shopping_Art", "Shopping_Automotive", "Shopping_Beauty", "Shopping_Books", "Shopping_Clothes", "Shopping_Digital_Goods", "Shopping_Direct_Marketing", "Shopping_Furnitures", "Shopping_Sport", "Shopping_Store", "Shopping_Technology", "Transport_Airports", "Transport_Charging_Station", "Transport_Parking", "Transport_Public_Transportation", "Transport_Road", "Transport_Service_Station", "Transport_Ships", "Transport_Taxi", "Transport_Toll_Roads", "Transport_Trains", "Travel_Airlines", "Travel_Agency", "Travel_Car_Rental", "Travel_Hotels", "Travel_Time_Shares"]); export const expenseCategory = z.object({id: z.string().optional(), code: z.string().optional(), name: z.string().optional(), description: z.string().optional(), tax_rate_id: z.string().optional(), enabled: z.boolean().optional(), merchant_categories: z.array(merchantCategory).optional(), expense_type: z.string().optional(), integration: z.string().optional(), creation_time: z.string().optional(), last_update_time: z.string().optional()}); export const vatRate = z.object({id: z.string().optional(), code: z.string().optional(), name: z.string().optional(), description: z.string().optional(), percentage: z.number().optional(), enabled: z.boolean().optional(), integration: z.string().optional(), creation_time: z.string().optional(), last_update_time: z.string().optional()}); export const transactionCarbonEmissionInfo = z.object({value: z.number().optional(), unit: z.string().optional()}); export const transactionRequiredInformation = z.enum(["COMPLETE", "NOT_COMPLETE"]); export const invoice = z.object({number: z.string().max(50).optional(), date: z.string().optional(), po_number: z.string().max(50).optional(), supplier_vat_number: z.string().max(15).optional()}); export const loadSource = z.enum(["UNSPECIFIED", "BANK_TRANSFER", "CARD", "SISAL_PAY", "FASTER_PAYMENT"]); export const source = z.object({name: z.string().optional(), type: loadSource.optional(), destination_wallet_id: z.string().optional(), destination_wallet_name: z.string().optional()}); export const customExport = z.object({product: z.string().optional(), export_date: z.string().optional()}); export const transactionAmount = z.object({amount: z.number().optional(), currency: iSO4217Currency.optional()}); export const transactionSpendingPolicyMetadata = z.object({approved_amount: transactionAmount.optional(), rejected_amount: transactionAmount.optional()}); export const iSO3166Country = z.enum(["ASC", "AND", "ARE", "AFG", "ATG", "AIA", "ALB", "ARM", "ANT", "AGO", "ATA", "ARG", "ASM", "AUT", "AUS", "ABW", "ALA", "AZE", "BIH", "BRB", "BGD", "BEL", "BFA", "BGR", "BHR", "BDI", "BEN", "BLM", "BMU", "BRN", "BOL", "BES", "BRA", "BHS", "BTN", "BUR", "BVT", "BWA", "BLR", "BLZ", "CAN", "CCK", "COD", "CAF", "COG", "CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CPT", "CRI", "CSXX", "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DGA", "DJI", "DNK", "DMA", "DOM", "DZA", "ECU", "EST", "EGY", "ESH", "ERI", "ESP", "ETH", "FIN", "FJI", "FLK", "FSM", "FRO", "FRA", "FXX", "GAB", "GBR", "GRD", "GEO", "GUF", "GGY", "GHA", "GIB", "GRL", "GMB", "GIN", "GLP", "GNQ", "GRC", "SGS", "GTM", "GUM", "GNB", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN", "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL", "ITA", "JEY", "JAM", "JOR", "JPN", "KEN", "KGZ", "KHM", "KIR", "COM", "KNA", "PRK", "KOR", "KWT", "CYM", "KAZ", "LAO", "LBN", "LCA", "LIE", "LKA", "LBR", "LSO", "LTU", "LUX", "LVA", "LBY", "MAR", "MCO", "MDA", "MNE", "MAF", "MDG", "MHL", "MKD", "MLI", "MMR", "MNG", "MAC", "MNP", "MTQ", "MRT", "MSR", "MLT", "MUS", "MDV", "MWI", "MEX", "MYS", "MOZ", "NAM", "NCL", "NER", "NFK", "NGA", "NIC", "NLD", "NOR", "NPL", "NRU", "NTZ", "NIU", "NZL", "OMN", "PAN", "PER", "PYF", "PNG", "PHL", "PAK", "POL", "SPM", "PCN", "PRI", "PSE", "PRT", "PLW", "PRY", "QAT", "REU", "ROU", "ROM", "SRB", "RUS", "RWA", "SAU", "SLB", "SYC", "SDN", "SWE", "SGP", "SHN", "SVN", "SJM", "SVK", "SLE", "SMR", "SEN", "SOM", "SUR", "SSD", "STP", "SUN", "SLV", "SXM", "SYR", "SWZ", "TAA", "TCA", "TCD", "ATF", "TGO", "THA", "TJK", "TKL", "TLS", "TKM", "TUN", "TON", "TUR", "TTO", "TUV", "TWN", "TZA", "UKR", "UGA", "UMI", "USA", "URY", "UZB", "VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF", "WSM", "XKX", "XXK", "QZZ", "YEM", "MYT", "YUCS", "ZAF", "ZMB", "ZRCD", "ZWE"]); export const transactionItemDetails = z.object({tx_country: iSO3166Country.optional()}); export const entityIdDTO = z.object({id: z.string().optional()}); export const transactionItemSplitInfo = z.object({line_number: z.number().int().optional(), amount: transactionAmount.optional(), vat_amount: transactionAmount.optional(), expense_type: expenseType.optional(), employee: entityIdDTO.optional(), expense_category: entityIdDTO.optional(), tax_rate: entityIdDTO.optional(), tags: z.array(transactionTag).optional(), approved_amount: transactionAmount.optional(), rejected_amount: transactionAmount.optional()}); export const transactionItem = z.object({id: z.string().optional(), wallet_id: z.string().optional(), wallet_name: z.string().optional(), status: transactionStatus.optional(), category: transactionCategory.optional(), transaction_sign: transactionSign.optional(), purchase_id: z.string().optional(), amount: z.number().optional(), amount_currency: iSO4217Currency.optional(), tx_amount: z.number().optional(), tx_amount_currency: iSO4217Currency.optional(), fee_amount: z.number().optional(), fee_currency: iSO4217Currency.optional(), exchange_rate: z.number().optional(), auth_exchange_rate: z.number().optional(), expense_status: expenseStatus.optional(), expense_type: expenseType.optional(), expense_date: z.string().optional(), expense_reviewer: z.string().optional(), expense_approved_amount: z.number().optional(), expense_report_id: z.string().optional(), date: z.string().optional(), settlement_date: z.string().optional(), update_time: z.string().optional(), merchant: transactionMerchant.optional(), merchant_category: transactionMerchantCategory.optional(), tags: z.array(transactionTag).optional(), card_id: z.string().optional(), masked_pan: z.string().optional(), owner_name: z.string().optional(), owner_surname: z.string().optional(), owner_type: transactionOwnerType.optional(), owner_id: z.string().optional(), custom_reference_id: z.string().optional(), group_id: z.string().optional(), has_attachments: z.boolean().optional(), trx_owner_id: z.string().optional(), metadata_ids: z.array(z.string()).optional(), fuel_details: transactionFuelDetails.optional(), vat_percentage: z.number().optional(), vat_amount: z.number().optional(), vat_currency: iSO4217Currency.optional(), user_notes: z.string().optional(), notes: z.string().optional(), direct_url: z.string().optional(), flags: z.array(z.string()).optional(), payment_method: transactionPaymentMethod.optional(), payment_method_id: z.string().optional(), expense_category: expenseCategory.optional(), tax_rate: vatRate.optional(), split: z.boolean().optional(), tx_id: z.string().optional(), payment_trn_code: z.string().optional(), carbon_emissions: transactionCarbonEmissionInfo.optional(), required_information: transactionRequiredInformation.optional(), reimbursement_expense_report_id: z.string().optional(), invoice: invoice.optional(), source: source.optional(), custom_export: z.array(customExport).optional(), out_spending_policy: transactionSpendingPolicyMetadata.optional(), business_trip_id: z.string().optional(), details: transactionItemDetails.optional(), split_transactions: z.array(transactionItemSplitInfo).optional()}); export const transactions = z.object({total: z.number().int().optional(), pages: z.number().int().optional(), page_size: z.number().int().optional(), current_page: z.number().int().optional(), results_size: z.number().int().optional(), results: z.array(transactionItem).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 }; /** * Search Transactions * * GET /business/v2/transactions */ export const getApiBusinessV2Transactions = async (args: GetApiBusinessV2TransactionsArgs, options?: GetApiBusinessV2TransactionsOptions) => { const {baseUrl = "https://api.soldo.com", fetch: fetchFn = fetch, standardAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.type != null) query.append("type", String(args.type)) if (args.hasAttachment != null) query.append("hasAttachment", String(args.hasAttachment)) if (args.publicId != null) query.append("publicId", String(args.publicId)) if (args.customreferenceId != null) query.append("customreferenceId", String(args.customreferenceId)) if (args.fromDate != null) query.append("fromDate", String(args.fromDate)) if (args.toDate != null) query.append("toDate", String(args.toDate)) if (args.dateType != null) query.append("dateType", String(args.dateType)) if (args.groupId != null) query.append("groupId", String(args.groupId)) for (const item of args.category ?? []) query.append("category", String(item)) for (const item of args.status ?? []) query.append("status", String(item)) for (const item of args.paymentMethod ?? []) query.append("paymentMethod", String(item)) if (args.tagId != null) query.append("tagId", String(args.tagId)) if (args.metadataId != null) query.append("metadataId", String(args.metadataId)) if (args.text != null) query.append("text", String(args.text)) for (const item of args.expenseType ?? []) query.append("expenseType", String(item)) for (const item of args.expenseStatus ?? []) query.append("expenseStatus", String(item)) for (const item of args.expenseCategoryId ?? []) query.append("expenseCategoryId", String(item)) for (const item of args.expenseReportId ?? []) query.append("expenseReportId", String(item)) if (args.exportStatus != null) query.append("exportStatus", String(args.exportStatus)) for (const item of args.taxRateId ?? []) query.append("taxRateId", String(item)) for (const item of args.businessTripId ?? []) query.append("businessTripId", String(item)) if (args.requiredInformation != null) query.append("requiredInformation", String(args.requiredInformation)) if (args.isSplit != null) query.append("isSplit", String(args.isSplit)) if (args.customExportedProduct != null) query.append("customExportedProduct", String(args.customExportedProduct)) if (args.customExported != null) query.append("customExported", String(args.customExported)) if (args.p != null) query.append("p", String(args.p)) if (args.s != null) query.append("s", String(args.s)) if (args.d != null) query.append("d", String(args.d)) for (const item of args.props ?? []) query.append("props", String(item)) if (args['X-Soldo-Fingerprint'] != null) headers.set("X-Soldo-Fingerprint", String(args['X-Soldo-Fingerprint'])) if (args['X-Soldo-Fingerprint-Signature'] != null) headers.set("X-Soldo-Fingerprint-Signature", String(args['X-Soldo-Fingerprint-Signature'])) if (standardAuth !== undefined) headers.set('authorization', `Bearer ${standardAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/business/v2/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(transactions, await res.json()) };