import {z} from 'zod' export type V2RegulatorInformation = {regulatorName?: string | undefined, regulatorJurisdiction?: string | undefined, regulatorRegisterNumber?: string | undefined}; export type V2PublicInformation = {listedExchange?: string | undefined, tickerSymbol?: string | undefined}; export type V2AssociatePerson = {firstName: string, lastName: string, dateOfBirth: string, nationality?: string | undefined, secondNationality?: string | undefined, birthCountryCode?: string | undefined, address: {addressLine1: string, addressLine2?: string | undefined, city: string, postalCode: string, stateCode?: string | undefined, countryCode: string}, contactInfo?: ({emailAddress?: string | undefined, phoneNumber?: string | undefined}) | undefined, taxIdentification: {number: string, taxResidenceCountryCode: string}, position?: string | undefined, estimatedYearlyIncome?: ('INCOME_0_TO_50K' | 'INCOME_50K_TO_100K' | 'INCOME_100K_TO_250K' | 'INCOME_250K_TO_500K' | 'INCOME_500K_TO_750K' | 'INCOME_750K_TO_1M' | 'INCOME_ABOVE_1M') | undefined, controlOptions?: {canAppointDirectors: boolean, hasSignificantControl: boolean, controlsManagement: boolean, controlsCorporateBody: boolean} | undefined, reliance?: ({identityDocumentMetadata?: ({type: 'PASSPORT' | 'ID_CARD' | 'DRIVERS' | 'RESIDENCE_PERMIT' | 'OTHER', number: string, issueDate?: string | undefined, expiryDate?: string | undefined, issuingCountryCode: string, kycTimestamp: string}) | undefined, biometricLiveness?: {livenessTimestamp: string} | undefined, addressVerification: {type: 'DOC' | 'NON_DOC'}, attestation: {riskScore: 'LOW' | 'MEDIUM' | 'HIGH', eddCompleted: boolean}}) | undefined}; export type V2CorporateCustomerAssociate = {id?: string | undefined, person: V2AssociatePerson, titles: Array<'UBO' | 'BUSINESS_OWNER' | 'CONTROL_PERSON' | 'SIGNATORY' | 'DIRECTOR' | 'ACCOUNT_REPRESENTATIVE'>, ownership?: ({percentage: unknown, type: 'DIRECT' | 'INDIRECT'}) | undefined}; export type V2CompanyCustomerDueDiligence = {intendedUseOfAccount?: ('SUPPLIER_VENDOR_PAYMENTS' | 'INTERCOMPANY_TRANSFERS' | 'PAYROLL' | 'CUSTOMER_PAYMENTS_RECEIVED' | 'CUSTOMER_PAYOUTS_REFUNDS_SETTLEMENTS' | 'OPERATING_EXPENSES' | 'DIVIDEND_PROFIT_DISTRIBUTIONS' | 'LOAN_REPAYMENT_FINANCIAL_ACTIVITIES') | undefined, pepStatus?: ('NOT_PEP' | 'FORMER_PEP_2_YEARS' | 'FORMER_PEP_OLDER' | 'DOMESTIC_PEP' | 'FOREIGN_PEP' | 'CLOSE_ASSOCIATES' | 'FAMILY_MEMBERS' | 'STATE_OWNED') | undefined, expectedMonthlyVolume?: ({amount: number, currency?: ('USD' | 'EUR') | undefined}) | undefined}; export type V2CompanyRelianceMetadata = {attestation: {riskScore: 'LOW' | 'MEDIUM' | 'HIGH', eddCompleted: boolean}}; export type V2CreateCompanyRequest = {name: string, entityType: 'CORPORATION' | 'LIMITED_LIABILITY_COMPANY' | 'PUBLICLY_LISTED_COMPANY' | 'SOLE_PROPRIETOR' | 'PARTNERSHIP' | 'TRUST', taxIdentification?: {number: string, taxResidenceCountryCode: string} | undefined, registrationNumber: string, businessProfile: {description?: string | undefined, naicsCode: string, monthlyExpectedVolumes: 'FROM_0_TO_10K' | 'FROM_10K_TO_50K' | 'FROM_50K_TO_100K' | 'FROM_100K_TO_1M' | 'FROM_1M_TO_10M' | 'ABOVE_10M', website?: string | undefined, websiteExplanation?: string | undefined, isRegulated?: boolean | undefined, regulatorInformation?: V2RegulatorInformation | undefined, isPubliclyListed?: boolean | undefined, publicInformation?: V2PublicInformation | undefined, sourceOfFunds?: ('COMMERCIAL_ACTIVITIES' | 'SHAREHOLDER_CAPITAL' | 'VENTURE_CAPITAL' | 'SALE_OF_ASSETS' | 'CRYPTO_FUNDRAISING' | 'CRYPTO_TRADING_REVENUE' | 'CORPORATE_LOANS' | 'SALARY' | 'PENSION' | 'SAVINGS' | 'SELF_EMPLOYMENT' | 'GAMBLING' | 'REAL_ESTATE' | 'OTHER') | undefined, intendedUseOfAccount?: ('SUPPLIER_VENDOR_PAYMENTS' | 'INTERCOMPANY_TRANSFERS' | 'PAYROLL' | 'CUSTOMER_PAYMENTS_RECEIVED' | 'CUSTOMER_PAYOUTS_REFUNDS_SETTLEMENTS' | 'OPERATING_EXPENSES' | 'DIVIDEND_PROFIT_DISTRIBUTIONS' | 'LOAN_REPAYMENT_FINANCIAL_ACTIVITIES') | undefined}, address: {addressLine1: string, addressLine2?: string | undefined, city: string, postalCode: string, stateCode?: string | undefined, countryCode: string}, isOperationalAddressDifferent?: boolean | undefined, operationalAddress?: ({addressLine1?: string | undefined, addressLine2?: string | undefined, city?: string | undefined, postalCode?: string | undefined, stateCode?: string | undefined, countryCode?: string | undefined}) | undefined, incorporationDate: string, associates?: Array | undefined, cdd?: V2CompanyCustomerDueDiligence | undefined, reliance?: V2CompanyRelianceMetadata | undefined}; export type V2IndividualDocumentInfo = {number?: string | undefined, type?: ('PASSPORT' | 'ID_CARD' | 'DRIVERS' | 'RESIDENCE_PERMIT' | 'OTHER') | undefined, issuingCountryCode?: string | undefined}; export type V2PersonRelianceMetadata = {identityDocumentMetadata?: ({type: 'PASSPORT' | 'ID_CARD' | 'DRIVERS' | 'RESIDENCE_PERMIT' | 'OTHER', number: string, issueDate?: string | undefined, expiryDate?: string | undefined, issuingCountryCode: string, kycTimestamp: string}) | undefined, biometricLiveness?: {livenessTimestamp: string} | undefined, addressVerification: {type: 'DOC' | 'NON_DOC'}, attestation: {riskScore: 'LOW' | 'MEDIUM' | 'HIGH', eddCompleted: boolean}}; export type V2CreateIndividualRequest = {firstName: string, lastName: string, emailAddress: string, phoneNumber?: string | undefined, description?: string | undefined, dateOfBirth: string, placeOfBirth?: string | undefined, birthCountryCode?: string | undefined, nationality?: string | undefined, documentNumber?: string | undefined, documentInfo?: V2IndividualDocumentInfo | undefined, address: {addressLine1: string, addressLine2?: string | undefined, city: string, postalCode: string, stateCode?: string | undefined, countryCode: string}, taxIdentification: {number: string, taxResidenceCountryCode: string}, cdd?: ({employmentStatus?: ('SALARIED' | 'SELF_EMPLOYED' | 'UNEMPLOYED' | 'RETIRED' | 'STUDENT' | 'NOT_PROVIDED') | undefined, sourceOfFunds?: ('SALARY' | 'PENSION' | 'SAVINGS' | 'SELF_EMPLOYMENT' | 'CRYPTO_TRADING' | 'GAMBLING' | 'REAL_ESTATE' | 'GIFT' | 'STUDENT_LOAN_GRANT') | undefined, pepStatus?: ('NOT_PEP' | 'FORMER_PEP_2_YEARS' | 'FORMER_PEP_OLDER' | 'DOMESTIC_PEP' | 'FOREIGN_PEP' | 'CLOSE_ASSOCIATES' | 'FAMILY_MEMBERS' | 'STATE_OWNED') | undefined, intendedUseOfAccount?: ('TRANSFERS_OWN_WALLET' | 'TRANSFERS_FAMILY_FRIENDS' | 'INVESTMENTS' | 'GOODS_SERVICES' | 'DONATIONS') | undefined, expectedMonthlyVolume?: ({amount: number, currency?: ('USD' | 'EUR') | undefined}) | undefined, estimatedYearlyIncome?: ('INCOME_0_TO_50K' | 'INCOME_50K_TO_100K' | 'INCOME_100K_TO_250K' | 'INCOME_250K_TO_500K' | 'INCOME_500K_TO_750K' | 'INCOME_750K_TO_1M' | 'INCOME_ABOVE_1M') | undefined, employmentIndustrySector?: ('INVESTMENT' | 'HEDGE_FUND' | 'MONEY_SERVICE_BUSINESS' | 'STO_ISSUER' | 'PRECIOUS_METALS' | 'NON_PROFIT' | 'REGISTERED_INVESTMENT_ADVISOR' | 'AGRICULTURE_FORESTRY_FISHING_HUNTING' | 'MINING' | 'UTILITIES' | 'CONSTRUCTION' | 'MANUFACTURING' | 'WHOLESALE_TRADE' | 'RETAIL_TRADE' | 'TRANSPORTATION_WAREHOUSING' | 'INFORMATION' | 'FINANCE_INSURANCE' | 'REAL_ESTATE_RENTAL_LEASING' | 'PROFESSIONAL_SCIENTIFIC_TECHNICAL_SERVICES' | 'MANAGEMENT_OF_COMPANIES_ENTERPRISES' | 'ADMINISTRATIVE_SUPPORT_WASTE_MANAGEMENT_REMEDIATION_SERVICES' | 'EDUCATIONAL_SERVICES' | 'HEALTH_CARE_SOCIAL_ASSISTANCE' | 'ARTS_ENTERTAINMENT_RECREATION' | 'ACCOMMODATION_FOOD_SERVICES' | 'OTHER_SERVICES' | 'PUBLIC_ADMINISTRATION' | 'NOT_CLASSIFIED' | 'ADULT_ENTERTAINMENT' | 'AUCTIONS' | 'AUTOMOBILES' | 'BLOCKCHAIN' | 'CRYPTO' | 'DRUGS' | 'EXPORT_IMPORT' | 'E_COMMERCE' | 'FINANCIAL_INSTITUTION' | 'GAMBLING' | 'INSURANCE' | 'MARKET_MAKER' | 'SHELL_BANK' | 'TRAVEL_TRANSPORT' | 'WEAPONS') | undefined}) | undefined, reliance?: V2PersonRelianceMetadata | undefined}; export type V2CreateCustomerRequest = {useCase: 'FIAT' | 'CRYPTO' | 'STABLECOIN_PAYOUTS' | 'EMBEDDED_STABLECOIN_WALLETS' | 'EMBEDDED_FIAT_ACCOUNTS', reference?: string | undefined, model?: 'RELIANCE' | undefined, company: V2CreateCompanyRequest} | {useCase: 'FIAT' | 'CRYPTO' | 'STABLECOIN_PAYOUTS' | 'EMBEDDED_STABLECOIN_WALLETS' | 'EMBEDDED_FIAT_ACCOUNTS', reference?: string | undefined, model?: 'RELIANCE' | undefined, individual: V2CreateIndividualRequest}; export type CreateApiPlatformV2CustomersArgs = {'Idempotency-Key'?: string | undefined, body: V2CreateCustomerRequest}; export type CreateApiPlatformV2CustomersOptions = {baseUrl?: string | undefined, BearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const v2AuthenticatedLinkResponse = z.object({link: z.string().optional(), expiresAt: z.string().optional()}); export const v2RequiredActionTargetAgreement = z.object({kind: z.literal("AGREEMENT").optional(), assignedAgreementId: z.string().optional(), urn: z.string().optional(), version: z.string().optional(), title: z.string().optional(), locale: z.string().optional()}); export const v2RequiredActionTargetDocument = z.object({kind: z.literal("DOCUMENT").optional(), docSetType: z.string().optional(), types: z.array(z.string()).optional(), subTypes: z.array(z.string()).optional(), associateId: z.string().optional()}); export const v2RequiredActionTargetField = z.object({kind: z.literal("FIELD").optional(), path: z.string().optional(), associateId: z.string().optional()}); export const v2RequiredAction = z.object({type: z.enum(["DATA", "USER_ROLE", "BLOCKER"]).optional(), code: z.string().optional(), category: z.string().optional(), description: z.string().optional(), status: z.enum(["REQUIRED", "PROCESSING"]).optional(), target: z.discriminatedUnion("kind", [v2RequiredActionTargetAgreement, v2RequiredActionTargetDocument, v2RequiredActionTargetField]).optional()}); export const v2CustomerResponse = z.object({id: z.string().optional(), reference: z.string().optional(), status: z.enum(["AGREEMENTS_PENDING", "INFO_REQUIRED", "PENDING", "ACTIONS_REQUIRED", "VERIFIED", "REJECTED", "TERMINATED"]).optional(), type: z.enum(["COMPANY", "INDIVIDUAL"]).optional(), model: z.enum(["EMBEDDED", "RELIANCE"]).optional(), useCase: z.enum(["FIAT", "CRYPTO", "STABLECOIN_PAYOUTS", "EMBEDDED_STABLECOIN_WALLETS", "EMBEDDED_FIAT_ACCOUNTS"]).optional(), name: z.string().optional(), createdAt: z.string().optional(), updatedAt: z.string().optional(), authenticatedLink: v2AuthenticatedLinkResponse.optional(), requiredActions: z.array(v2RequiredAction).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 }; /** * Create customer * * POST /platform/v2/customers */ export const createApiPlatformV2Customers = async (args: CreateApiPlatformV2CustomersArgs, options?: CreateApiPlatformV2CustomersOptions) => { const {baseUrl = "https://api.sandbox.bvnk.com", fetch: fetchFn = fetch, BearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args['Idempotency-Key'] != null) headers.set("Idempotency-Key", String(args['Idempotency-Key'])) if (BearerAuth !== undefined) headers.set('authorization', `Bearer ${BearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/platform/v2/customers${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(v2CustomerResponse, await res.json()) };