import {z} from 'zod' export type PaymentContextSource = {type: string, account_holder: {billing_address: {country: string}}} | {type: string} | {type: string} | {type: string}; export type PaymentContextDetailsCustomer = {phone?: ({country_code?: string | undefined, number?: string | undefined, phone_verified?: boolean | undefined}) | undefined, email?: string | undefined, name?: string | undefined, email_verified?: boolean | undefined, summary?: ({registration_date?: string | undefined, first_transaction_date?: string | undefined, last_payment_date?: string | undefined, total_order_count?: number | undefined, last_payment_amount?: number | undefined}) | undefined}; export type Address = {address_line1?: string | undefined, address_line2?: string | undefined, city?: string | undefined, state?: string | undefined, zip?: string | undefined, country?: string | undefined}; export type PhoneNumber = {country_code?: string | undefined, number?: string | undefined}; export type Shipping = {first_name?: string | undefined, last_name?: string | undefined, email?: string | undefined, address?: Address | undefined, phone?: PhoneNumber | undefined, from_address_zip?: string | undefined, timeframe?: ('ElectronicDelivery' | 'SameDay' | 'Overnight' | 'TwoDayOrMore') | undefined, method?: ('Digital' | 'PickUp' | 'BillingAddress' | 'OtherAddress') | undefined, delay?: number | undefined}; export type AirlineData = Array<{ticket?: ({number?: string | undefined, issue_date?: string | undefined, issuing_carrier_code?: string | undefined, travel_package_indicator?: string | undefined, travel_agency_name?: string | undefined, travel_agency_code?: string | undefined}) | undefined, passenger?: (Array<{first_name?: string | undefined, last_name?: string | undefined, date_of_birth?: string | undefined, address?: ({country?: string | undefined}) | undefined}>) | undefined, flight_leg_details?: (Array<{flight_number?: string | undefined, carrier_code?: string | undefined, class_of_travelling?: string | undefined, departure_airport?: string | undefined, departure_date?: string | undefined, departure_time?: string | undefined, arrival_airport?: string | undefined, stop_over_code?: string | undefined, fare_basis_code?: string | undefined}>) | undefined}>; export type AccommodationData = Array<{name?: string | undefined, booking_reference?: string | undefined, check_in_date?: string | undefined, check_out_date?: string | undefined, address?: ({address_line1?: string | undefined, zip?: string | undefined}) | undefined, state?: string | undefined, country?: string | undefined, city?: string | undefined, number_of_rooms?: number | undefined, guests?: (Array<{first_name?: string | undefined, last_name?: string | undefined, date_of_birth?: string | undefined}>) | undefined, room?: (Array<{rate?: string | undefined, number_of_nights_at_room_rate?: string | undefined}>) | undefined, property_phone?: (Array<{country_code?: string | undefined, number?: string | undefined}>) | undefined, customer_service_phone?: (Array<{country_code?: string | undefined, number?: string | undefined}>) | undefined}>; export type PaymentContextProcessing = {plan?: ({type: 'MERCHANT_INITIATED_BILLING' | 'MERCHANT_INITIATED_BILLING_SINGLE_AGREEMENT' | 'CHANNEL_INITIATED_BILLING' | 'CHANNEL_INITIATED_BILLING_SINGLE_AGREEMENT' | 'RECURRING_PAYMENTS' | 'PRE_APPROVED_PAYMENTS', skip_shipping_address: boolean, immutable_shipping_address: boolean}) | undefined, discount_amount?: number | undefined, shipping_amount?: number | undefined, tax_amount?: number | undefined, invoice_id?: string | undefined, brand_name?: string | undefined, locale?: string | undefined, shipping_preference?: ('no_shipping' | 'set_provided_address' | 'get_from_file') | undefined, user_action?: ('pay_now' | 'continue') | undefined, partner_customer_risk_data?: ({key?: string | undefined, value?: string | undefined}) | undefined, custom_payment_method_ids?: Array | undefined, airline_data?: AirlineData | undefined, accommodation_data?: AccommodationData | undefined}; export type PaymentContextItems = Array<{type?: string | undefined, name?: string | undefined, quantity?: number | undefined, unit_price?: number | undefined, reference?: string | undefined, total_amount?: number | undefined, tax_rate?: number | undefined, tax_amount?: number | undefined, discount_amount?: number | undefined, url?: string | undefined, image_url?: string | undefined}>; export type PaymentContext = {source: PaymentContextSource, amount: number, currency: string, payment_type?: ('Regular' | 'Recurring') | undefined, capture?: boolean | undefined, customer?: PaymentContextDetailsCustomer | undefined, shipping?: Shipping | undefined, processing?: PaymentContextProcessing | undefined, processing_channel_id?: string | undefined, reference?: string | undefined, description?: string | undefined, success_url?: string | undefined, failure_url?: string | undefined, items?: PaymentContextItems | undefined, metadata?: Record | undefined}; export type CreateApiPaymentContextsArgs = {'Cko-Idempotency-Key'?: string | undefined, body: PaymentContext}; export type CreateApiPaymentContextsOptions = {baseUrl: string, OAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const paymentContextId = z.string().min(30).max(30); export const serverTimestamp = z.string(); export const paymentPlan = z.object({days_between_payments: z.number().int().optional(), total_number_of_payments: z.number().int().optional(), current_payment_number: z.number().int().optional(), expiry: z.string().optional(), name: z.string().max(35).optional(), start_date: z.string().optional(), amount: z.number().int().gte(1).optional()}); export const availablePaymentTypes = z.array(z.object({payment_type: z.enum(["Regular", "PayLater", "Installment"]).optional(), payment_plan: paymentPlan.optional()})); export const unavailablePaymentTypes = z.array(z.object({payment_type: z.enum(["Regular", "PayLater", "Installment"]).optional(), rejection_reason: z.string().optional(), payment_plan: paymentPlan.optional(), description: z.string().optional()})); export const partnerMetadata = z.object({order_id: z.string().optional(), customer_id: z.string().optional(), session_id: z.string().optional(), client_token: z.string().optional()}); export const link = z.object({href: z.string()}); export const paymentContextResponse = z.object({id: paymentContextId, amount: z.number().int().optional(), processed_on: serverTimestamp, status: z.string().optional(), response_code: z.string().optional(), response_summary: z.string().optional(), available_payment_types: availablePaymentTypes.optional(), unavailable_payment_types: unavailablePaymentTypes.optional(), partner_metadata: partnerMetadata, _links: z.object({self: link.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 }; /** * Request a Payment Context * * POST /payment-contexts * * Also accepts auth: ApiSecretKey */ export const createApiPaymentContexts = async (args: CreateApiPaymentContextsArgs, options: CreateApiPaymentContextsOptions) => { const {baseUrl, fetch: fetchFn = fetch, OAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args['Cko-Idempotency-Key'] != null) headers.set("Cko-Idempotency-Key", String(args['Cko-Idempotency-Key'])) if (OAuth !== undefined) headers.set('authorization', `Bearer ${OAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/payment-contexts${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(paymentContextResponse, await res.json()) };