Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 93 additions & 75 deletions src/api/hosted-payments/hosted-payments.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,93 @@
import { determineError } from '../../services/errors.js';
import { get, post } from '../../services/http.js';

// Path segments appended to the API base (config.host).
const HOSTED_PAYMENTS_PATH = 'hosted-payments';

/**
* Class dealing with the /hosted-payments endpoint
*
* @export
* @class HostedPayments
*/
export default class HostedPayments {
constructor(config) {
this.config = config;
}

/**
* Create a Hosted Payments Page session.
*
* Notable optional fields (swagger HostedPaymentsRequest, 2026-06-08):
* - body.authorization_type — e.g. `Estimated`, `Final`.
* - body.3ds.challenge_indicator — four values only (default
* `no_preference`): `no_preference`, `no_challenge_requested`,
* `challenge_requested`, `challenge_requested_mandate`. The exemption
* values (`low_value`, `trusted_listing`, `trusted_listing_prompt`,
* `transaction_risk_assessment`, `data_share`) are accepted only by
* `cko.sessions.request` and are rejected here.
* - body.payment_plan — installment / recurring schedule
* (`amount`, `name`, `start_date` added 2026-05-08).
*
* @memberof HostedPayments
* @param {Object} body - Hosted Payments Page session request body
* @return {Promise<Object>} A promise to the Hosted Payment response.
*/
async create(body) {
try {
const response = await post(
this.config.httpClient,
`${this.config.host}/${HOSTED_PAYMENTS_PATH}`,
this.config,
this.config.sk,
body
);
return await response.json;
} catch (err) {
throw await determineError(err);
}
}

/**
* Get Hosted Payments Page details
*
* The response (swagger GetHostedPaymentsResponse) includes a `_links`
* object with `self` and `redirect` links, plus `payment` and
* `payment_actions` once a payment is in progress or completed.
*
* @memberof HostedPayments
* @param {string} id - Hosted payment id
* @return {Promise<Object>} A promise to the Hosted Payment response.
*/
async get(id) {
try {
const response = await get(
this.config.httpClient,
`${this.config.host}/${HOSTED_PAYMENTS_PATH}/${id}`,
this.config,
this.config.sk
);
return await response.json;
} catch (err) {
throw await determineError(err);
}
}
}
import { determineError } from '../../services/errors.js';
import { get, post } from '../../services/http.js';

// Path segments appended to the API base (config.host).
const HOSTED_PAYMENTS_PATH = 'hosted-payments';

