import {z} from 'zod' export type SessionSource = {type: string, scheme?: ('amex' | 'cartes_bancaires' | 'diners' | 'mastercard' | 'visa' | 'discover' | 'upi' | 'jcb') | undefined, number: string, expiry_month: number, expiry_year: number, billing_address?: ({address_line1?: string | undefined, address_line2?: string | undefined, address_line3?: string | undefined, city?: string | undefined, state?: string | undefined, zip?: string | undefined, country?: string | undefined}) | undefined, home_phone?: {country_code: string, number: string} | undefined, mobile_phone?: {country_code: string, number: string} | undefined, work_phone?: {country_code: string, number: string} | undefined, email?: string | undefined, name?: string | undefined, stored?: boolean | undefined} | {type: string, scheme?: ('amex' | 'cartes_bancaires' | 'diners' | 'mastercard' | 'visa' | 'discover' | 'upi' | 'jcb') | undefined, number?: string | undefined, expiry_month?: number | undefined, expiry_year?: number | undefined, billing_address?: ({address_line1?: string | undefined, address_line2?: string | undefined, address_line3?: string | undefined, city?: string | undefined, state?: string | undefined, zip?: string | undefined, country?: string | undefined}) | undefined, home_phone?: {country_code: string, number: string} | undefined, mobile_phone?: {country_code: string, number: string} | undefined, work_phone?: {country_code: string, number: string} | undefined, email?: string | undefined, id: string} | {type: string, scheme?: ('amex' | 'cartes_bancaires' | 'diners' | 'mastercard' | 'visa' | 'discover' | 'upi' | 'jcb') | undefined, number?: string | undefined, expiry_month?: number | undefined, expiry_year?: number | undefined, billing_address?: ({address_line1?: string | undefined, address_line2?: string | undefined, address_line3?: string | undefined, city?: string | undefined, state?: string | undefined, zip?: string | undefined, country?: string | undefined}) | undefined, home_phone?: {country_code: string, number: string} | undefined, mobile_phone?: {country_code: string, number: string} | undefined, work_phone?: {country_code: string, number: string} | undefined, email?: string | undefined, token: string} | {type: string, scheme?: ('amex' | 'cartes_bancaires' | 'diners' | 'mastercard' | 'visa' | 'discover' | 'upi' | 'jcb') | undefined, number?: string | undefined, expiry_month: number, expiry_year: number, billing_address?: ({address_line1?: string | undefined, address_line2?: string | undefined, address_line3?: string | undefined, city?: string | undefined, state?: string | undefined, zip?: string | undefined, country?: string | undefined}) | undefined, home_phone?: {country_code: string, number: string} | undefined, mobile_phone?: {country_code: string, number: string} | undefined, work_phone?: {country_code: string, number: string} | undefined, email?: string | undefined, token: string, name?: string | undefined, stored?: boolean | undefined}; export type SessionMarketplaceData = {sub_entity_id?: string | undefined}; export type AuthenticationType = 'regular' | 'recurring' | 'installment' | 'maintain_card' | 'add_card'; export type Category = 'payment' | 'non_payment'; export type ThreeDsRequestorAuthenticationInfo = {three_ds_req_auth_method?: ('no_threeds_requestor_authentication_occurred' | 'three3ds_requestor_own_credentials' | 'federated_id' | 'issuer_credentials' | 'third_party_authentication' | 'fido_authenticator' | 'fido_authenticator_fido_assurance_data_signed' | 'src_assurance_data') | undefined, three_ds_req_auth_timestamp?: string | undefined, three_ds_req_auth_data?: string | undefined}; export type CardholderAccountInfo = {purchase_count?: number | undefined, account_age?: ('no_account' | 'created_during_transaction' | 'less_than_thirty_days' | 'thirty_to_sixty_days' | 'more_than_sixty_days') | undefined, add_card_attempts?: number | undefined, shipping_address_age?: ('this_transaction' | 'less_than_thirty_days' | 'thirty_to_sixty_days' | 'more_than_sixty_days') | undefined, account_name_matches_shipping_name?: boolean | undefined, suspicious_account_activity?: boolean | undefined, transactions_today?: number | undefined, authentication_method?: ('no_authentication' | 'own_credentials' | 'federated_id' | 'issuer_credentials' | 'third_party_authentication' | 'fido') | undefined, cardholder_account_age_indicator?: ('no_account,' | 'this_transaction' | 'less_than_thirty_days' | 'thirty_to_sixty_days' | 'more_than_sixty_days') | undefined, account_change?: string | undefined, account_change_indicator?: ('this_transaction' | 'less_than_thirty_days' | 'thirty_to_sixty_days' | 'more_than_sixty_days') | undefined, account_date?: string | undefined, account_password_change?: string | undefined, account_password_change_indicator?: ('no_change' | 'this_transaction' | 'less_than_thirty_days' | 'thirty_to_sixty_days' | 'more_than_sixty_days') | undefined, transactions_per_year?: number | undefined, payment_account_age?: string | undefined, shipping_address_usage?: string | undefined, account_type?: ('not_applicable' | 'credit' | 'debit') | undefined, account_id?: string | undefined, three_ds_requestor_authentication_info?: ThreeDsRequestorAuthenticationInfo | undefined}; export type ChallengeIndicator = 'no_preference' | 'no_challenge_requested' | 'challenge_requested' | 'challenge_requested_mandate' | 'low_value' | 'trusted_listing' | 'trusted_listing_prompt' | 'transaction_risk_assessment' | 'data_share'; export type SessionsBillingDescriptor = {name: string}; export type Reference = string; export type MerchantRiskInfo = {delivery_email?: string | undefined, delivery_timeframe?: ('electronic_delivery' | 'same_day' | 'overnight' | 'two_day_or_more') | undefined, is_preorder?: boolean | undefined, is_reorder?: boolean | undefined, shipping_indicator?: ('billing_address' | 'another_address_on_file' | 'not_on_file' | 'store_pick_up' | 'digital_goods' | 'travel_and_event_no_shipping' | 'other') | undefined, reorder_items_indicator?: ('first_time_ordered' | 'reordered') | undefined, pre_order_purchase_indicator?: ('merchandise_available' | 'future_availability') | undefined, pre_order_date?: string | undefined, gift_card_amount?: string | undefined, gift_card_currency?: string | undefined, gift_card_count?: string | undefined}; export type TransactionType = 'goods_service' | 'check_acceptance' | 'account_funding' | 'quasi_card_transaction' | 'prepaid_activation_and_load'; export type SessionAddress = {address_line1?: string | undefined, address_line2?: string | undefined, address_line3?: string | undefined, city?: string | undefined, state?: string | undefined, zip?: string | undefined, country?: string | undefined}; export type CompletionInfo = {type: 'hosted', success_url: string, failure_url: string} | {type: 'non_hosted', callback_url?: string | undefined, challenge_notification_url?: string | undefined}; export type SdkEphemeralPublicKey = {kty?: 'EC' | undefined, crv?: string | undefined, x?: string | undefined, y?: string | undefined}; export type ChannelData = {channel: 'browser', three_ds_method_completion?: ('Y' | 'N' | 'U') | undefined, accept_header: string, java_enabled: boolean, javascript_enabled: boolean, language: string, color_depth: string, screen_height: string, screen_width: string, timezone: string, user_agent: string, ip_address: string, iframe_payment_allowed?: boolean | undefined, user_agent_client_hint?: string | undefined} | {channel: 'app', sdk_app_id: string, sdk_max_timeout: number, sdk_ephem_pub_key: SdkEphemeralPublicKey, sdk_reference_number: string, sdk_encrypted_data: string, sdk_transaction_id: string, sdk_interface_type: 'native' | 'html' | 'both', sdk_ui_elements: Array<'text' | 'single_select' | 'multi_select' | 'oob' | 'html_other'>} | {channel: 'merchant_initiated', request_type: 'recurring_transaction' | 'installment_transaction' | 'add_card' | 'maintain_card_information' | 'account_verification' | 'split_or_delayed_shipment' | 'top_up' | 'mail_order' | 'telephone_order' | 'whitelist_status_check' | 'other_payment'}; export type Recurring = {days_between_payments?: number | undefined, expiry?: string | undefined}; export type Installment = {number_of_payments: number, days_between_payments?: number | undefined, expiry?: string | undefined}; export type Optimization = {framework?: 'acceptance_rates' | undefined}; export type InitialTransaction = {acs_transaction_id?: string | undefined, authentication_method?: ('frictionless_authentication' | 'challenge_occurred' | 'avs_verified' | 'other_issuer_methods') | undefined, authentication_timestamp?: string | undefined, authentication_data?: string | undefined, initial_session_id?: string | undefined}; export type Experience = '3ds' | 'google_spa'; export type DeviceInformation = {device_id?: string | undefined, device_session_id?: string | undefined}; export type SessionRequest = {source: SessionSource, amount?: number | undefined, currency: string, processing_channel_id?: string | undefined, marketplace?: SessionMarketplaceData | undefined, authentication_type?: AuthenticationType | undefined, authentication_category?: Category | undefined, account_info?: CardholderAccountInfo | undefined, challenge_indicator?: ChallengeIndicator | undefined, billing_descriptor?: SessionsBillingDescriptor | undefined, reference?: Reference | undefined, merchant_risk_info?: MerchantRiskInfo | undefined, transaction_type?: TransactionType | undefined, shipping_address?: SessionAddress | undefined, shipping_address_matches_billing?: boolean | undefined, completion: CompletionInfo, channel_data?: ChannelData | undefined, recurring?: Recurring | undefined, installment?: Installment | undefined, optimization?: Optimization | undefined, initial_transaction?: InitialTransaction | undefined, google_spa?: ({continue_url?: string | undefined}) | undefined, preferred_experiences?: Array | undefined, device_information?: DeviceInformation | undefined}; export type CreateApiSessionsArgs = {body: SessionRequest}; export type CreateApiSessionsOptions = {baseUrl: string, OAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const sessionId = z.string().min(30).max(30); export const sessionSecret = z.string().min(48).max(48); export const amount = z.number().int().gte(0).lte(9007199254740991); export const currency = z.string(); export const authenticationType = z.enum(["regular", "recurring", "installment", "maintain_card", "add_card"]); export const category = z.enum(["payment", "non_payment"]); export const dsPublicKeys = z.object({ds_public: z.string().max(1024), ca_public: z.string().max(1024).optional(), ca_public_all: z.array(z.string().max(1024)).optional()}); export const status = z.enum(["challenged", "pending", "processing", "challenge_abandoned", "expired", "approved", "attempted", "unavailable", "declined", "rejected"]); export const statusReason = z.enum(["ares_status", "ares_error", "rreq_error", "rreq_status", "risk_declined"]); export const approved = z.boolean(); export const protocolVersion = z.string().max(50); export const threeDsRequestorAuthenticationInfo = z.object({three_ds_req_auth_method: z.enum(["no_threeds_requestor_authentication_occurred", "three3ds_requestor_own_credentials", "federated_id", "issuer_credentials", "third_party_authentication", "fido_authenticator", "fido_authenticator_fido_assurance_data_signed", "src_assurance_data"]).optional(), three_ds_req_auth_timestamp: z.string().optional(), three_ds_req_auth_data: z.string().max(20000).optional()}); export const cardholderAccountInfo = z.object({purchase_count: z.number().gte(0).lte(9999).optional(), account_age: z.enum(["no_account", "created_during_transaction", "less_than_thirty_days", "thirty_to_sixty_days", "more_than_sixty_days"]).optional(), add_card_attempts: z.number().gte(0).lte(999).optional(), shipping_address_age: z.enum(["this_transaction", "less_than_thirty_days", "thirty_to_sixty_days", "more_than_sixty_days"]).optional(), account_name_matches_shipping_name: z.boolean().optional(), suspicious_account_activity: z.boolean().optional(), transactions_today: z.number().gte(0).lte(999).optional(), authentication_method: z.enum(["no_authentication", "own_credentials", "federated_id", "issuer_credentials", "third_party_authentication", "fido"]).optional(), cardholder_account_age_indicator: z.enum(["no_account,", "this_transaction", "less_than_thirty_days", "thirty_to_sixty_days", "more_than_sixty_days"]).optional(), account_change: z.string().optional(), account_change_indicator: z.enum(["this_transaction", "less_than_thirty_days", "thirty_to_sixty_days", "more_than_sixty_days"]).optional(), account_date: z.string().optional(), account_password_change: z.string().optional(), account_password_change_indicator: z.enum(["no_change", "this_transaction", "less_than_thirty_days", "thirty_to_sixty_days", "more_than_sixty_days"]).optional(), transactions_per_year: z.number().int().lte(999).optional(), payment_account_age: z.string().optional(), shipping_address_usage: z.string().optional(), account_type: z.enum(["not_applicable", "credit", "debit"]).optional(), account_id: z.string().max(64).optional(), three_ds_requestor_authentication_info: threeDsRequestorAuthenticationInfo.optional()}); export const merchantRiskInfo = z.object({delivery_email: z.string().max(254).optional(), delivery_timeframe: z.enum(["electronic_delivery", "same_day", "overnight", "two_day_or_more"]).optional(), is_preorder: z.boolean().optional(), is_reorder: z.boolean().optional(), shipping_indicator: z.enum(["billing_address", "another_address_on_file", "not_on_file", "store_pick_up", "digital_goods", "travel_and_event_no_shipping", "other"]).optional(), reorder_items_indicator: z.enum(["first_time_ordered", "reordered"]).optional(), pre_order_purchase_indicator: z.enum(["merchandise_available", "future_availability"]).optional(), pre_order_date: z.string().optional(), gift_card_amount: z.string().max(15).optional(), gift_card_currency: z.string().min(3).max(3).optional(), gift_card_count: z.string().min(2).max(2).optional()}); export const reference = z.string().max(100); export const transactionType = z.enum(["goods_service", "check_acceptance", "account_funding", "quasi_card_transaction", "prepaid_activation_and_load"]).max(50); export const nextActions = z.array(z.enum(["redirect_cardholder", "collect_channel_data", "issuer_fingerprint", "challenge_cardholder", "complete"])); export const ds = z.object({ds_id: z.string().max(32).optional(), reference_number: z.string().max(32).optional(), transaction_id: z.string().min(36).max(36).optional()}); export const acs = z.object({reference_number: z.string().max(32), transaction_id: z.string().min(36).max(36), operator_id: z.string().max(32), url: z.string().max(2048).optional(), signed_content: z.string().max(512).optional(), challenge_mandated: z.boolean(), authentication_type: z.string().optional(), challenge_cancel_reason: z.enum(["cardholder_cancel", "transaction_timed_out", "challenge_timed_out", "transaction_error", "unknown", "sdk_timed_out"]).optional(), interface: z.enum(["native_ui", "html"]).optional(), ui_template: z.enum(["text", "single_select", "multi_select", "oob", "html_other"]).optional(), challenge_cancel_reason_code: z.string().optional()}); export const responseCode = z.enum(["Y", "N", "U", "A", "C", "D", "R", "I"]); export const responseStatusReason = z.string(); export const cryptogram = z.string().min(28).max(28); export const eci = z.string().min(2).max(2); export const cardInfo = z.object({instrument_id: z.string(), fingerprint: z.string(), metadata: z.object({card_type: z.enum(["CREDIT", "DEBIT", "PREPAID", "CHARGE", "DEFERRED DEBIT"]).optional(), card_category: z.enum(["CONSUMER", "COMMERCIAL"]).optional(), issuer_name: z.string().optional(), issuer_country: z.string().optional(), product_id: z.string().optional(), product_type: z.string().optional()}).optional()}); export const recurring = z.object({days_between_payments: z.number().int().optional(), expiry: z.string().optional()}); export const installment = z.object({number_of_payments: z.number().int().gte(2), days_between_payments: z.number().int().optional(), expiry: z.string().optional()}); export const initialTransaction = z.object({acs_transaction_id: z.string().min(36).optional(), authentication_method: z.enum(["frictionless_authentication", "challenge_occurred", "avs_verified", "other_issuer_methods"]).optional(), authentication_timestamp: z.string().optional(), authentication_data: z.string().max(2048).optional(), initial_session_id: z.string().min(30).max(30).optional()}); export const getSessionLinks = z.object({self: z.object({href: z.string().max(100)})}); export const trustedBeneficiary = z.object({status: z.enum(["Y", "N", "E", "P", "R", "U"]).optional(), source: z.string().optional()}); export const optimizedProperty = z.object({field: z.string().optional(), original_value: z.string().optional(), optimized_value: z.string().optional()}); export const errorDetails = z.object({error_code: z.string().optional(), error_component: z.string().optional(), error_detail: z.string().max(2048).optional(), error_description: z.string().max(2048).optional()}); export const preferredExperiences = z.object({google_spa: z.object({status: z.enum(["available", "unprocessed", "processed", "unavailable"]).optional(), reason: z.array(z.string()).optional()}).optional(), "3ds": z.object({status: z.enum(["available", "unprocessed", "processed", "unavailable"]).optional(), reason: z.array(z.string()).optional()}).optional()}); export const experience = z.enum(["3ds", "google_spa"]); export const googleSpaToken = z.object({number: z.string().optional(), expiry_month: z.number().optional(), expiry_year: z.number().optional()}); export const hostedGoogleSpaInfo = z.object({token: googleSpaToken.optional()}); export const nonHostedGoogleSpaInfo = z.object({challenge_url: z.string().optional(), initial_timeout: z.string().optional(), max_timeout: z.string().optional(), iframe: z.object({height: z.string().optional(), width: z.string().optional()}).optional(), token: googleSpaToken.optional()}); export const googleSpaInfo = z.union([hostedGoogleSpaInfo, nonHostedGoogleSpaInfo]); export const createSessionOkResponse = z.object({id: sessionId, session_secret: sessionSecret.optional(), transaction_id: z.string().min(36).max(36), scheme: z.enum(["visa", "mastercard", "jcb", "amex", "diners", "cartes_bancaires", "discover", "upi"]), amount: amount, currency: currency, completed: z.boolean().optional(), challenged: z.boolean().optional(), authentication_type: authenticationType, authentication_category: category, certificates: dsPublicKeys.optional(), status: status, status_reason: statusReason.optional(), approved: approved.optional(), protocol_version: protocolVersion, account_info: cardholderAccountInfo.optional(), merchant_risk_info: merchantRiskInfo.optional(), reference: reference.optional(), transaction_type: transactionType.optional(), next_actions: nextActions.optional(), ds: ds.optional(), acs: acs.optional(), response_code: responseCode.optional(), response_status_reason: responseStatusReason.optional(), cryptogram: cryptogram.optional(), eci: eci.optional(), xid: z.string().optional(), cardholder_info: z.string().optional(), card: cardInfo.optional(), recurring: recurring.optional(), installment: installment.optional(), initial_transaction: initialTransaction.optional(), customer_ip: z.string().optional(), _links: getSessionLinks, authentication_date: z.string().optional(), exemption: z.object({requested: z.literal("none").optional(), applied: z.enum(["none", "low_value", "transaction_risk_assessment", "secure_corporate_payment", "trusted_listing", "3ds_outage", "sca_delegation", "out_of_sca_scope", "other", "low_risk_program"]).optional(), code: z.string().optional(), trusted_beneficiary: trustedBeneficiary.optional()}).optional(), flow_type: z.enum(["challenged", "frictionless", "frictionless_delegated"]).optional(), challenge_indicator: z.enum(["no_preference", "no_challenge_requested", "challenge_requested", "challenge_requested_mandate"]), optimization: z.object({optimized: z.boolean().optional(), framework: z.literal("acceptance_rates").optional(), optimized_properties: z.array(optimizedProperty).optional()}).optional(), scheme_info: z.object({name: z.enum(["cartes_bancaires", "visa", "mastercard"]).optional(), score: z.string().optional(), avalgo: z.string().optional()}).optional(), "3ds": z.object({challenge_request: z.string().optional(), interaction_counter: z.string().max(2).optional(), error_details: errorDetails.optional()}).optional(), preferred_experiences: preferredExperiences.optional(), experience: experience.optional(), google_spa: googleSpaInfo.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 session * * POST /sessions */ export const createApiSessions = async (args: CreateApiSessionsArgs, options: CreateApiSessionsOptions) => { 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 (OAuth !== undefined) headers.set('authorization', `Bearer ${OAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/sessions${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(createSessionOkResponse, await res.json()) };