Creating a checkout

This guide covers creating a checkout in Shopify, and completing it using Shopify's web checkout form. You'll learn how to query for the required line item data, and properly use the checkoutCreate mutation. The guide also covers modifying the checkout by adding line items and modifying the shipping address, before redirecting the user to Shopify's web checkout form.

Prerequisites

This guide assumes you have completed our Getting started guide, and that you are authenticated with the Storefront API. The guide also assumes that you've created product variants in your test shop.

The code examples in this guide can be run in GraphiQL or your preferred HTTP client.

Querying for data

Mutations often require that data is first obtained by running a query. In the case of checkoutCreate, you need to return product variants, before you can populate the checkout input fields with the required line item data.

The following query returns the first two products from your test shop, and specifies the return fields of the payload object that you want back from the server. When specifying the return fields you must include nested subfields until you return only scalars, as described in the spec.

query {
  products(first: 2) {
    edges {
      node {
        variants(first: 2) {
          edges {
            node {
              id
            }
          }
        }
      }
    }
  }
}

View response

JSON response

The query returns the following data object:

{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "variants": {
              "edges": [
                {
                  "node": {
                    "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMzg3MDQ4MzI3NTc5OA=="
                  }
                },
                {
                  "node": {
                    "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMzg3MDQ4MzMwODU2Ng=="
                  }
                }
              ]
            }
          }
        },
        {
          "node": {
            "variants": {
              "edges": [
                {
                  "node": {
                    "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMzg3MDQ4MzQzOTYzOA=="
                  }
                },
                {
                  "node": {
                    "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMzg3MDQ4MzQ3MjQwNg=="
                  }
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Creating the Checkout

You can use the checkoutCreate mutation to create a new checkout. The return fields include the Checkout object with the webUrl field.

The following mutation creates the checkout and returns the checkout id, the added line items, and the webUrl field that you'll use later to redirect the user to the web checkout.

mutation {
  checkoutCreate(input: {
    lineItems: [{ variantId: "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMzg3MDQ4MzI3NTc5OA==", quantity: 1 }]
  }) {
    checkout {
       id
       webUrl
       lineItems(first: 5) {
         edges {
           node {
             title
             quantity
           }
         }
       }
    }
  }
}

Let’s examine this mutation in more detail:

checkoutCreate(input: {
  lineItems: [{ variantId: "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMzg3MDQ4MzI3NTc5OA==", quantity: 1}]})

In the above snippet,checkoutCreate is the name of the mutation, and input is the required argument. The required argument value is an input object type that includes the lineItems field, an array that includes variantId and quantity as required fields.

{
  checkout {
     id
     webUrl
     lineItems(first: 5) {
       edges {
         node {
           id
           title
           quantity
         }
       }
     }
  }
}

The rest of the mutation defines the return fields for the payload object. The return fields of the Checkout show that id and webUrl fields can be returned, and that a lineItems connection can be specified. The lineItems connection data must be accessed with edges; the node at the end of the CheckoutLineItemConnection type is a CheckoutLineItem and requires title and quantity.

View response

JSON response

If the mutation is valid, then the following response is returned:

{
  "data": {
    "checkoutCreate": {
      "checkout": {
        "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC81ZDliYTZjOTlhNWY4YTVhNTFiYzllMzlmODEwNTNhYz9rZXk9NWIxZTg5NDQzNTZkMjMxOGU1N2ZlNjQwZDJiNjY1M2Y=",
        "webUrl": "https://checkout.myshopify.io/1/checkouts/07e63bcab2b53dc6ac46cbcb6abbca5b?key=4ac66ff3ca2a8d2c25b43d1a6b40d905",
        "lineItems": {
          "edges": [
            {
              "node": {
                "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dExpbmP0V3brNWZoN2PwYmZiljY0IzNwIjZiZDOmNjNjJWY5MDNkFTO4UGN4IzLtVGdJVTVkOWJhNmM5OWE1ZjhhNWE1MWJjOWUzOWY4MTA1M2Fj"
                "title": "Blue Shirt",
                "quantity": 1
              }
            }
          ]
        }
      }
    }
  }
}

Modifying the Checkout

After creating the checkout using checkoutCreate you can modify it by changing the line items, or the customer's shipping address.

Changing line items on a Checkout

To change the line items on a checkout, you can use the checkoutLineItemsReplace mutation. The mutation replaces the checkout's existing lineItems array with a new array that's specified in the mutation.

The example below replaces the existing line item with two new line items. The checkoutId argument identifies the checkout to update, and the lineItems argument specifies the variants and quantities to add to the checkout.

mutation {
  checkoutLineItemsReplace(lineItems: [{ variantId: "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8z", quantity: 1 },{ variantId: "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC80", quantity: 1}], checkoutId: "Z2lkOi8vc2hvcGlmeS9DaGVja291dC81ZDliYTZjOTlhNWY4YTVhNTFiYzllMzlmODEwNTNhYz9rZXk9NWIxZTg5NDQzNTZkMjMxOGU1N2ZlNjQwZDJiNjY1M2Y=",
  ) {
    checkout {
       id
       lineItems(first:2) {
         edges {
           node {
             id
             title
             quantity
           }
         }
       }
    }
  }
}

View response

JSON response

The mutation returns the following data object:

{
  "data": {
    "checkoutLineItemsReplace": {
      "checkout": {
        "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC81ZDliYTZjOTlhNWY4YTVhNTFiYzllMzlmODEwNTNhYz9rZXk9NWIxZTg5NDQzNTZkMjMxOGU1N2ZlNjQwZDJiNjY1M2Y=",
        "lineItems": {
          "edges": [
            {
              "node": {
                "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dExpbmVJdGVtLzI4NGU4OTFkNDM5YWJjNjNmODZiZjIwNzI0YjliZmYwP2NoZWNrb3V0PTVkOWJhNmM5OWE1ZjhhNWE1MWJjOWUzOWY4MTA1M2Fj",
                "title": "Men's Classic V-Neck",
                "quantity": 1
              }
            },
            {
              "node": {
                "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dExpbmVJdGVtLzk0MTAwMmJmNWM4MmJjYjZjNDc2NjI0NzZlZWY5ZTViP2NoZWNrb3V0PTVkOWJhNmM5OWE1ZjhhNWE1MWJjOWUzOWY4MTA1M2Fj",
                "title": "Women's Scoop Neck (White)",
                "quantity": 1
              }
            }
          ]
        }
      }
    }
  }
}

Populating Shipping Address

Before you can properly complete a checkout, you need to set the customer shipping address by using the checkoutShippingAddressUpdateV2 mutation. The example below defines the customer's shipping address using GraphQL variables:

mutation checkoutShippingAddressUpdateV2($shippingAddress: MailingAddressInput!, $checkoutId: ID!) {
  checkoutShippingAddressUpdateV2(shippingAddress: $shippingAddress, checkoutId: $checkoutId) {
    userErrors {
      field
      message
    }
    checkout {
      id
      shippingAddress {
        firstName
        lastName
        address1
        province
        country
        zip
      }
    }
  }
}

GraphQL Variables:

{
  "shippingAddress": {
    "lastName": "Doe",
    "firstName": "John",
    "address1": "123 Test Street",
    "province": "QC",
    "country": "Canada",
    "zip": "H3K0X2",
    "city": "Montreal"
  },

   "checkoutId": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC81ZDliYTZjOTlhNWY4YTVhNTFiYzllMzlmODEwNTNhYz9rZXk9NWIxZTg5NDQzNTZkMjMxOGU1N2ZlNjQwZDJiNjY1M2Y="
}

View response

JSON response

A successful mutation returns the following data object:

{
  "data": {
    "checkoutShippingAddressUpdateV2": {
      "userErrors": [],
      "checkout": {
        "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC81ZDliYTZjOTlhNWY4YTVhNTFiYzllMzlmODEwNTNhYz9rZXk9NWIxZTg5NDQzNTZkMjMxOGU1N2ZlNjQwZDJiNjY1M2Y=",
        "shippingAddress": {
          "firstName": "John",
          "lastName": "Doe",
          "address1": "123 Test Street",
          "province": "Quebec",
          "country": "Canada",
          "zip": "H3K0X2"
        }
      }
    }
  }
}

Setting the shipping rate

You can query Shopify for the shipping rates that are available for the checkout. Then you can select the applicable rate using the ShippingRates handle and apply it to the checkout.

To return the availableShippingRates you can query the Checkout object using node. The following query returns the shippingRates for the Checkout.

query {
  node(id: "Z2lkOi8vc2hvcGlmeS9DaGVja291dC9hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMj9rZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY=") {
    ... on Checkout {
      id
      webUrl
      availableShippingRates {
        ready
        shippingRates {
          handle
          priceV2 {
            amount
          }
          title
        }
      }
    }
  }
}

View response

JSON response

{
  "data": {
    "node": {
      "id": "{checkout_ID}",
      "webUrl": "https://domain.myshopify.com/14376108/checkouts/a8a41e8cb8058b7f925171d5038cbff2?key=e484ae67ed182f37f486df91415032a6",
      "availableShippingRates": {
        "ready": true,
        "shippingRates": [
          {
            "handle": "shopify-Heavy%20Goods%20Shipping-18.00",
            "priceV2": {
              "amount": "18.0"
            },
            "title": "Heavy Goods Shipping"
          }
        ]
      }
    }
  }
}

Since retrieving shipping rates can cause asynchronous recalculation, you might have to poll multiple times to return the list of rates. The following response indicates that you will need to poll again:

{
  "data": {
    "node": {
      "id": "{checkout_id}",
      "webUrl": "https://{domain}.myshopify.com/14376108/checkouts/1f236dce30300b17d7c97eb0721f3b5b?key=22731033907db51ea069222159977d8f",
      "availableShippingRates": {
        "ready": false,
        "shippingRates": null
      }
    }
  }
}

You can then set the handle using the checkoutShippingLineUpdate mutation:

mutation checkoutShippingLineUpdate($checkoutId: ID!, $shippingRateHandle: String!) {
  checkoutShippingLineUpdate(checkoutId: $checkoutId, shippingRateHandle: $shippingRateHandle) {
    checkout {
      id
    }
    checkoutUserErrors {
      code
      field
      message
    }
  }
}

GraphQL variables:

{
  "checkoutId": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC9hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMj9rZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY=",
  "shippingRateHandle": "shopify-Heavy%20Goods%20Shipping-18.00"
}

View response

JSON response:

{
  "data": {
    "checkoutShippingLineUpdate": {
      "checkout": {
        "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC9hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMj9rZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY="
      },
      "checkoutUserErrors": []
    }
  }
}

Completing the Checkout

After you've finished creating and performing any updates to the checkout, you can complete the checkout.

There are several ways to complete a checkout:

Shopify web checkout

The simplest way to complete it is to redirect the customer to Shopify's web checkout form using the returned webUrl field. At any point during the checkout flow, you can redirect the user to this form by querying the webUrl field on the Checkout:

query {
  node(id:"Z2lkOi8vc2hvcGlmeS9DaGVja291dC81ZDliYTZjOTlhNWY4YTVhNTFiYzllMzlmODEwNTNhYz9rZXk9NWIxZTg5NDQzNTZkMjMxOGU1N2ZlNjQwZDJiNjY1M2Y=" ) {
    ... on Checkout {
      id
      webUrl
    }
  }
}

Notice the inline fragment ...on Checkout. This is required to show which type should be queried for using id. Starting from the query root, node is an interface that implements the type Checkout. You can pass the id of the Checkout to the node interface, and the inline fragment indicates that id should be passed to the Checkout type.

A successful query to the Checkout object for webUrl returns the following data object:

{
  "data": {
    "node": {
      "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC81ZDliYTZjOTlhNWY4YTVhNTFiYzllMzlmODEwNTNhYz9rZXk9NWIxZTg5NDQzNTZkMjMxOGU1N2ZlNjQwZDJiNjY1M2Y=",
      "webUrl": "https://checkout.myshopify.io/1/checkouts/07e63bcab2b53dc6ac46cbcb6abbca5b?key=4ac66ff3ca2a8d2c25b43d1a6b40d905"
    }
  }
}

Shopify card vault

You can complete the checkout by sending credit card information to Shopify's PCI-compliant card server. Then you can use the returned payment session ID with the checkoutcompletewithcreditcardv2 mutation.

Obtaining the session ID

To get the session ID to complete payment you need to send a POST request to the card vault endpoint in the REST Admin API. The credit card information is sent in the body of the request, and a valid request will return the ID formatted as follows:

HTTP/1.1 200 OK
{
  "id": "83hru3obno3hu434b3u"
}

Using the mutation

To complete the payment, send the payment information, including the amount, currencyCode and billingAddress fields. Send the payment session ID as the vaultID.

mutation checkoutCompleteWithCreditCardV2($checkoutId: ID!, $payment: CreditCardPaymentInputV2!) {
  checkoutCompleteWithCreditCardV2(checkoutId: $checkoutId, payment: $payment) {
    checkout {
      id
    }
    checkoutUserErrors {
      code
      field
      message
    }
    payment {
      id
    }
  }
}

GraphQL variables:

{
  "checkoutId": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC9hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMj9rZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY=",
  "payment": {
    "paymentAmount": {
      "amount": "23.75",
      "currencyCode": "USD"
    },
    "idempotencyKey": "123",
    "billingAddress": {
      "firstName":  "John",
      "lastName": "Doe",
      "address1": "123 Test Street",
      "province": "Quebec",
      "country": "Canada",
      "city": "Montreal",
      "zip": "H3K0X2"
    },
    "vaultId": "west-0a4b2a42884c0cb9df4a3f56dda227aa"
  }
}

View response

JSON response:

The response includes the payment id of the completed checkout:

{
  "data": {
    "checkoutCompleteWithCreditCardV2": {
      "checkout": {
        "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC9hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMj9rZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY="
      },
      "checkoutUserErrors": [],
      "payment": {
        "id": "Z2lkOi8vc2hvcGlmeS9QYXltZW50LzgwNTY3MDg3OTI4OD9jaGVja291dD1hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMiZrZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY="
      }
    }
  }
}

Stripe

You can use Shopify's integration with Stripe to tokenize credit cards on behalf of merchants that have enabled Shopify Payments as their payment gateway solution.

You can complete the checkout by sending credit card information to Stripe. Then you can use the returned token with the checkoutcompletewithtokenizedpaymentv2 mutation.

Setup requirements

Shopify's integration with Stripe has the following requirements:

  • Merchant must have Shopify Payments enabled
  • Stripe platform account with Connect integration
  • Token create access for Shopify's accounts in Stripe

Shopify Payments:

Each merchant that installs you app must have Shopify payments enabled to use the Stripe integration. You can enable Shopify Payments for your test shop from the payments settings.

Connect integration:

You can visit Stripe to sign up for a Connect integration.

Token create access:

You'll need token create access to tokenize credit cards on behalf of Shopify's Custom accounts in Stripe. When your app creates a new checkout for a store with Shopify Payments enabled, Shopify creates a Stripe account for the merchant as part of the Connect integration and returns the shopify_payments_account_id. You can then get a credit card token from Stripe and complete the payment.

To get token create access, provide Shopify with your Stripe platform account ID. You can query for this ID using the Stripe API.

Obtain the Stripe token

To obtain a Stripe token for payment you need to send the credit card information to the Stripe Create a card token endpoint. You can then use the returned token to complete the payment.

https://api.stripe.com/v1/tokens \
  -u {secret_key}: \
  -d card[number]=4242424242424242 \
  -d card[exp_month]=12 \
  -d card[exp_year]=2020 \
  -d card[cvc]=123

where {secret_key} represents the test or live key token used for your Stripe platform account.

View response

JSON response:

The response includes the token in the id field:

{
    "id": "tok_1Ejt4eLgiPhRqvr3SQdtLvSW",
    "object": "token",
    "card": {
        "id": "card_1Ejt4eLgiPhRqvr3n4HIjWZn",
        "object": "card",
        "address_city": null,
        "address_country": null,
        "address_line1": null,
        "address_line1_check": null,
        "address_line2": null,
        "address_state": null,
        "address_zip": null,
        "address_zip_check": null,
        "brand": "Visa",
        "country": "US",
        "cvc_check": "unchecked",
        "dynamic_last4": null,
        "exp_month": 12,
        "exp_year": 2020,
        "fingerprint": "AiBmDoZLO3qqVDXD",
        "funding": "credit",
        "last4": "4242",
        "metadata": {},
        "name": null,
        "tokenization_method": null
    },
    "client_ip": "104.163.132.195",
    "created": 1560194552,
    "livemode": false,
    "type": "card",
    "used": false
}

Using the mutation

To complete the payment, send the payment information, including the amount, currencyCode and paymentData fields. Send the Stripe token in the payentData field.

mutation checkoutCompleteWithTokenizedPaymentV2($checkoutId: ID!, $payment: TokenizedPaymentInputV2!) {
  checkoutCompleteWithTokenizedPaymentV2(checkoutId: $checkoutId, payment: $payment) {
    checkout {
      id
    }
    checkoutUserErrors {
      code
      field
      message
    }
    payment {
      id
    }
  }
}

GraphQL variables:

{
  "checkoutId": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC80N2YxMmQ4OTA2YjBhNTlhYTkzZTdjZDFhZjQwMzJjNj9rZXk9ZDc4YmIyOTg5ZmJjNzEzYTQ2Zjc1OTRkOTUyMzhhNjk=",
  "payment": {
    "paymentAmount": {
      "amount": "88.71",
      "currencyCode": "USD"
    },
    "idempotencyKey": "123",
    "billingAddress": {
      "firstName":  "John",
      "lastName": "Doe",
      "address1": "123 Test Street",
      "province": "Quebec",
      "country": "Canada",
      "city": "Montreal",
      "zip": "H3K0X2"
    },
    "type": "placeholder",
    "paymentData": "tok_1Ejt4eLgiPhRqvr3SQdtLvSW"
  }
}

View response

JSON response:

The response includes the payment id of the completed checkout:

{
  "data": {
    "checkoutCompleteWithTokenizedPaymentV2": {
      "checkout": {
        "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC80N2YxMmQ4OTA2YjBhNTlhYTkzZTdjZDFhZjQwMzJjNj9rZXk9ZDc4YmIyOTg5ZmJjNzEzYTQ2Zjc1OTRkOTUyMzhhNjk="
      },
      "checkoutUserErrors": [],
      "payment": {
        "id": "Z2lkOi8vc2hvcGlmeS9QYXltZW50LzgxMjcxOTgwMDM3Nj9jaGVja291dD00N2YxMmQ4OTA2YjBhNTlhYTkzZTdjZDFhZjQwMzJjNiZrZXk9ZDc4YmIyOTg5ZmJjNzEzYTQ2Zjc1OTRkOTUyMzhhNjk="
      }
    }
  }
}

Next steps

You might find the following resources useful if you want to know more about the concepts introduced in this guide:

Sign up for a Partner account to get started.

Sign up