Checkout
The Checkout and Selection fields together enable you to build a fully functional checkout. Query the Checkout field to trigger shipping and tax calculations, which require details like the full ship-to address.
It is advised to always query Checkout field if the customer is on the checkout page or the mutation was instantiated from the checkout page.
Checkout and payments are the most complex parts of any e-commerce site. Carefully follow these instructions. Even if you don't encounter certain PaymentAction flows during development, they may appear in production due to Payment Service Provider configuration changes.
Elements of the checkout
There are a few key elements to any Checkout:
- Showing the contents and totals of the cart
- Modifying the cart contents (quantities, adding upsell products shown on the Checkout)
- Handling of code vouchers
- Collecting the shoppers address
- How the goods shall be delivered
- Choosing the paymentMethod
- Collecting the payment.
These elements interact with each other and must remain accurately represented as data changes. The Storefront API always returns the last valid state of the Selection and Checkout, so you can rely on the response even if you receive userErrors.
As always it’s good to have a solid understanding of each field’s contents, purpose and dependencies so let’s break them down.
addressFields
These are the form fields the Storefront API accepts as shopper input to the setAddress and paymentInstructions mutations. They are divided into shippingAddress, separateBillingAddress, termsAndConditions and newsletter.
The AddressField interface exposes three properties: key, visible and required. Use these to correctly collect all necessary information before proceeding to payment. These properties match HTML form field properties.
The list of required and visible fields is dynamic depending on your country and your selected PaymentMethod.
For example, Sweden has no states, so the state field won't be visible or required. The US, however, requires it. Some PaymentMethods allow you to collect the address on their Hosted Payment Page or within an iframe ("address after payment"), in which case only shippingCountry.country (and state if applicable) are required and visible.
The Centra admin can configure required fields in the Storefront API plugin. Note that for "address after payment" payment methods, these can be overridden.
The shippingAddress and separateBillingAddress fields are presented as lists, allowing you to loop through them to generate form inputs for the setAddress mutation. The current value of each field can be found in the [shipping|separateBilling]Address properties of the Checkout object. You can override the default field sort order based on your design needs.
paymentMethods
The available payment methods for the current selection
The availability of a PaymentMethod is configured in the Centra admin based on the following factors: shippingAddress.country, market, pricelist and language.
There is additional filtering done by the Storefront API after the payment methods have been filtered based on their configuration;
- if the contents of the cart doesn’t meet the minimum order value required by the PSP it will be filtered out.
- if your cart contains any line with a subscription plan attached to it and the PSP doesn’t support recurring payments it will be filtered out.
PaymentMethods are filtered by the Storefront API based on session data. Always display all returned methods.
If there hasn’t been any active choice of PaymentMethod the first one will always be the active one, you can control the sort order of the PaymentMethods based on it’s kind. Per default they are sorted by the internal plugin name.
Any logos or similar should be based on the PaymentMethod.kind field and not bound to an id or name as these are subject to change.
The Storefront API has support for following PaymentMethods:
| Payment plugin | PaymentMethodKind |
|---|---|
| Adyen Drop-in | ADYEN_DROPIN |
| * Test Payment (Dummy) | DUMMY |
| External Payment | EXTERNAL_PAYMENT |
| Klarna Checkout V3 | KLARNA_CHECKOUT_V3 |
| Klarna Payments | KLARNA_PAYMENTS |
| PayPal Commerce | PAYPAL_COMMERCE |
| Qliro One | QLIRO_ONE |
| Stripe Checkout (Beta) | STRIPE_CHECKOUT |
| Stripe Payment Intents (Beta) | STRIPE_PAYMENT_INTENTS |
shippingMethods
The available shipping methods configured within Centra for the current selection
The availability of a ShippingMethod is configured based on the Selection's Currency, market, country and state(if applicable). Additionally in order for a ShippingMethod to be available the cart price range criteria must be met. For example; if you have a ShippingMethod connected to the SEK currency where one has a price range for Sweden starting from 500 SEK, it won’t be available until the cart has reached that value.
The price of the ShippingMethod depends on its ranges and are configured by the Centra admin, but can also be subject to vouchers that set the shipping cost to 0 for given ShippingMethod.
totals
The summary of all order totals and taxes, represented as a list.
You will always get all totals back
- ITEMS_SUBTOTAL The subtotal of lines, including line level discounts
- DISCOUNT The total order level discount, e.g. from a voucher.
- CREDIT The total amount applied from credit vouchers.
- SHIPPING The shipping cost
- HANDLING Eventual handling cost.
- GRAND_TOTAL The summarized total that the customer will pay, tax taken into account (added, deducted, included)
The following fields depend on the Tax rule setup for the shippingAddress
| Tax rule (include tax) | Type |
|---|---|
| In prices displayed before the checkout and in the checkout | INCLUDING_TAX |
| In prices displayed before the checkout but not in the checkout | TAX_DEDUCT |
| On top of prices in the checkout | TAX_ADDED |
All tax fields implement SelectionTotalTaxRow, gaining you access to the percentage
These rows will give you:
- A row with the tax added for each tax percentage: e.g. one row for the amount of tax at 25%, one row for the amount of tax at 6%
- A row with the total tax amount
widgets
A list of widgets available for the selection, exposes integrations prebuilt by Centra that you can use on the checkout page
Implementing the checkout
Since pre-checkout and checkout mutations share similar patterns, operations like updating quantities and adding items are omitted here. The key difference is querying the Checkout field on the Selection for checkout page data.
Dealing with errors
The Storefront API has three concepts of errors, userErrors which are logical errors and errors which are either validation errors on the GraphQL level or an internal system error. If you would encounter the latter please reach out to partnersupport@centra.com.
The userError type is an interface giving you a generic message of what went wrong and the path of where it went wrong, you can further inspect the error by using fragments of the different implementations and craft your own error messages shown to the shopper with as many details as you wish. Even if you get userErrors back you can still update your state with the other data returned, no need to refetch it.
Getting checkout specific data
Below you can find an example of the data you would query whilst on the checkout page, whether it’s reading the contents when the shopper first lands on the checkout page or performs a mutation whilst there.
For brevity we will use the SelectionCheckoutFragment in all examples going forward.
To keep your checkout current, reuse the same fragment for all operations and pass it to your components.
fragment CheckoutFragment on CheckoutSelection {
shippingMethods {
id
name
comment
selected
price {
formattedValue
}
}
paymentMethods {
id
name
active
addressAfterPayment
kind
initiateOnlySupported
recurringSupported
}
widgets {
kind
... on IngridWidget {
snippet
sessionId
ingridAttributes
deliveryOptionsAvailable
reload
}
}
addressFields {
shippingAddress {
key
visible
required
... on CountryAddressField {
choices {
name
code
}
}
... on StateAddressField {
choices {
name
code
}
}
}
separateBillingAddress {
key
visible
required
}
newsletter {
key
visible
required
}
termsAndConditions {
key
visible
required
}
}
hasSeparateBillingAddress
shippingAddress {
firstName
lastName
address1
address2
city
zipCode
stateOrProvince
phoneNumber
email
country {
name
code
}
state {
name
code
}
}
separateBillingAddress {
firstName
lastName
address1
address2
city
zipCode
stateOrProvince
phoneNumber
email
country {
name
code
}
state {
name
code
}
}
totals {
price {
formattedValue
}
... on SelectionTotalTaxRow {
taxPercent
}
type
}
}
fragment SelectionCheckoutFragment on Selection {
id
lines {
...LineFragment
}
checkout {
...CheckoutFragment
}
language {
name
code
}
discounts {
name
appliedOn
method
type
value {
value
formattedValue
}
... on CodeVoucher {
code
}
... on UrlVoucher {
url
}
}
}
fragment LineFragment on Line {
...ProductLineFragment
... on BundleLine {
bundle {
id
type
priceType
sections {
id
quantity
lines {
...ProductLineFragment
}
}
}
}
}
fragment ProductLineFragment on ProductLine {
id
name
productVariantName
size
productNumber
comment
productExternalUrl
brand {
name
}
item {
id
name
sku
GTIN
preorder
stock {
available
}
}
appliedPromotions {
type
percent
value {
value
formattedValue
}
}
hasDiscount
unitPrice {
value
formattedValue
}
unitOriginalPrice {
value
formattedValue
}
quantity
subscriptionId
displayItem {
id
}
}
Rendering the checkout
We start off with a query to render the full checkout page
query GetCheckout {
selection {
...SelectionCheckoutFragment
}
}
Collecting the customer’s address details
The Storefront API offers two ways to set the customer’s address, setAddress and paymentInstructions. The reason for this is that you might want to gather information as they fill out the address form, for example if you want to trigger cartAbandonment, before they start the payment.
Changing the shippingAddress.[country|stateOrProvince] in by providing it in an AddressInput triggers the same logic as if you would change it via the setCountryState mutation, so market and pricelist are be affected by this mutation, and might cause lines to be removed from the Selection. In such case you will receive an UserError implementation, UnavailableItem, detailing which line and the item and displayItem info regarding it.
Collecting the customer info before going to payment
The setAddress mutation allows you to collect incremental address data about the shopper as they fill out the address form.
mutation setAddress($shippingAddress: AddressInput!, $separateBillingAddress: AddressInput) {
setAddress(
sendCartAbandonmentEmail: true
shippingAddress: $shippingAddress
separateBillingAddress: #separateBillingAddress
) {
selection {
...SelectionCheckoutFragment
}
userErrors {
message
path
... on UnavailableItem {
item {
id
name
}
originalQuantity
availableQuantity
unavailableQuantity
displayItem {
name
productVariant {
name
}
}
}
}
}
}
If you trigger the setAddress mutation on each “blur” of your address field it’s advisable to gather the events and send a bigger call instead of many small ones since the browser’s prefill of addresses will trigger many calls.
Vouchers
Adding a voucher
You can add as many vouchers as you like, depending on their configuration they might not all apply, to the selection by using the addVoucher mutation.
mutation AddVoucher($code: String!) {
addVoucher(code: $code) {
selection {
...SelectionCheckoutFragment
}
userErrors {
message
path
}
}
}
Since Centra supports URLVouchers and auto vouchers as well, there are vouchers which might have been applied before reaching the checkout, so they are visible outside of the checkout field on the Selection
Removing a voucher
The shopper might not want to utilize the voucher for this purchase after they see how it’s been applied so they have the option to remove it as well
mutation RemoveVoucher($code: String!) {
removeVoucher(code: $code) {
selection {
...SelectionCheckoutFragment
}
userErrors {
message
path
}
}
}
Shipping
Changing shipping method
mutation UpdateShippingMethod($id: Int!) {
setShippingMethod(id: $id) {
selection {
...SelectionCheckoutFragment
}
userErrors {
message
path
}
}
}
Payment flow
Once the customer has selected their shipping method, payment method, filled out their address etc then it’s time to start the payment flow. Please see the payment flows article for more details.
Showing the last placed order
The last order placed for the session is available under the order query, typically used on the “thank you” page. Using this query allows the customer to see their latest order or if they go back to the thank you page or reload it.
query GetLastOrder {
order {
...OrderFragment
}
}
fragment OrderFragment on Order {
id
number
status
shippingMethod {
id
name
price {
formattedValue
}
}
paymentMethod {
id
name
kind
}
shippingAddress {
firstName
lastName
address1
address2
city
zipCode
stateOrProvince
cellPhoneNumber
faxNumber
email
companyName
attention
vatNumber
country {
name
code
}
state {
name
code
}
}
billingAddress {
firstName
lastName
address1
address2
city
zipCode
stateOrProvince
cellPhoneNumber
faxNumber
email
companyName
attention
vatNumber
country {
name
code
}
state {
name
code
}
}
paymentHtml
affiliateHtml
totals {
type
price {
formattedValue
}
... on SelectionTotalTaxRow {
taxPercent
}
}
}