import {z} from 'zod' export type BfpoAddress = {type: 'UK' | 'OVERSEAS' | 'EMAIL' | 'DX' | 'BFPO' | 'PO_BOX', care_of_name?: string | undefined, number: string, service_number_rank: string, unit_regiment: string}; export type DxAddress = {type: 'UK' | 'OVERSEAS' | 'EMAIL' | 'DX' | 'BFPO' | 'PO_BOX', care_of_name?: string | undefined, exchange_name: string, number: string}; export type EmailAddress = {type: 'UK' | 'OVERSEAS' | 'EMAIL' | 'DX' | 'BFPO' | 'PO_BOX', email: string}; export type OverseasAddress = {type: 'UK' | 'OVERSEAS' | 'EMAIL' | 'DX' | 'BFPO' | 'PO_BOX', care_of_name?: string | undefined, country: string, line1?: string | undefined, line2?: string | undefined, line3?: string | undefined, line4?: string | undefined, line5?: string | undefined}; export type PoBoxAddress = {type: 'UK' | 'OVERSEAS' | 'EMAIL' | 'DX' | 'BFPO' | 'PO_BOX', care_of_name?: string | undefined, number: string, post_town: string, postcode: string}; export type UkAddress = {type: 'UK' | 'OVERSEAS' | 'EMAIL' | 'DX' | 'BFPO' | 'PO_BOX', building_description: string, care_of_name?: string | undefined, county?: string | undefined, department_name?: string | undefined, dependent_locality?: string | undefined, dependent_street?: string | undefined, double_dependent_locality?: string | undefined, organisation_name?: string | undefined, post_town: string, postcode: string, street?: string | undefined, sub_building_description?: string | undefined, uprn?: number | undefined}; export type Address = {details: BfpoAddress | DxAddress | EmailAddress | OverseasAddress | PoBoxAddress | UkAddress}; export type PartyReference = string; export type ApplicationLodger = {email: string, telephone?: string | undefined, type: 'CONVEYANCER' | 'NON_CONVEYANCER'}; export type ValidationDisagreement = {comment: string, reason: 'DISAGREE_WITH_REGISTER' | 'HMLR_DATA_INCORRECT_OR_OUTDATED' | 'EXCEPTION_NOT_COVERED_BY_BUSINESS_RULES', validation_pointer: string, validation_type: string}; export type DocumentMetadata = {certification_statement_type: 'CERTIFIED' | 'CERTIFIED_BY_ANOTHER' | 'NOT_CERTIFIED', document_filename: string}; export type DocumentDetails = {companies_house_certification?: boolean | undefined, document_id: string, document_metadata: DocumentMetadata, type: 'ABSTRACT' | 'ACKAPU' | 'ADJAR' | 'ADJREVU' | 'ADMIN_LTRS' | 'ADV1' | 'ADV2' | 'AGREEMENT' | 'AMS1' | 'AN1' | 'AP1' | 'APPL_FRM' | 'APPOINTMENT_OF_TRUSTEE' | 'AS1' | 'AS2' | 'AS3' | 'ASSENT' | 'ASSIGNMENT' | 'BIRTH_CERT' | 'BOUND_PLAN' | 'CC' | 'CCD' | 'CERT_CON_CH' | 'CERT_DEATH' | 'CERT_RED_EX' | 'CERT_REG_CH' | 'CERT_S89' | 'CH1' | 'CH2' | 'CH3' | 'CHARGE' | 'CHARG_ORD' | 'CIVIL_CERT' | 'CM2' | 'CM5' | 'CM6' | 'CN1' | 'CNFRM_DTMN_LTA_LGHA' | 'CNFRM_NO_DEED_SUR' | 'CNFRM_NO_LTA_LGHA' | 'CNSNT_ADMIN_COURT' | 'COMP_DOC' | 'CONSENT' | 'CONST_COMP' | 'CONTR_RES' | 'CONVEYANCE' | 'CONV_CERT' | 'CONV_CERT_DEATH' | 'CORRES' | 'COR_CERT' | 'COSR' | 'COURT_ORD' | 'CRALIQ' | 'CRED_DEC' | 'CRED_RES' | 'CRT_FORM_7' | 'CRWALIQ' | 'DB' | 'DEATH_CERT' | 'DEBENTURE' | 'DEC_AB_NULL_MARR' | 'DEED' | 'DEED_POLL' | 'DEED_REG_DIS' | 'DEED_SUR' | 'DISCHARGE' | 'DJP' | 'DL' | 'DOP' | 'DRIVING_LICENCE' | 'DS1' | 'DS2' | 'DS3' | 'DS3_SHORT' | 'EOB' | 'EOL' | 'EVD_NO_RENEW' | 'EVIDENCE' | 'EV_OV_NAME_CHANGE' | 'EX1' | 'EX1A' | 'EX3' | 'FORM_600' | 'FORM_600CH' | 'FORM_DI' | 'FORM_JO' | 'FR1' | 'GENDER_CERT' | 'GVD' | 'HR1' | 'HR2' | 'HR4' | 'ID1' | 'ID2' | 'ID3' | 'ID4' | 'ID5' | 'ID_EV' | 'ID_FRM' | 'INDENTURE' | 'JP1' | 'K17_OR_K18' | 'K20' | 'K22' | 'K3' | 'K4' | 'LEASE' | 'LICENCE' | 'LIQ01' | 'LIQ_CERT_1' | 'LIQ_CERT_2' | 'LIQ_CERT_3' | 'LNDLD_CNSNT' | 'LONP' | 'LR_CORRES' | 'LTT' | 'MARR_CERT' | 'MEMO' | 'MORD' | 'MRTG_DEED' | 'NOD' | 'ORD_DISS_NULL_CP' | 'PASSPORT' | 'PLAN' | 'POA' | 'PROBATE' | 'PSS1' | 'REVERS_INT' | 'RN' | 'RX1' | 'RX2' | 'RX3' | 'RX4' | 'RXC' | 'RXCD' | 'SC' | 'SDLT' | 'SEV' | 'SHRF_RTN' | 'SIDE_LTR' | 'SOT' | 'SSALIQ' | 'STAT_DEC' | 'SUB_CHARGE' | 'TP1' | 'TP2' | 'TR1' | 'TR2' | 'TR4' | 'TR5' | 'TRANSFER' | 'TRUSTEE_RESOLUTION' | 'UN1' | 'UN2' | 'UN3' | 'UN4' | 'UT1' | 'VAR_CHARGE' | 'VAR_COV' | 'VAR_EAS' | 'VAR_LEASE' | 'VESTING_ORDER' | 'WCT' | 'WINDING_UP' | 'WIT_STATE'}; export type AddressForServiceOption = 'PROVIDED_ADDRESS' | 'NOT_REQUIRED'; export type AddressReference = string; export type OtherConveyancer = {address_reference: string, conveyancer_reference: string, full_name: string}; export type Party = {address_for_service_option: AddressForServiceOption, addresses?: Array | undefined, identity_evidence_type?: ('EVIDENCE' | 'VERIFIED' | 'NOT_REQUIRED') | undefined, other_conveyancer?: OtherConveyancer | undefined, register_action?: ('AMEND' | 'REMOVE') | undefined, representation_type: 'LODGING_CONVEYANCER' | 'OTHER_CONVEYANCER' | 'NOT_REPRESENTED' | 'NOT_REQUIRED', details: {type: 'PRIVATE_INDIVIDUAL' | 'OTHER_ORGANISATION' | 'OVERSEAS_COMPANY' | 'UK_COMPANY' | 'UNKNOWN', organisation_name: string} | {type: 'PRIVATE_INDIVIDUAL' | 'OTHER_ORGANISATION' | 'OVERSEAS_COMPANY' | 'UK_COMPANY' | 'UNKNOWN', company_number?: string | undefined, organisation_name: string, incorporation_territory: string, roe_id?: string | undefined, roe_id_exempt: boolean} | {type: 'PRIVATE_INDIVIDUAL' | 'OTHER_ORGANISATION' | 'OVERSEAS_COMPANY' | 'UK_COMPANY' | 'UNKNOWN', forenames?: string | undefined, surname: string} | {type: 'PRIVATE_INDIVIDUAL' | 'OTHER_ORGANISATION' | 'OVERSEAS_COMPANY' | 'UK_COMPANY' | 'UNKNOWN', company_number?: string | undefined, organisation_name: string} | {type: 'PRIVATE_INDIVIDUAL' | 'OTHER_ORGANISATION' | 'OVERSEAS_COMPANY' | 'UK_COMPANY' | 'UNKNOWN', freeformat_name: string}}; export type TitleScopeDetails = {part_description?: string | undefined, scope: 'WHOLE' | 'PART'}; export type TitleDetails = {disclosable_overriding_interests: boolean, scope_details: TitleScopeDetails, title_number: string, title_type: 'REGISTER_TITLE' | 'TRANSFEROR_TITLE' | 'ADDITIONAL_TITLE' | 'LANDLORD_TITLE' | 'TENANT_TITLE'}; export type ValueBand = {lower_value_band: number, upper_value_band?: number | undefined}; export type AmountDetails = {type: string, value?: number | undefined, value_band?: ValueBand | undefined, full_value_of_property_band?: ValueBand | undefined, full_value_of_property?: number | undefined, outstanding_charge?: number | undefined}; export type Charge = {type: string, date: string, mdref?: string | undefined, value: number}; export type Discharge = {type: string, discharge_submission_type: 'ATTACHED' | 'LENDER' | 'LATER'}; export type Transfer = {type: string, additional_provisions?: string | undefined, additional_provisions_code: 'NO_PROVISIONS' | 'MANUAL_TR1_FORM' | 'DETAILS_ENTERED', consideration_description?: string | undefined, consideration_type: 'MONETARY_VALUE' | 'NO_MONETARY_VALUE' | 'OTHER', date: string, title_guarantee_code: 'FULL' | 'LIMITED', trust_declaration_type?: ('JOINT_TENANTS' | 'TENANTS_IN_COMMON' | 'TRUST_DETAILS' | 'FORM_JO') | undefined, trust_details?: string | undefined, value?: number | undefined, value_band?: ValueBand | undefined, full_value_of_property_band?: ValueBand | undefined, full_value_of_property?: number | undefined, outstanding_charge?: number | undefined}; export type DocumentReference = string; export type PartyRole = {attorneys?: Array | undefined, capacity?: ('REGISTERED_PROPRIETOR' | 'ENTITLED_REGISTERED_PROPRIETOR' | 'ADDITIONAL_TRUSTEE' | 'INSOLVENCY_PRACTITIONER' | 'RECEIVER' | 'DEPUTY' | 'GUARDIAN' | 'PERSONAL_REPRESENTATIVE' | 'NOT_REQUIRED') | undefined, party_reference: PartyReference, role: 'ATTORNEY' | 'TRANSFEROR' | 'TRANSFEREE' | 'LENDER' | 'BORROWER' | 'PERSONAL_REPRESENTATIVE' | 'ASSENTOR' | 'LANDLORD' | 'TENANT'}; export type Transaction = {details?: (AmountDetails | Charge | Discharge | Transfer) | undefined, documents?: Array | undefined, priority: number, fee_in_pence: number, relates_to_new_title?: boolean | undefined, party_roles?: Array | undefined, type: 'ADV1' | 'ADV2' | 'AGN' | 'AML' | 'APLC' | 'APLCO' | 'APLM' | 'APR' | 'APT' | 'ARC' | 'ASSTTP' | 'ASTC' | 'ASTT' | 'ATP' | 'ATR' | 'AUN' | 'BKN' | 'BKR' | 'C' | 'CAG' | 'CANI' | 'CANR' | 'CANU' | 'CBKN' | 'CBKR' | 'CCT' | 'CH2' | 'CH3' | 'CHOA' | 'CHOU' | 'CHR' | 'CN' | 'CNC' | 'CNL' | 'COA' | 'COAC' | 'CON' | 'COP' | 'CPD' | 'CPVK' | 'CPVU' | 'CTD' | 'CUR' | 'DB' | 'DCLN' | 'DCLV' | 'DEB' | 'DFL1' | 'DFL3' | 'DFL4' | 'DFL5' | 'DFT' | 'DIS' | 'DJP' | 'DL' | 'DMR' | 'DOG' | 'DP' | 'DSP' | 'DSS' | 'DTL' | 'EX1' | 'EX3' | 'EXR' | 'HR' | 'JP1' | 'LCATCO' | 'LCBD' | 'LCBET' | 'LCBN' | 'LCF' | 'LCMRE' | 'LCOE' | 'LCOF' | 'LCSD' | 'LCSDM' | 'LCSOL' | 'LCSOLM' | 'LCSDWT' | 'LCSDMWT' | 'MDR' | 'NCT' | 'NDC' | 'NFR' | 'NOE' | 'NOL' | 'NOPSC' | 'NPR' | 'NRT' | 'PC' | 'PER' | 'PRO' | 'RC' | 'RE' | 'RFN' | 'RHR' | 'ROCA' | 'ROCC' | 'ROCU' | 'RNT' | 'ROE' | 'RRC' | 'RRD' | 'RTM' | 'RUN' | 'RXL' | 'RXN' | 'RXS' | 'SBC' | 'SHO' | 'SJT' | 'SOT' | 'STVC' | 'STVL' | 'T' | 'TNV' | 'TNVTP' | 'TOC' | 'TOSNV' | 'TOSNVTP' | 'TOSTP' | 'TOSV' | 'TPS' | 'TPSTP' | 'TRC' | 'TRM' | 'TSCNV' | 'TSCNVTP' | 'TSCTP' | 'TSCV' | 'TTP' | 'TVR' | 'TVRTP' | 'UNN' | 'UPT' | 'VC' | 'VLAN' | 'VLAP' | 'VLUN' | 'VO' | 'VOC' | 'VOCA' | 'VOCU' | 'VOE' | 'VOEA' | 'VOEU' | 'VRC' | 'WCT' | 'WDR', title_references?: Array | undefined}; export type SubstantiveApplicationData = {additional_provider_filter?: string | undefined, addresses?: {[key: string]: Address} | undefined, applicants?: Array | undefined, application_lodger: ApplicationLodger, customer_reference: string, disagree_with_validation_results?: Array | undefined, documents?: {[key: string]: DocumentDetails} | undefined, jp1_reference?: string | undefined, parties?: {[key: string]: Party} | undefined, submission_warning_understood: boolean, titles: {[key: string]: TitleDetails}, transactions: {[key: string]: Transaction}, type: 'REGISTER_UPDATE' | 'TRANSFER_OF_PART' | 'DISPOSITIONARY_FIRST_LEASE' | 'REMOVE_JP1'}; export type SubstantiveApplication = {data: SubstantiveApplicationData}; export type CreateApiV1ApplicationsArgs = {'Idempotency-Key': string, body: SubstantiveApplication}; export type CreateApiV1ApplicationsOptions = {baseUrl?: string | undefined, basicAuth?: {username: string, password: string} | undefined, fetch?: typeof fetch | undefined}; export const applicationCreationResponse = z.object({application_request_id: z.string().optional()}); export const applicationCreationDataResponse = z.object({data: applicationCreationResponse.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 }; /** * Submit an application * * POST /v1/applications */ export const createApiV1Applications = async (args: CreateApiV1ApplicationsArgs, options?: CreateApiV1ApplicationsOptions) => { const {baseUrl = "https://businessgateway.landregistry.gov.uk/bg2/api", fetch: fetchFn = fetch, basicAuth} = 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 (basicAuth !== undefined) headers.set('authorization', `Basic ${btoa(`${basicAuth.username}:${basicAuth.password}`)}`) const url = `${baseUrl.replace(/\/+$/, '')}/v1/applications${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(applicationCreationDataResponse, await res.json()) };