/**
* Class dealing with the /hosted-payments endpoint
*
* @export
* @class HostedPayments
*/
export default class HostedPayments {
constructor(config) {
this.config = config;
}

/**
* Create a Hosted Payments Page session.
*
* Notable optional fields (swagger HostedPaymentsRequest, 2026-06-08):
* - body.authorization_type — e.g. `Estimated`, `Final`.
* - body.3ds.challenge_indicator — four values only (default
* `no_preference`): `no_preference`, `no_challenge_requested`,
* `challenge_requested`, `challenge_requested_mandate`. The exemption
* values (`low_value`, `trusted_listing`, `trusted_listing_prompt`,
* `transaction_risk_assessment`, `data_share`) are accepted only by
* `cko.sessions.request` and are rejected here.
* - body.payment_plan — installment / recurring schedule
* (`amount`, `name`, `start_date` added 2026-05-08).
* - body.processing.airline_data: optional array of
* PaymentInterfacesProcessingAirlineData: `ticket`, `passenger` and
* `flight_leg_details`. See the `cko.payments.request` JSDoc for the full nested shape.
* - body.processing.accommodation_data: optional array of
* PaymentInterfacesProcessingAccommodationData: the same eleven fields as
* `cko.payments.request` **minus** `property_phone` and `customer_service_phone`. Those
* two are declared on `AccommodationData` only, so they are read by `POST /payments` and
* payment contexts and ignored here.
*
* **Send `passenger` as a single object here, never an array.** Verified against the
* sandbox on 2026-09-28: an array is rejected with 422
* `processing_airline_data_0_passenger_invalid` on this endpoint, while a single
* `{ first_name, last_name, date_of_birth [date], address: { country } }` object is
* accepted. This inverts the specification, which declares the property array-only on
* `AirlineData` and `oneOf[array, object]` here. Only `POST /payments` and
* `POST /payment-sessions` accept the array form, so several passengers cannot be
* expressed on this endpoint at all. Omit the key entirely when there are no passengers:
* an empty array and an explicit `null` are both rejected too.
*
* @memberof HostedPayments
* @param {Object} body - Hosted Payments Page session request body
* @return {Promise<Object>} A promise to the Hosted Payment response.
*/
async create(body) {
try {
const response = await post(
this.config.httpClient,
`${this.config.host}/${HOSTED_PAYMENTS_PATH}`,
this.config,
this.config.sk,
body
);
return await response.json;
} catch (err) {
throw await determineError(err);
}
}

/**
* Get Hosted Payments Page details
*
* The response (swagger GetHostedPaymentsResponse) includes a `_links`
* object with `self` and `redirect` links, plus `payment` and
* `payment_actions` once a payment is in progress or completed.
*
* @memberof HostedPayments
* @param {string} id - Hosted payment id
* @return {Promise<Object>} A promise to the Hosted Payment response.
*/
async get(id) {
try {
const response = await get(
this.config.httpClient,
`${this.config.host}/${HOSTED_PAYMENTS_PATH}/${id}`,
this.config,
this.config.sk
);
return await response.json;
} catch (err) {
throw await determineError(err);
}
}
}
35 changes: 35 additions & 0 deletions src/api/payment-contexts/payment-contexts.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,29 @@ export default class PaymentContexts {
/**
* Request a Payment Context.
*
* Notable optional fields (swagger PaymentContext / PaymentContextProcessing):
* - body.processing.airline_data: optional array of AirlineData: `ticket`, `passenger` and
* `flight_leg_details`. See the `cko.payments.request` JSDoc for the full nested shape.
* - body.processing.accommodation_data: optional array of AccommodationData, the full
* thirteen-field shape **including** `property_phone` and `customer_service_phone`.
* Payment contexts resolves to the same `AccommodationData` schema as `POST /payments`,
* unlike hosted payments, payment links and payment sessions, which resolve to the
* narrower `PaymentInterfacesProcessingAccommodationData` without the two phone arrays.
*
* **Send `passenger` as a single object here, never an array.** Verified against the
* sandbox on 2026-09-28: an array is rejected with 422 `passenger_required`, a different
* error code from the `processing_airline_data_0_passenger_invalid` that hosted payments
* and payment links return, while a single
* `{ first_name, last_name, date_of_birth [date], address: { country } }` object is
* accepted. The specification declares this property array-only, so it is exactly
* inverted here. Several passengers cannot be expressed on this endpoint.
* - body.processing.airline_data[].flight_leg_details[].stop_over_code: **do not send
* this on payment contexts.** The endpoint rejects every value for it with 422
* `flight_leg_detail_stop_over_code_invalid`, including the specification's own example
* `"x"`, while accepting the identical flight leg with the key omitted. Confirmed by
* sending the same request twice on 2026-09-28, once with the key and once without: the
* code appears only in the first. The other eight flight-leg fields are fine.
*
* @memberof PaymentContexts
* @param {object} body PaymentContexts Request body.
* @param {string} [idempotencyKey] Idempotency Key.
Expand Down Expand Up @@ -48,6 +71,18 @@ export default class PaymentContexts {
* Response now carries an `id` field on `PaymentContextDetails` (swagger 2026-05-26)
* — the payment-context identifier echoed back in the response.
*
* Response fields available under `payment_request.processing` (pass-through, swagger
* `PaymentContextDetails`):
* - airline_data: array of AirlineData, each entry with `ticket`, `passenger` and
* `flight_leg_details`. See the `cko.payments.request` JSDoc for the full nested shape.
* - accommodation_data: array of AccommodationData, the full thirteen-field shape including
* `property_phone` and `customer_service_phone`.
*
* **Read `passenger` defensively: it may be a single object or an array.** The
* specification declares it array-only, but a single passenger is sent and echoed back as
* a bare object. This client returns `response.json` untouched, so whichever shape the API
* returns is the shape the caller receives.
*
* @memberof PaymentContexts
* @param {string} id /^(pay|sid)_(\w{26})$/ The payment or payment session identifier.
* @return {Promise<object>} A promise to the get payment context response.
Expand Down
24 changes: 24 additions & 0 deletions src/api/payment-sessions/payment-sessions.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ export default class PaymentSessions {
* - body.payment_plan — installment / recurring schedule. See swagger
* `PaymentSessionPaymentPlanRecurring` for the recurring variant
* (fields: amount, name, start_date — added 2026-05-08).
* - body.processing.airline_data: optional array of
* PaymentInterfacesProcessingAirlineData: `ticket`, `passenger` and
* `flight_leg_details`. See the `cko.payments.request` JSDoc for the full nested shape.
* - body.processing.accommodation_data: optional array of
* PaymentInterfacesProcessingAccommodationData: the same eleven fields as
* `cko.payments.request` **minus** `property_phone` and `customer_service_phone`. Those
* two are declared on `AccommodationData` only, so they are read by `POST /payments` and
* payment contexts and ignored here.
*
* **`passenger` accepts either a single object or an array on this endpoint.** Verified
* against the sandbox on 2026-09-28: both forms return 201. That makes payment sessions
* the exception among the payment-interfaces endpoints. Hosted payments and payment links
* resolve to the *same* `PaymentInterfacesProcessing` schema yet reject the array with
* 422 `processing_airline_data_0_passenger_invalid`, so the shared schema is not a
* reliable guide to which form a surface takes and each has to be tested. A single object
* is still the safer default, being the one form every surface accepts. Omit the key
* entirely when there are no passengers.
*
* @memberof PaymentSessions
* @param {object} body PaymentSessions Request body.
Expand Down Expand Up @@ -101,6 +118,13 @@ export default class PaymentSessions {
* values (`low_value`, `trusted_listing`, `trusted_listing_prompt`,
* `transaction_risk_assessment`, `data_share`) are accepted only by
* `cko.sessions.request` and are rejected here.
* - body.processing.airline_data and body.processing.accommodation_data: accepted here too.
* The request schema `CreateAndSubmitPaymentSessionsRequest` composes the same
* `CreatePaymentSessionsBaseRequest` that `cko.paymentSessions.request` uses, so both
* fields and the `PaymentInterfacesProcessing` shape apply unchanged. See the `request`
* JSDoc above for the fields and the `passenger` cardinality, and
* `cko.payments.request` for the full nested shape. As on `request`, both a single
* `passenger` object and an array are accepted on this endpoint.
*
* @memberof PaymentSessions
* @param {object} body PaymentSessions Request body.
Expand Down
9 changes: 8 additions & 1 deletion src/api/payment-setups/payment-setups.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ export default class PaymentSetups {
* PaymentSetupAirline (all fields optional): ticket (object: number, issue_date [date],
* issuing_carrier_code, travel_package_indicator [free-form string], travel_agency_name, travel_agency_code),
* passengers (array of { first_name, last_name, date_of_birth [date], address: { country [ISO 3166-1 alpha-2] } }),
* flight_leg_details (array of PaymentSetupFlightLegDetails),
* flight_leg_details (array of PaymentSetupFlightLegDetails: flight_number [string,
* e.g. "BA1483", not a number], carrier_code [IATA 2-letter accounting code],
* class_of_travelling [one-letter travel class, e.g. "W"], departure_airport [IATA
* 3-letter], departure_date [date format], departure_time [e.g. "18:30"],
* arrival_airport [IATA 3-letter], stop_over_code [one letter, e.g. "X"],
* fare_basis_code [e.g. "WUP14B"]. Note class_of_travelling with two l's and
* stop_over_code as three words: six SDKs previously shipped service_class,
* class_of_traveling or stopover_code here and the values never reached the API),
* total_number_of_passengers (integer, added 2026-09-08), travel_type (string, added 2026-09-08; free-form,
* not a typed enum), trip_type (string, added 2026-09-08; free-form, not a typed enum),
* refundable (boolean, added 2026-09-08), delivery_recipient (string, added 2026-09-08; plain string,
Expand Down
Loading
Loading