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
32 changes: 28 additions & 4 deletions src/api/payment-setups/payment-setups.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ export default class PaymentSetups {
* Creates a Payment Setup.
* To maximize the amount of information the payment setup can use, we recommend that you create a payment setup as early
* as possible in the customer's journey. For example, the first time they land on the basket page.
*
* Request/response (swagger `PaymentSetup`, 2026-05-26) may also include:
* - billing_descriptor — optional PaymentSetupBillingDescriptor: name (string, max 25 characters),
* city (string, max 13 characters), reference (string, max 50 characters).
* - presentment_details — optional PaymentSetupPresentmentDetails: amount (integer, int64),
* currency (string).
* - terminal — optional PaymentSetupTerminal: id (string, min 8 / max 8 characters),
* local_date_time (string, date-time format).
*
* @memberof PaymentSetups
* @param {Object} body - Request body
* @returns {Promise<Object>} A promise to the Create a Payment Setup response
Expand Down Expand Up @@ -46,6 +55,15 @@ export default class PaymentSetups {
* Updates a Payment Setup.
* You should update the payment setup whenever there are significant changes in the data relevant to the customer's
* transaction. For example, when the customer makes a change that impacts the total payment amount.
*
* Request/response (swagger `PaymentSetup`, 2026-05-26) may also include:
* - billing_descriptor — optional PaymentSetupBillingDescriptor: name (string, max 25 characters),
* city (string, max 13 characters), reference (string, max 50 characters).
* - presentment_details — optional PaymentSetupPresentmentDetails: amount (integer, int64),
* currency (string).
* - terminal — optional PaymentSetupTerminal: id (string, min 8 / max 8 characters),
* local_date_time (string, date-time format).
*
* @memberof PaymentSetups
* @param {string} id - The unique identifier of the Payment Setup to update.
* @param {Object} body - Request body
Expand Down Expand Up @@ -78,6 +96,12 @@ export default class PaymentSetups {
* when the setup was created with one. See
* `PaymentSetupAccountFundingTransaction` in swagger for sender /
* recipient / identification shapes.
* - billing_descriptor — optional PaymentSetupBillingDescriptor: name (string, max 25 characters),
* city (string, max 13 characters), reference (string, max 50 characters).
* - presentment_details — optional PaymentSetupPresentmentDetails: amount (integer, int64),
* currency (string).
* - terminal — optional PaymentSetupTerminal: id (string, min 8 / max 8 characters),
* local_date_time (string, date-time format).
*
* @memberof PaymentSetups
* @param {string} id - The unique identifier of the Payment Setup to retrieve.
Expand All @@ -101,15 +125,15 @@ export default class PaymentSetups {
/**
* Confirm a Payment Setup
* [BETA]
* Confirm a Payment Setup to begin processing the payment request with your chosen payment method option.
* Confirm a Payment Setup to begin processing the payment request with your chosen payment method.
* @memberof PaymentSetups
* @param {string} id - The unique identifier of the Payment Setup.
* @param {string} payment_method_option_id - The unique identifier of the payment option to process the payment with.
* @param {string} payment_method_name - The name of the payment method to process the payment with (e.g. "tabby", "klarna", "card").
* @returns {Promise<Object>} A promise to the Confirm a Payment Setup response
*/
async confirmAPaymentSetup(id, payment_method_option_id) {
async confirmAPaymentSetup(id, payment_method_name) {
try {
const url = `${this.config.host}/payments/setups/${id}/confirm/${payment_method_option_id}`;
const url = `${this.config.host}/payments/setups/${id}/confirm/${payment_method_name}`;
const response = await post(
this.config.httpClient,
url,
Expand Down
210 changes: 191 additions & 19 deletions test/payment-setups/payment-setups-unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,18 @@ describe('Unit::Payment-Setups', () => {
};

nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups/pay_setup_123/confirm/pmo_456')
.post('/payments/setups/pay_setup_123/confirm/tabby')
.reply(201, response
);

// Act
const id = "pay_setup_123";
const payment_method_option_id = "pmo_456";
const payment_method_name = "tabby";

const SK = 'sk_test_xxx';
const cko = new Checkout(SK, { subdomain: '123456789' });

const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_option_id);
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_name);

// Assert
expect(result).to.deep.equal(response);
Expand All @@ -113,20 +113,20 @@ describe('Unit::Payment-Setups', () => {
const response = {};

nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups/pay_setup_123/confirm/pmo_456')
.post('/payments/setups/pay_setup_123/confirm/tabby')
.reply(400
);

// Act
const id = "pay_setup_123";
const payment_method_option_id = "pmo_456";
const payment_method_name = "tabby";

const SK = 'sk_test_xxx';
const cko = new Checkout(SK, { subdomain: '123456789' });

try
{
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_option_id);
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_name);
} catch (error) {
err = error;
}
Expand All @@ -143,22 +143,22 @@ describe('Unit::Payment-Setups', () => {
const response = {};

nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups/pay_setup_123/confirm/pmo_456')
.post('/payments/setups/pay_setup_123/confirm/tabby')
.reply(401
);

// Act
const id = "pay_setup_123";
const payment_method_option_id = "pmo_456";
const payment_method_name = "tabby";

const SK = 'sk_test_xxx';
const cko = new Checkout(SK, { subdomain: '123456789' });

try
{
const id = "pay_setup_123";
const payment_method_option_id = "pmo_456";
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_option_id);
const payment_method_name = "tabby";
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_name);
} catch (error) {
err = error;
}
Expand All @@ -175,20 +175,20 @@ describe('Unit::Payment-Setups', () => {
const response = {};

nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups/pay_setup_123/confirm/pmo_456')
.post('/payments/setups/pay_setup_123/confirm/tabby')
.reply(403
);

// Act
const id = "pay_setup_123";
const payment_method_option_id = "pmo_456";
const payment_method_name = "tabby";

const SK = 'sk_test_xxx';
const cko = new Checkout(SK, { subdomain: '123456789' });

try
{
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_option_id);
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_name);
} catch (error) {
err = error;
}
Expand All @@ -211,20 +211,20 @@ describe('Unit::Payment-Setups', () => {
};

nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups/pay_setup_123/confirm/pmo_456')
.post('/payments/setups/pay_setup_123/confirm/tabby')
.reply(422
);

// Act
const id = "pay_setup_123";
const payment_method_option_id = "pmo_456";
const payment_method_name = "tabby";

const SK = 'sk_test_xxx';
const cko = new Checkout(SK, { subdomain: '123456789' });

try
{
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_option_id);
const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_name);
} catch (error) {
err = error;
}
Expand All @@ -235,6 +235,101 @@ describe('Unit::Payment-Setups', () => {

});

describe('Create payment setup - Success (200) with billing_descriptor, presentment_details and terminal', () => {
it('should send and receive billing_descriptor, presentment_details and terminal', async () => {
// Arrange
const request = {
processing_channel_id: 'pc_q4dbxom5jbgudnjzjpz7j2z6uq',
amount: 10000,
currency: 'GBP',
payment_type: 'Regular',
reference: 'REF-0987-475',
description: 'Set of three t-shirts.',
billing_descriptor: {
name: 'Checkout.com',
city: 'London',
reference: 'Payment for order 123456'
},
presentment_details: {
amount: 110,
currency: 'EUR'
},
terminal: {
id: '12345678',
local_date_time: '2026-05-26T13:05:14+01:00'
}
};

const response = {
id: 'psu_mbabizu24mvu3mela5njyhpit4',
processing_channel_id: 'pc_q4dbxom5jbgudnjzjpz7j2z6uq',
amount: 10000,
currency: 'GBP',
payment_type: 'Regular',
reference: 'REF-0987-475',
description: 'Set of three t-shirts.',
billing_descriptor: {
name: 'Checkout.com',
city: 'London',
reference: 'Payment for order 123456'
},
presentment_details: {
amount: 110,
currency: 'EUR'
},
terminal: {
id: '12345678',
local_date_time: '2026-05-26T13:05:14+01:00'
}
};

nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups', request)
.reply(200, response
);

// Act
const SK = 'sk_test_xxx';
const cko = new Checkout(SK, { subdomain: '123456789' });

const result = await cko.paymentSetups.createAPaymentSetup(request);

// Assert
expect(result).to.deep.equal(response);
expect(result.billing_descriptor).to.deep.equal(request.billing_descriptor);
expect(result.presentment_details).to.deep.equal(request.presentment_details);
expect(result.terminal).to.deep.equal(request.terminal);
});
});

describe('Confirm payment setup - uses payment_method_name path segment', () => {
it('should build the confirm URL with the payment_method_name value, not payment_method_option_id', async () => {
// Arrange
const response = {
id: 'pay_mbabizu24mvu3mela5njyhpit4',
status: 'Authorized',
approved: true
};

nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups/pay_setup_123/confirm/klarna')
.reply(201, response
);

// Act
const id = "pay_setup_123";
const payment_method_name = "klarna";

const SK = 'sk_test_xxx';
const cko = new Checkout(SK, { subdomain: '123456789' });

const result = await cko.paymentSetups.confirmAPaymentSetup(id, payment_method_name);

// Assert
expect(result).to.deep.equal(response);
});
});

describe('Create payment setup - Success (200)', () => {
it('should create payment setup with payment method options', async () => {
// Arrange
Expand Down Expand Up @@ -3044,19 +3139,96 @@ describe('Unit::Payment-Setups', () => {
});

describe('Confirm payment setup - End-to-end flow', () => {
it('should successfully confirm payment setup with payment method option', async () => {
it('should successfully confirm payment setup with payment method name', async () => {
nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups/psu_abc123/confirm/pmo_abc123')
.post('/payments/setups/psu_abc123/confirm/tabby')
.reply(200, {
id: "psu_abc123",
status: "confirmed"
});

const cko = new Checkout('sk_test_0b9b5db6-f223-49d0-b68f-f6643dd4f808', { subdomain: '123456789' });
const response = await cko.paymentSetups.confirmAPaymentSetup("psu_abc123", "pmo_abc123");
const response = await cko.paymentSetups.confirmAPaymentSetup("psu_abc123", "tabby");

expect(response).to.not.be.null;
expect(response.status).to.equal("confirmed");
});

it('should build the confirm URL from id and payment_method_name (not payment_method_option_id)', async () => {
// Arrange: the path param is `payment_method_name` in swagger, e.g. "tabby"
const scope = nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups/pay_setup_123/confirm/tabby')
.reply(200, { id: 'pay_setup_123', status: 'confirmed' });

const cko = new Checkout('sk_test_xxx', { subdomain: '123456789' });

// Act
const result = await cko.paymentSetups.confirmAPaymentSetup('pay_setup_123', 'tabby');

// Assert
expect(scope.isDone()).to.be.true;
expect(result).to.deep.equal({ id: 'pay_setup_123', status: 'confirmed' });
});
});

describe('Create payment setup - billing_descriptor, presentment_details and terminal', () => {
it('should send and receive billing_descriptor, presentment_details and terminal', async () => {
// Arrange
const request = {
processing_channel_id: 'pc_q4dbxom5jbgudnjzjpz7j2z6uq',
amount: 10000,
currency: 'GBP',
payment_type: 'Regular',
billing_descriptor: {
name: 'Checkout.com',
city: 'London',
reference: 'REF-0987-475'
},
presentment_details: {
amount: 10000,
currency: 'GBP'
},
terminal: {
id: 'TID12345',
local_date_time: '2026-01-01T10:00:00Z'
}
};

const response = {
id: 'psu_wmakpe4nrza3rv2vhtwzoszja',
processing_channel_id: 'pc_q4dbxom5jbgudnjzjpz7j2z6uq',
amount: 10000,
currency: 'GBP',
payment_type: 'Regular',
billing_descriptor: {
name: 'Checkout.com',
city: 'London',
reference: 'REF-0987-475'
},
presentment_details: {
amount: 10000,
currency: 'GBP'
},
terminal: {
id: 'TID12345',
local_date_time: '2026-01-01T10:00:00Z'
}
};

nock('https://123456789.api.sandbox.checkout.com')
.post('/payments/setups', request)
.reply(200, response);

// Act
const SK = 'sk_test_xxx';
const cko = new Checkout(SK, { subdomain: '123456789' });
const result = await cko.paymentSetups.createAPaymentSetup(request);

// Assert
expect(result).to.deep.equal(response);
expect(result.billing_descriptor).to.deep.equal(request.billing_descriptor);
expect(result.presentment_details).to.deep.equal(request.presentment_details);
expect(result.terminal).to.deep.equal(request.terminal);
});
});
});
Loading