Checkout.com Nuxt module
Stay connected
How to install
- Open your theme directory and run:
yarn add @vue-storefront/checkout-com
If you are Developing Core of Vue Storefront Next you might need to add @vue-storefront/checkout-com
to useRawSource
attribute in one of buildModules
:
['@vue-storefront/nuxt', {
coreDevelopment: true,
useRawSource: {
dev: [
'@vue-storefront/commercetools',
'@vue-storefront/core',
'@vue-storefront/checkout-com'
],
prod: [
'@vue-storefront/commercetools',
'@vue-storefront/core',
'@vue-storefront/checkout-com'
]
}
}],
- Open your
nuxt.config.js
- At the bottom of
modules
add:
['@vue-storefront/checkout-com/nuxt', {
channels: {
en: {
publicKey: 'pk_test_your-public-key',
secretKey: 'sk_test_your-secret-key',
ctApiUrl: 'https://your-commerctools-instance.com'
}
},
defaultChannel: 'en'
}],
defaultChannel
is the channel which will be chosen by default. Value should be keyname from channels
channels
allows us to define many variants of attributes. Developer is able to change them just by calling setChannel
publicKey
and secretKey
comes from Checkout COM
ctApiUrl
is base URL to the CT CKO API - do not put slash at the end!
Render payment handlers & finalize payment
- Import
useCko
:
import { useCko } from '@vue-storefront/checkout-com';
useCko
returns:
interface {
availableMethods: { name: string, [key: string]: any },
error: Error | null,
selectedPaymentMethod: CkoPaymentType,
storedPaymentInstruments: PaymentInstrument[],
submitDisabled: ComputedRef<boolean>,
storedContextId: ComputedRef<string>,
loadAvailableMethods: (cartId: string, email?: string): { id, apms },
initForm: (): void,
submitCardForm: (): void,
makePayment: ({ cartId, email, contextDataId, success_url, failure_url, secure3d, cvv, reference }): Promise<Response | void>,
setPaymentInstrument: (token: string): void,
setSavePaymentInstrument: (newSavePaymentInstrument: boolean): void,
loadSavePaymentInstrument: (): boolean,
removePaymentInstrument: (customerId: string, paymentInstrument: string): Promise<void>,
loadStoredPaymentInstruments: (customerId: string): Promise<void>
}
In this step you need:
const { cart } = useCart();
const { setBillingDetails } = useCheckout();
const { isAuthenticated, user } = useUser();
const {
initForm,
loadAvailableMethods,
availableMethods,
submitDisabled,
storedPaymentInstruments,
loadStoredPaymentInstruments,
submitKlarnaForm,
error
} = useCko();
setBillingDetails
to save billing address. So you will be able to fetch availableMethods
which base on your billing address (server-side)- Run
loadStoredPaymentInstruments
for logged in user to load stored payment instruments. They will be loaded to storedPaymentInstruments
array of PaymentInstrument
s. Caution: This interface is being used for storing credit cards currently. It might have different shape for stored different payment methods in the future. Interface:
interface PaymentInstrument {
id: string;
type: string;
expiry_month: number;
expiry_year: number;
scheme: string;
last4: string;
fingerprint: string;
bin: string;
card_type: string;
card_category: string;
issuer: string;
issuer_country: string;
product_id: string;
product_type: string;
avs_check: string;
cvv_check: string;
payouts: string;
fast_funds: string;
payment_instrument_id: string;
}
Example of usage:
if (isAuthenticated.value && cart.value && cart.value.customerId) {
await loadStoredPaymentInstruments(cart.value.customerId);
}
- Run
loadAvailableMethods
- first argument is cartId (access it via cart.value.id
) - second for authenticated customer is an email (access it via user.value.email
) - third for products, you can modify order products items. Then it will return interface { id, apms: Array<any> }
and set apms
inside availableMethods
. E.g:
onMounted(async () => {
await loadAvailableMethods(cart.value.id, user.value && user.value.email);
})
onMounted(async () => {
const products = [
{
id: "dbe4f68c",
name: "Product name",
quantity: 2,
price: 799,
tax_amount: 220,
type: "digital",
metadata: {
tax_rate: 1600,
reference: "ref",
image_url: "",
product_url: ""
}
}
];
await loadAvailableMethods(cart.value.id, user.value && user.value.email, products);
})
- Execute
initForm
. It mounts different payment handlers depends on arguments (check details below). If you are calling it after load component - use onMounted
to make sure DOM Element where it should be mounted already exists.
- Card's Frames will be mounted in DOM element with class
card-frame
. - PayPal & Sofort does not need any SDK, we just redirect to their's website like in 3DS redirection process for credit cards. So if you are interested only in this payment method you could omit this step.
- Klarna by default will be mounted in container with id
klarna_container
interface PaymentMethods {
card?: boolean;
klarna?: boolean;
}
interface PaymentMethodsConfig {
card?: Omit<Configuration, 'publicKey'>;
klarna?: any;
}
const initForm = (initMethods: PaymentMethods = null, config: PaymentMethodsConfig = {}): void
initMethods
- if it is null
- method will try to mount handler for each supported payment method
- if it is
{}
- nothing will be mounted - in object, you can specify which method you want to mount, e.g:
{ card: true }
but it will still check whether it is supported or not
config
allows to specify configuration for some payment handler, e.g. for card Frames we could use:
{
card: {
localization: 'es-ES'
}
}
This configuration will have bigger priority than one from nuxt.config.js
. The thing is you cannot overwrite is publicKey
there. Signature for Frames looks like that:
(params?: Omit<Configuration, 'publicKey'>): void
Unfortunately, Checkout.com is not sharing any component for Saved Cards. After using loadStoredPaymentInstruments
you can access an array of them via storedPaymentInstruments
. Show them to user in a way you want. To choose certain Stored Instrument call setPaymentInstrument(item.id)
where item
is single element of storePaymentInstruments
array.
setPaymentInstrument
will set transaction token in your sessionStorage for a moment to make it work even after the refresh. Then it will set selectedPaymentMethod
to CkoPaymentType.SAVED_CARD
.
-
When submitDisabled
changes to false - it means provided Card's data is proper and you could allow your user go forward. Card's token will be stored in sessionStorage for a moment.
-
Call submitCardForm
function on card form submit (only for Credit Card method - not necessary for Stored Payment Method). It requires mounted Frames
instance as it uses Frames.submitCard()
under the hood. If you are using Klarna please call submitKlarnaForm
(it returns promise) to authorize payment.
-
Then you need to make Payment
error
- contains error message from the response if you do not use 3ds or we have some server related issues. If the user just removed stored token from sessionStorage it will have There is no payment token
inside.
makePayment
- it proceeds with the payment and removes card token afterward. Returns Promise if succeed, or Promise if failed.
-
You should call makePayment
at first (remember to check if everything went ok):
const payment = await makePayment({ cartId: cart.value.id });
const payment = await makePayment({ cartId: cart.value.id, cvv: 1234 });
const payment = await makePayment({ cartId: cart.value.id, email: user.value && user.value.email });
const payment = await makePayment({ cartId: cart.value.id, email: user.value && user.value.email, cvv: 100 });
const payment = await makePayment();
if (error.value) {
console.error(error.value.message);
return;
}
-
If there is any error, you can access it via error.value
. Otherwise, it will be nullish
-
If no errors, place an order:
const order = await placeOrder();
payment.data.redirect_url
contains 3DS Auth redirect url for Credit Card if it requires it and it always contain redirect url for the PayPal and Sofort. You have to support it:
if (payment.data.redirect_url) {
window.location.href = payment.data.redirect_url;
return;
}
- After 3DS Auth/PayPal Auth/Sofort Auth, user will be redirected to one of these urls. They are being created inside
makePayment
method:
success_url: `${window.location.origin}/cko/payment-success`,
failure_url: `${window.location.origin}/cko/payment-error`
You can override them while calling makePayment
with success_url
and failure_url
attributes.
E.g:
await makePayment({
success_url: 'https://example.com/success',
failure_url: 'https://example.com/failure',
})
Would redirect after process to the:
success_url: 'https://example.com/success',
failure_url: 'https://example.com/failure'
- You should make sure that after user leaves checkout - payment token is being removed from sessionStorage. For that purpose,
useCko
exports removeTransactionToken
method. Call it when user exits Checkout's view! E.g:
import { useCko } from '@vue-storefront/checkout-com';
import { onUnmounted } from '@vue/composition-api';
export default {
setup() {
const { removeTransactionToken } = useCko();
onUnmounted(removeTransactionToken);
}
}
Changing current payment method
It is important to set proper CKO's Payment Method in useCko
instance so it will be able to figure out proper payload to send in makePayment
. To do that:
import { useCko, CkoPaymentType } from '@vue-storefront/checkout-com'
const {
initForm,
loadAvailableMethods,
submitCardForm,
makePayment,
setPaymentInstrument,
setSavePaymentInstrument,
loadSavePaymentInstrument,
selectedPaymentMethod,
loadStoredPaymentInstruments,
removePaymentInstrument,
storedPaymentInstruments,
submitDisabled,
error
} = useCko();
Currently, these are available payment methods:
enum CkoPaymentType {
NOT_SELECTED = 0,
CREDIT_CARD = 1,
SAVED_CARD,
KLARNA,
PAYPAL,
SOFORT
}
By default, selectedPaymentMethod
equals CkoPaymentType.NOT_SELECTED
.
If user uses stored payment call setSavePaymentInstrument
and it will set selectedPaymentMethod.value = CkoPaymentType.SAVED_CARD
setPaymentInstrument(item.id);
If user uses credit card use:
selectedPaymentMethod.value = CkoPaymentType.CREDIT_CARD
Allowing user to decide whether save payment instrument or not
useCko
composable shares loadSavePaymentInstrument
method and setSavePaymentInstrument
method for that purpose. It is being stored in the localStorage. E.g:
const {
initForm,
loadAvailableMethods,
submitCardForm,
makePayment,
setPaymentInstrument,
setSavePaymentInstrument,
loadSavePaymentInstrument,
selectedPaymentMethod,
loadStoredPaymentInstruments,
removePaymentInstrument,
storedPaymentInstruments,
submitDisabled,
error
} = useCko();
const savePaymentInstrument = ref(loadSavePaymentInstrument());
<SfCheckbox
@change="setSavePaymentInstrument(savePaymentInstrument)"
v-model="savePaymentInstrument"
label="Save payment instrument"
name="savePaymentInstrument"
class="form__element"
/>
Autoloading SDK
Checkout.com supports many payment methods, only a few have own SDKs - Credit Card & Klarna. By default, module fetches SDK only for Credit Card (Frames). You can customize it with module's config paymentMethods
attribute. E.g:
['@vue-storefront/checkout-com/nuxt', {
paymentMethods: {
cc: true,
klarna: true
}
}]
Customizing Frames
In nuxt.config.js
module's config you can use each attribute from this page, e.g:
['@vue-storefront/checkout-com/nuxt', {
card: {
localization: 'KO-KR',
style: {
'card-number': {
color: 'red'
},
base: {
color: '#72757e',
fontSize: '19px',
minWidth: '60px'
},
invalid: {
color: 'red'
},
placeholder: {
base: {
color: 'cyan',
fontSize: '50px'
}
}
}
}
}]
localization
attribute must be a string or fulfill CustomLocalization
interface:
interface CustomLocalization {
cardNumberPlaceholder: string;
expiryMonthPlaceholder: string;
expiryYearPlaceholder: string;
cvvPlaceholder: string;
}
Customizing Klarna
In nuxt.config.js
and initForm
method call you can configure Klarna component.
E.g:
['@vue-storefront/checkout-com/nuxt', {
klarna: {
containerSelector: '#my-klarna-div',
beforeLoad ({ apm, options, data }) {
return {
options,
data
}
}
}
}]
Also you can modify merchant_reference1 and customer phone on call initForm. For example:
const {
initForm,
availableMethods
} = useCko();
onMounted(async () => {
await loadAvailableMethods(cart.value.id, user.value && user.value.email);
initForm({ klarna: true },
{
klarna: {
beforeLoad({ options, data }) {
data.merchant_reference1 = cart.value?.custom?.merchant_reference;
data.billing_address.phone = billingDetails.value.phone;
return { options, data };
}
}
}
);
})
beforeLoad
- hook that allows you to modify options
and data
(first and second argument) used to call Klarna.Payments.load
Fetching available payment methods
At first, you have to save billing address in your backend to do that. You can do it just after setBillingDetails
call from Creadit card component
step. Then you can easily use loadAvailableMethods
method. It requires reference as the first argument - which is cartId. E.g:
const { cart } = useCart();
const { user } = useUser();
const { loadAvailableMethods, availableMethods } = useCko();
const { setBillingDetails } = useCheckout();
const handleFormSubmit = async () => {
await setBillingDetails(billingDetails.value, { save: true });
const response = await loadAvailableMethods(cart.value.id);
const response = await loadAvailableMethods(cart.value.id, user.value.email);
console.log('Server respond with ', response)
console.log('Array of available payment methods ', availableMethods)
};
Response might look like:
{
"id": "cid_XXX",
"apms": [
{
"name": "paypal",
"schema": "https://somewebsite.com/apms/paypal.json",
"show": true
}
]
}
availableMethods
might look like:
[
{
"name": "card"
},
{
"name": "klarna",
"some_key": "123"
},
{
"name": "paypal",
"some_key": "456"
}
]
Removing Stored Payment Instrument
useCko
composable shares removePaymentInstrument
method for that purpose. Keep in mind you use storedPaymentMethods[i].id
for payment but storedPaymentMethods[i].payment_instrument
for removing it from the vault. Use it like:
const {
removePaymentInstrument,
} = useCko();
const { isAuthenticated } = useUser();
const { cart } = useCart();
const removeMinePaymentInstrument = async (paymentInstrument: string): Promise<void> => {
if (isAuthenticated.value && cart.value && cart.value.customerId) {
await removePaymentInstrument(cart.value.customerId, paymentInstrument);
}
}
Changing current channel
All you have to do is just import setChannel
method and call it:
import { setChannel } from '@vue-storefront/checkout-com';
setChannel('it');
Where it
is name of channel to set. It should be present inside config's channels
.
Sending CVV
To send CVV for saved payment instrument just add cvv
attribute to object provided inside makePayment
, e.g:
const payment = await makePayment({ cartId: cart.value.id, cvv: 1234 });
const payment = await makePayment({ cartId: cart.value.id, email: user.value && user.value.email, cvv: 100 });
You might wonder how you could learn whether you have to provide CVV for saved card or not. For that, I shared isCvvRequired
computed boolean in useCko
. It's value bases on loadAvailableMethods
response. So you have to call this method before. If you didn't provide cvv
to makePayment
and it requires it - then it will throw an error.
Downgrade payments to non-3DS
There are banks (especially in US) which do not support any version of 3DS standard. You can instruct the makePayment
method to attempt non-3DS payment in case customer's card is not enrolled for 3DS using attempt_n3d
parameter. Visit checkout.com docs for more details. Please note: if you downgrade the payment to non-3DS, the liability shift advantage of 3DS2 will not apply, meaning you will not be protected against potentially fraudulent payments or chargebacks.
const payment = await makePayment({ cartId: cart.value.id, cvv: 1234, attempt_n3d: true });