Skip to main content

Checkout script

What is Centra CheckoutScript?

In the selection response, if Klarna Checkout, Qliro One or Ingrid are active on the selection, Centra will return an element called centraCheckoutScript. It registers an event for events triggered by the widgets which need to be passed down to Centra, and convenience functions for suspension and resume of the widgets. If you get the centraCheckoutScript in the selection response, you should add it to your page so that it's picked up.

Events

Embed the script onto your page. You will also need to add an event listener for centra_checkout_callback. This event listener receives events from checkout widgets and sends them back to Centra.

document.addEventListener(
'centra_checkout_callback',
async function (event: CheckoutEvent) {
try {
// graphql client ie. apollo client
await gqlFetch(
graphql(`
mutation widgetEvent($payload: Map!) {
handleWidgetEvent(payload: $payload) {
selection {
...checkout
}
userErrors {
message
path
}
}
}
`),
{
variables: {
payload: event.detail,
},
}
);
} finally {
CentraCheckout.resume(event.detail.additionalFields?.suspendIgnore);
}
}
);

Suspend() and Resume()

When you change the selection in the checkout whilst Klarna Checkout, Qliro One or Ingrid plugin is loaded, they need to get updated with the same data Centra has, while Centra does most of the heavy lifting here, like sending data to the Klarna, Qliro One and Ingrid. Your website, however, needs to suspend and resume the widgets. The CentraCheckout object has functions for suspending and resuming Klarna Checkout, Qliro One and Ingrid, depending on which are loaded from Centra. They are CentraCheckout.suspend() and CentraCheckout.resume() respectively.

Here's an example:

// Perform quantity change of a selection line
async function updateLineOnCheckout(lineId: string, quantity: number) {
try {
CentraCheckout?.suspend(); // suspend Klarna, Qliro One and Ingrid
// graphql client ie. apollo client
const response = await gqlFetch(
graphql(`
mutation updateLineCheckout($id: String!, $quantity: Int!) {
updateLine(lineId: $id, quantity: $quantity) {
userErrors {
message
path
}
selection {
...checkout
}
}
}
`),
{
id: lineId,
quantity: quantity,
},
);
updateCheckout(response.data.updateLine.selection.checkout); // Update checkout data from response
} finally {
CentraCheckout?.resume();
}
}

TypeScript Types

If you're using TypeScript, you can use the following type definitions for the checkout events and the CentraCheckout global object.

Event Address

The address structure used in payment events:

export interface EventAddress {
country: string;
state?: string;
email?: string;
firstName?: string;
lastName?: string;
address1?: string;
address2?: string;
city?: string;
zipCode?: string;
phoneNumber?: string;
companyName?: string;
vatNumber?: string;
}

Event Payloads

export type PaymentPayload = {
responseEventRequired?: boolean;
paymentMethod: string | number;
paymentMethodSpecificFields: Record<string, unknown>;
} & (
| {
addressIncluded: true;
shippingAddress: EventAddress;
billingAddress: EventAddress;
}
| { addressIncluded: false }
);

export type ShippingMethodChangedPayload = {
shippingMethod: string;
};

export type ShippingAddressChangedPayload = {
shippingCountry: string;
shippingState: string;
shippingZipCode: string | undefined;
shippingCity: string | undefined;
};

Custom Events

export type ShippingMethodChangedEvent =
CustomEvent<ShippingMethodChangedPayload>;
export type ShippingAddressChangedEvent =
CustomEvent<ShippingAddressChangedPayload>;
export type PaymentEvent = CustomEvent<PaymentPayload>;
export type CheckoutEvent = CustomEvent<
Record<string, unknown> & { additionalFields?: { suspendIgnore?: unknown } }
>;

Global Declarations

Add these declarations to extend the global Window and DocumentEventMap interfaces:

declare global {
interface Window {
CentraCheckout?: {
suspend: (...args: unknown[]) => void;
resume: (...args: unknown[]) => void;
reInitiate: (handler: 'ingrid' | (string & {})) => void;
destroy: VoidFunction;
};
// Ingrid/Shipwallet
_sw?: (callback: (api: { destroy?: VoidFunction }) => void) => void;
// Qliro One
totalPrice?: number;
}

interface DocumentEventMap {
centra_checkout_callback: CheckoutEvent;
centra_checkout_payment_callback: PaymentEvent;
centra_checkout_shipping_method_callback: ShippingMethodChangedEvent;
centra_checkout_shipping_address_callback: ShippingAddressChangedEvent;
}
}

With these declarations, TypeScript will provide proper type inference when adding event listeners:

document.addEventListener('centra_checkout_callback', event => {
// event.detail is properly typed as Record<string, unknown> & { additionalFields?: { suspendIgnore?: unknown } }
window.CentraCheckout?.resume(event.detail.additionalFields?.suspendIgnore);
});

document.addEventListener('centra_checkout_payment_callback', event => {
// event.detail is properly typed as PaymentPayload
if (event.detail.addressIncluded) {
console.log(event.detail.shippingAddress.country);
}
});