import {z} from 'zod' export type GetApiEndUsersEndUserIdDocumentsArgs = {end_user_id: string, type?: 'direct_deposit_form' | undefined, 'Pinwheel-Version': '2025-07-08' | '2023-11-22' | '2023-07-18' | '2023-04-18' | '2022-09-09' | '2022-06-22' | '2022-03-02'}; export type GetApiEndUsersEndUserIdDocumentsOptions = {baseUrl?: string | undefined, apiSecret?: string | undefined, fetch?: typeof fetch | undefined}; export const paginationMeta = z.object({count: z.number().int().optional(), next_cursor: z.string().optional()}); export const documentObjPublicResponseItem = z.object({id: z.string(), download_url: z.string().optional(), download_url_expiration: z.string().optional()}); export const uploadedEarning = z.object({type: z.string().optional(), description: z.string().optional(), amount: z.number().int().optional(), amount_ytd: z.number().int().optional()}); export const uploadedTax = z.object({type: z.string().optional(), description: z.string().optional(), amount: z.number().int().optional(), amount_ytd: z.number().int().optional()}); export const uploadedDeduction = z.object({type: z.string().optional(), description: z.string().optional(), amount: z.number().int().optional(), amount_ytd: z.number().int().optional()}); export const addressGetResponseItem = z.object({raw: z.string(), line1: z.string().optional(), line2: z.string().optional(), city: z.string().optional(), state: z.string().optional(), postal_code: z.string().optional(), country: z.literal("US").optional()}); export const employerNameAndAddress = z.object({name: z.string().optional(), address: addressGetResponseItem.optional()}); export const employeeNameAndAddress = z.object({name: z.string().optional(), address: addressGetResponseItem.optional()}); export const uploadedTimeOff = z.object({name: z.string().optional(), category: z.enum(["pto", "sick", "other"]).optional(), available_hours: z.number().optional(), earned_hours: z.number().optional(), used_hours: z.number().optional()}); export const uploadedPaystub = z.object({document_type: z.literal("paystub").optional(), pay_date: z.string().optional(), pay_period_start: z.string().optional(), pay_period_end: z.string().optional(), gross_pay_amount: z.number().int().optional(), gross_pay_ytd: z.number().int().optional(), net_pay_amount: z.number().int().optional(), net_pay_ytd: z.number().int().optional(), earnings: z.array(uploadedEarning).optional(), taxes: z.array(uploadedTax).optional(), deductions: z.array(uploadedDeduction).optional(), employer: employerNameAndAddress.optional(), employee: employeeNameAndAddress.optional(), time_off: z.array(uploadedTimeOff).optional()}); export const applicantNameAndAddress = z.object({name: z.string().optional(), address: addressGetResponseItem.optional()}); export const bankAccountTransaction = z.object({date: z.string().optional(), description: z.string().optional(), amount: z.union([z.number(), z.string()]).optional(), base_type: z.string().optional(), type: z.string().optional()}); export const bankAccount = z.object({account_number: z.union([z.number(), z.string()]).optional(), account_name: z.string().optional(), bank_account_type: z.string().optional(), is_joint_account: z.boolean().optional(), total_deposits: z.union([z.number(), z.string()]).optional(), beginning_balance: z.union([z.number(), z.string()]).optional(), ending_balance: z.union([z.number(), z.string()]).optional(), transactions: z.array(bankAccountTransaction).optional()}); export const uploadedBankStatement = z.object({document_type: z.literal("bank_statement").optional(), bank_name: z.string().optional(), statement_begin_date: z.string().optional(), statement_end_date: z.string().optional(), statement_holders: z.array(z.string()).optional(), applicant1: applicantNameAndAddress.optional(), applicant2: applicantNameAndAddress.optional(), accounts: z.array(bankAccount).optional()}); export const uploadedSSIAwardLetter = z.object({document_type: z.literal("ssi_award_letter").optional(), applicant: applicantNameAndAddress.optional(), issue_date: z.string().optional(), pay_date: z.string().optional(), social_security_payment: z.number().int().optional(), social_security_deduction: z.number().int().optional(), social_security_net_payment: z.number().int().optional(), supplemental_security_payment: z.number().int().optional()}); export const uploadedW2Informed = z.object({document_type: z.literal("w2").optional(), applicant: applicantNameAndAddress.optional(), employer_name: z.string().optional(), total_wages: z.union([z.number(), z.string()]).optional(), state_wages: z.union([z.number(), z.string()]).optional(), social_security_wages: z.union([z.number(), z.string()]).optional(), medicare_wages: z.union([z.number(), z.string()]).optional(), federal_taxes: z.union([z.number(), z.string()]).optional(), state_taxes: z.union([z.number(), z.string()]).optional(), social_security_taxes: z.union([z.number(), z.string()]).optional(), medicare_taxes: z.union([z.number(), z.string()]).optional(), tax_year: z.string().optional()}); export const fieldWarning = z.object({field: z.string(), status: z.literal("unparsable"), message: z.string()}); export const sharedFraud = z.object({status: z.enum(["suspected", "not_suspected", "unavailable"])}); export const endUserDocumentObjResponse = z.object({id: z.string(), created_at: z.string(), end_user_id: z.string(), document: documentObjPublicResponseItem, document_type: z.enum(["paystub", "W-2", "1099", "direct_deposit_form", "verification_report", "1040", "bank_statement", "ssi_award_letter", "w2", "verification_photo"]), parsed_data: z.discriminatedUnion("document_type", [uploadedPaystub, uploadedBankStatement, uploadedSSIAwardLetter, uploadedW2Informed]).optional(), warnings: z.array(fieldWarning).optional(), fraud: sharedFraud.optional()}); export const getApiEndUsersEndUserIdDocumentsResponse = z.object({meta: paginationMeta, data: z.array(endUserDocumentObjResponse)}); 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 }; /** * List Documents * * GET /end_users/{end_user_id}/documents */ export const getApiEndUsersEndUserIdDocuments = async (args: GetApiEndUsersEndUserIdDocumentsArgs, options?: GetApiEndUsersEndUserIdDocumentsOptions) => { const {baseUrl = "https://api.getpinwheel.com/v1", fetch: fetchFn = fetch, apiSecret} = 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['Pinwheel-Version'] != null) headers.set("Pinwheel-Version", String(args['Pinwheel-Version'])) if (apiSecret !== undefined) headers.set("X-API-SECRET", apiSecret) const url = `${baseUrl.replace(/\/+$/, '')}/end_users/${encodeURIComponent(String(args.end_user_id))}/documents${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(getApiEndUsersEndUserIdDocumentsResponse, await res.json()) };