import {z} from 'zod' export type TaxResidence = {country: string, tin?: string | undefined, noTinReason?: ('NOT_ISSUED' | 'UNABLE_TO_OBTAIN' | 'NOT_REQUIRED') | undefined, noTinExplanation?: string | undefined}; export type CompanyTaxDeclaration = {acceptedAt: string, signatory: {fullName: string, capacity: 'DIRECTOR' | 'OWNER_OR_SHAREHOLDER' | 'AUTHORISED_SIGNATORY'}}; export type AddressCountryCode = string; export type AddressV2 = {addressLine1: string, addressLine2?: string | undefined, postalCode: string, city: string, countryCode: AddressCountryCode, country?: string | undefined, stateCode?: string | undefined}; export type CorporateCdd = {pepStatus: 'NOT_PEP' | 'FORMER_PEP_2_YEARS' | 'FORMER_PEP_OLDER' | 'DOMESTIC_PEP' | 'FOREIGN_PEP' | 'CLOSE_ASSOCIATES' | 'FAMILY_MEMBERS', intendedUseOfAccount: 'SUPPLIER_VENDOR_PAYMENTS' | 'PAYROLL' | 'CUSTOMER_PAYMENTS_RECEIVED' | 'CUSTOMER_PAYOUTS_REFUNDS_SETTLEMENTS' | 'OPERATING_EXPENSES' | 'DIVIDEND_PROFIT_DISTRIBUTIONS' | 'LOAN_REPAYMENT_FINANCIAL_ACTIVITIES' | 'INTERCOMPANY_TRANSFER', expectedMonthlyVolume: {amount: string, currency?: string | undefined}}; export type Reliance = {identityDocumentMetadata: {type: 'PASSPORT' | 'ID_CARD' | 'DRIVERS' | 'RESIDENCE_PERMIT' | 'OTHER', number: string, expiryDate?: string | undefined, issueDate?: string | undefined, issuingCountryCode: string, kycTimestamp: string}, biometricLiveness: {livenessTimestamp: string}, addressVerification: {type: 'DOC' | 'NON_DOC'}}; export type TaxDeclaration = {acceptedAt: string}; export type CreateCorporateCustomerAssociates = Array<{person: {firstName: string, lastName: string, dateOfBirth: string, birthCountryCode?: string | undefined, placeOfBirth?: string | undefined, nationality?: string | undefined, address: AddressV2, contactInfo: {emailAddress?: string | undefined, phoneNumber?: string | undefined}, taxIdentification?: {number: string, taxResidenceCountryCode: 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, reliance?: Reliance | undefined}, titles?: (Array<'BUSINESS_OWNER' | 'ACCOUNT_REPRESENTATIVE' | 'DIRECTOR'>) | undefined, ownership?: ({type?: ('DIRECT' | 'INDIRECT') | undefined, percentage?: number | undefined}) | undefined, controllingPersonRole?: ('LP_OWNERSHIP' | 'LP_OTHER_MEANS' | 'LP_SENIOR_MANAGING_OFFICIAL' | 'TRUST_SETTLOR' | 'TRUST_TRUSTEE' | 'TRUST_PROTECTOR' | 'TRUST_BENEFICIARY' | 'TRUST_OTHER' | 'ARR_SETTLOR_EQ' | 'ARR_TRUSTEE_EQ' | 'ARR_PROTECTOR_EQ' | 'ARR_BENEFICIARY_EQ' | 'ARR_OTHER_EQ') | undefined, taxResidences?: Array | undefined, taxDeclaration?: TaxDeclaration | undefined}>; export type CreateCorporateRiskScore = 'LOW' | 'MEDIUM' | 'HIGH'; export type RelianceAttestation = {riskScore: CreateCorporateRiskScore, eddCompleted: boolean}; export type CorporateReliance = {attestation: RelianceAttestation}; export type RegulatorInformation = {regulatorName: string, regulatorJurisdiction: string}; export type PublicInformation = {listedExchange: string, tickerSymbol: string}; export type CreateCorporateCustomer = {name: string, description?: string | undefined, entityType: 'LIMITED_LIABILITY_COMPANY' | 'PUBLICLY_LISTED_COMPANY' | 'SOLE_PROPRIETOR' | 'PARTNERSHIP' | 'CORPORATION' | 'TRUST' | 'PRIVATE_FOUNDATION' | 'CHARITY' | 'NON_PROFIT_ORGANIZATION' | 'PUBLIC_AGENCIES_OR_AUTHORITIES', taxResidenceCountryCode?: string | undefined, taxNumber?: string | undefined, taxResidences?: Array | undefined, countryOfIncorporation?: string | undefined, crsClassification?: ('ACTIVE_NFE' | 'PASSIVE_NFE' | 'FI_OTHER' | 'PMIE_PARTICIPATING' | 'PMIE_NON_PARTICIPATING') | undefined, carfClassification?: ('EXCLUDED_FI' | 'EXCLUDED_GOVERNMENT' | 'EXCLUDED_LISTED_PMIE' | 'EXCLUDED_LISTED' | 'ACTIVE_ENTITY' | 'OTHER_ENTITY') | undefined, taxDeclaration?: CompanyTaxDeclaration | undefined, registrationNumber: string, industryReference: string, industryNaceCode?: number | undefined, industryNaicsCode?: number | undefined, monthlyExpectedVolumesReference: string, sourceOfFunds?: ('COMMERCIAL_ACTIVITIES' | 'SHAREHOLDER_CAPITAL' | 'VENTURE_CAPITAL' | 'SALE_OF_ASSETS' | 'CRYPTO_FUNDRAISING' | 'CRYPTO_TRADING_REVENUE' | 'CORPORATE_LOANS' | '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: AddressV2, cdd?: CorporateCdd | undefined, operationalAddress?: AddressV2 | undefined, incorporationDate?: string | undefined, website?: string | undefined, associates: CreateCorporateCustomerAssociates, reliance?: CorporateReliance | undefined, isRegulated?: boolean | undefined, regulatorInformation?: RegulatorInformation | undefined, isPubliclyListed?: boolean | undefined, publicInformation?: PublicInformation | undefined}; export type CreateCompanyCustomerRequest = {type: 'company', company: CreateCorporateCustomer, signedAgreementSessionReference: string}; export type CreateIndividualCustomer = {description: string, firstName: string, lastName: string, dateOfBirth: string, nationality: string, birthCountryCode: string, placeOfBirth?: string | undefined, emailAddress: string, phoneNumber?: string | undefined, address: {addressLine1: string, addressLine2?: string | undefined, postalCode: string, city: string, countryCode: AddressCountryCode, country?: string | undefined, stateCode?: string | undefined}, taxIdentification?: {number: string, taxResidenceCountryCode: string} | undefined, taxResidences?: Array | undefined, taxDeclaration?: TaxDeclaration | undefined, cdd: {employmentStatus: 'SELF_EMPLOYED' | 'SALARIED' | 'UNEMPLOYED' | 'RETIRED' | 'STUDENT', sourceOfFunds: 'SALARY' | 'PENSION' | 'SAVINGS' | 'SELF_EMPLOYMENT' | 'CRYPTO_TRADING' | 'GAMBLING' | 'REAL_ESTATE' | 'GIFT' | 'STUDENT_LOAN', pepStatus: 'NOT_PEP' | 'FORMER_PEP_2_YEARS' | 'FORMER_PEP_OLDER' | 'DOMESTIC_PEP' | 'FOREIGN_PEP' | 'CLOSE_ASSOCIATES' | 'FAMILY_MEMBERS', intendedUseOfAccount: 'TRANSFERS_OWN_WALLET' | 'TRANSFERS_FAMILY_FRIENDS' | 'INVESTMENTS' | 'GOODS_SERVICES' | 'DONATIONS', expectedMonthlyVolume: {amount: string, currency?: 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, 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}, reliance?: Reliance | undefined}; export type CreateIndividualCustomerRequest = {type: 'individual', individual: CreateIndividualCustomer, signedAgreementSessionReference: string}; export type CreateApiPlatformV1CustomersArgs = {'X-Idempotency-Key': string, body: CreateCompanyCustomerRequest | CreateIndividualCustomerRequest}; export type CreateApiPlatformV1CustomersOptions = {baseUrl?: string | undefined, Hawk?: string | undefined, fetch?: typeof fetch | undefined}; export const customerStatusExternal = z.enum(["INFO_REQUIRED", "PENDING", "VERIFIED", "REJECTED"]); export const customerReferenceAndStatus = z.object({reference: z.string(), status: customerStatusExternal}); 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/v1/customers */ export const createApiPlatformV1Customers = async (args: CreateApiPlatformV1CustomersArgs, options?: CreateApiPlatformV1CustomersOptions) => { const {baseUrl = "https://api.sandbox.bvnk.com", fetch: fetchFn = fetch, Hawk} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args['X-Idempotency-Key'] != null) headers.set("X-Idempotency-Key", String(args['X-Idempotency-Key'])) if (Hawk !== undefined) headers.set("Authorization", Hawk) const url = `${baseUrl.replace(/\/+$/, '')}/platform/v1/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(customerReferenceAndStatus, await res.json()) };