Create a checkout with the Storefront API
This guide covers creating and completing a checkout in Shopify. You'll learn how to query for the required line item data, and properly use the various mutations that complete checkouts. 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 with the Storefront API 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 returned 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 ID as the payload object. When specifying the return fields you must include nested subfields until you return only scalars, as described in the GraphQL spec.
query {
products(first:2) {
edges {
node {
variants(first: 2) {
edges {
node {
id
}
}
}
}
}
}
}
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
.
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
}
}
}
}
}
}
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="
}
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
}
}
}
}
}
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"
}
JSON response:
{
"data": {
"checkoutShippingLineUpdate": {
"checkout": {
"id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC9hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMj9rZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY="
},
"checkoutUserErrors": []
}
}
}
Associating the customer
You can associate a customer with a checkout so that the customer doesn't have to enter customer information when checking out. You can associate the customer to Shopify's web checkout or to a checkout that will be completed through the API.
Associating customers to web checkouts
If you're using Shopify's web checkout, then you can use Multipass to log in customers and redirect them to a web checkout link. You can refer to Multipass to learn how to enable Multipass in a Shopify store, obtain the token identifying the customer, and log in the customer.
Redirecting the customer to the web checkout URL
To get the Multipass token for the customer, you need to provide some customer information. During this step, you can provide a redirect URL using the return_to
field to specify the URL of the web checkout. When customers are redirected to the checkout URL, they stay logged-in to the Shopify store.
Associating customers to Storefront API checkouts
If you're not using Shopify's web checkout, then you need to get a customer access token to associate the customer with the checkout. You can get the access token using either the customerAccessTokenCreate or customerAccessTokenCreateWithMultipass mutations. After you have the customer access token, you can use the checkoutCustomerAssociateV2 mutation.
Associating a customer to a checkout using checkoutCustomerAssociateV2
After you've created a customer with a customer access token, you can use the token to associate the customer to the checkout. The following mutation uses the customer's access token and the checkout ID to associate the customer with the checkout.
mutation associateCustomerWithCheckout($checkoutId: ID!, $customerAccessToken: String!) {
checkoutCustomerAssociateV2(checkoutId: $checkoutId, customerAccessToken: $customerAccessToken) {
checkout {
id
}
checkoutUserErrors {
code
field
message
}
customer {
id
}
}
}
GraphQL variables:
{
"checkoutId": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC8xMzc3MjRiYWI4ZDc1ZmJlYTliZTFmMGJjMzU1MWFkNT9rZXk9ZjBkYjM5ZTM1ODVjOWZiNjhkNzg3NjNlNWMwNWE4YjI=",
"customerAccessToken": "68443c133be80b1c6c026be8fe54a901"
}
JSON response:
{
"data": {
"checkoutCustomerAssociateV2": {
"checkout": {
"id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC8xMzc3MjRiYWI4ZDc1ZmJlYTliZTFmMGJjMzU1MWFkNT9rZXk9ZjBkYjM5ZTM1ODVjOWZiNjhkNzg3NjNlNWMwNWE4YjI="
},
"checkoutUserErrors": [],
"customer": {
"id": "Z2lkOi8vc2hvcGlmeS9DdXN0b21lci8yMTg1Njg1OTkxNDgw"
}
}
}
}
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:
- Use the
webUrl
field to redirect the customer to Shopify's web checkout form - Request payment processing and then complete the checkout using one of the following methods:
Complete a checkout for a logged-in customer:
If you complete a checkout for a logged-in customer, then the customer is prompted to log in again. You can't use the X-Shopify-Customer-Access-Token
header to preserve authentication when the customer is associated to the checkout. If the store is on a Shopify Plus plan, then you can use Multipass to preserve authentication and associate the customer with the checkout.
If the customer doesn't have an account, then you can use the customerCreate mutation to create one.
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 vault. Then you can use the returned payment vault ID with the checkoutCompleteWithCreditCardv2 mutation.
Getting the vault ID
To get the vault ID to complete payment, you need to send a POST request to the Shopify card vault. The credit card information is sent in the body of the request, and a valid request returns an 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 vault 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"
}
}
JSON response:
The response includes the payment ID of the completed checkout:
{
"data": {
"checkoutCompleteWithCreditCardV2": {
"checkout": {
"id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC9hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMj9rZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY="
},
"checkoutUserErrors": [],
"payment": {
"id": "Z2lkOi8vc2hvcGlmeS9QYXltZW50LzgwNTY3MDg3OTI4OD9jaGVja291dD1hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMiZrZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY="
}
}
}
}
3D Secure payments
If you are located in an area impacted by PSD2, then you need to implement 3D Secure payment processing into your app or sales channel. To implement 3D Secure, the following steps are required:
- After creating the
checkoutCompleteWithCreditCardV2
mutation, redirect the customer to the URL that's returned by thenextActionUrl
field so they can complete the 3D Secure authentication. - Poll the checkout until the payment is complete and the
ready
field returnstrue
.
For a detailed guide, see Authenticating payments with 3D Secure.
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 checkoutCompleteWithTokenizedPaymentV3 mutation.
Setup requirements
Shopify's integration with Stripe has the following requirements:
- The merchant must have Shopify Payments enabled.
- You need a Stripe platform account with Connect integration.
- You need token create access for Shopify's accounts in Stripe.
Shopify Payments:
Each merchant that installs your 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.
Access to create tokens:
You need access to create tokens 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 to complete the payment.
To get access, provide Shopify with your Stripe platform account ID. You can query for this ID using the Stripe API.
Get the Stripe token
To get a Stripe token for payment, you need to send the credit card information to the Stripe tokens endpoint. You can 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.
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 checkoutCompleteWithTokenizedPaymentV3 mutation
To complete the checkout, send the payment information in the payment
argument of the checkoutCompleteWithTokenizedPaymentV3 mutation. Send the Stripe token in the paymentData
field.
mutation checkoutCompleteWithTokenizedPaymentV3($checkoutId: ID!, $payment: TokenizedPaymentInputV3!) {
checkoutCompleteWithTokenizedPaymentV3(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"
}
}
JSON response:
The response includes the payment ID of the completed checkout:
{
"data": {
"checkoutCompleteWithTokenizedPaymentV3": {
"checkout": {
"id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC80N2YxMmQ4OTA2YjBhNTlhYTkzZTdjZDFhZjQwMzJjNj9rZXk9ZDc4YmIyOTg5ZmJjNzEzYTQ2Zjc1OTRkOTUyMzhhNjk="
},
"checkoutUserErrors": [],
"payment": {
"id": "Z2lkOi8vc2hvcGlmeS9QYXltZW50LzgxMjcxOTgwMDM3Nj9jaGVja291dD00N2YxMmQ4OTA2YjBhNTlhYTkzZTdjZDFhZjQwMzJjNiZrZXk9ZDc4YmIyOTg5ZmJjNzEzYTQ2Zjc1OTRkOTUyMzhhNjk="
}
}
}
}
Spreedly
You can use Spreedly to send customer credit card information to Shopify's PCI compliant card vault.
Overview
The process of exchanging credit card information for a Shopify payment vault ID is a multi-step process. To obtain the vault ID the following flow is observed:
- Get a token from the Spreedly payment_methods endpoint.
- Send the token and credit card info to the Spreedly deliver endpoint.
- Use the returned Shopify vault ID sent to you by Spreedly to complete the checkout with the checkoutCompleteWithCreditCardV2 mutation.
Setup requirements
Shopify's integration with Spreedly has the following requirements:
- Add the Shopify receiver to your Spreedly account.
- Create a credit card in Spreedly.
- Deliver the payment information to Shopify's card vault using Spreedly's deliver endpoint.
Add Shopify as a receiver in Spreedly
Spreedly lets you distribute vaulted credit card data to non-gateway third parties called receivers. You need to add Shopify as a receiver in your Spreedly account so Spreedly can send credit card information to Shopify's card vault.
To add Shopify as a receiver, send a POST request to the Spreedly receivers endpoint including the receiver
object in the body of the request. The receiver
object includes "shopify"
as the receiver_type
.
{
"receiver": {
"receiver_type": "shopify",
"hostnames": "https://elb.deposit.shopifycs.com/",
"credentials": [
{
"name": "app-id",
"value": 1234,
"safe": true
},
{
"name": "app-secret",
"value": 5678
}
]
}
}
JSON response:
The response includes the receiver token required for the call to the Spreedly deliver endpoint:
{
"receiver": {
"company_name": "Shopify",
"receiver_type": "shopify",
"token": "E6bjwnTkx9NR39BVwyQ2JXzRIKL",
"hostnames": "https://elb.deposit.shopifycs.com/",
"state": "retained",
"created_at": "2019-07-09T20:55:18Z",
"updated_at": "2019-07-09T20:55:18Z",
"credentials": [
{
"name": "app-id",
"value": 1234,
"safe": true
},
{
"name": "app-secret",
"safe": "false"
}
]
}
}
Add a credit card in Spreedly
To get a vault ID, you first need to tokenize a credit card with Spreedly. This should be done using an iFrame payment form or Spreedly Express for less PCI scope.
To get the token, send a POST request to the Spreedly payment_methods endpoint, and include the credit card information in the body of the request.
{
"payment_method": {
"credit_card": {
"first_name": "Joe",
"last_name": "Cardholder",
"number": "4242424242424242",
"verification_value": "123",
"month": "10",
"year": "2020",
"email": "joey@example.com"
},
"data": {
"my_payment_method_identifier": "448",
"extra_stuff": {
"some_other_things": "Can be anything really"
}
}
}
}
JSON response:
The response includes the payment_method_token
needed to complete the call to the Spreedly deliver endpoint:
{
"transaction": {
"token": "GTYRRhCG95M4N72P37zMovzPzBx",
"created_at": "2019-09-12T16:06:06Z",
"updated_at": "2019-09-12T16:06:06Z",
"succeeded": true,
"transaction_type": "AddPaymentMethod",
"retained": false,
"state": "succeeded",
"message_key": "messages.transaction_succeeded",
"message": "Succeeded!",
"payment_method": {
"token": "THHaYZg4FXeEtV1qzKlS7j8RBbW",
"created_at": "2019-09-12T16:06:06Z",
"updated_at": "2019-09-12T16:06:06Z",
"email": "joey@example.com",
"data": {
"my_payment_method_identifier": "448",
"extra_stuff": {
"some_other_things": "Can be anything really"
}
},
"storage_state": "cached",
"test": false,
"metadata": null,
"callback_url": null,
"last_four_digits": "4242",
"first_six_digits": "424242",
"card_type": "visa",
"first_name": "Joe",
"last_name": "Cardholder",
"month": 10,
"year": 2020,
"address1": null,
"address2": null,
"city": null,
"state": null,
"zip": null,
"country": null,
"phone_number": null,
"company": null,
"full_name": "Joe Cardholder",
"eligible_for_card_updater": true,
"shipping_address1": null,
"shipping_address2": null,
"shipping_city": null,
"shipping_state": null,
"shipping_zip": null,
"shipping_country": null,
"shipping_phone_number": null,
"payment_method_type": "credit_card",
"errors": [],
"fingerprint": "149d1f4cfe740bf11ccec969297e47c2e37a",
"verification_value": "XXX",
"number": "XXXX-XXXX-XXXX-4242"
}
}
}
Deliver the payment information
After you get a payment method token, you can get the Shopify card vault ID from the Spreedly deliver endpoint. Spreedly delivers the payment method to Shopify's receiver endpoint, and, in response, Shopify returns the vault ID.
To get the vault ID, send a POST request to the Spreedly deliver endpoint. You need to include Shopify's receiver token as a path parameter, and the payment method token in the body of the request. This tells Spreedly to deliver the credit card associated with the payment method token to the Shopify card vault. You also need to include properly formatted JSON syntax in the body
object.
POST https://core.spreedly.com/v1/receivers/E6bjwnTkx9NR39BVwyQ2JXzRIKL/deliver.json
{
"delivery": {
"payment_method_token": "THHaYZg4FXeEtV1qzKlS7j8RBbW",
"url": "https://elb.deposit.shopifycs.com/sessions",
"headers": "Content-type: application/json",
"body": "{ \"payment\": { \"credit_card\":{ \"number\": \"\", \"month\": \"\", \"year\": \"\", \"verification_value\": \"\", \"first_name\":\"\", \"last_name\":\"\"}}}"
}
}
JSON response:
The body
property of the response
object includes the Shopify card vault Id ("west-5dc7e488afe4fea418036b0c44bf0039") that you need to complete the checkout:
{
"transaction": {
"token": "N02ASqSzxZcRFRbaJPwDNuxXiIU",
"transaction_type": "DeliverPaymentMethod",
"state": "succeeded",
"created_at": "2019-09-12T16:06:44Z",
"updated_at": "2019-09-12T16:06:44Z",
"succeeded": true,
"message": "Succeeded!",
"url": "https://elb.deposit.shopifycs.com/sessions",
"response": {
"status": 200,
"headers": "Server: nginx\r\nDate: Thu, 12 Sep 2019 16:06:44 GMT\r\nContent Type: application/json\r\nContent-Length: 46\r\nConnection: close\r\nVary: Accept-Encoding\r\nAccess-Control-Allow-Origin: *\r\nStrict-Transport Security: max-age=31536000; includeSubDomains; preload\r\nP3P: CP=\"NOI DSP COR NID ADMa OPTa OUR NOR\"",
"body": "{\"id\":\"west-5dc7e488afe4fea418036b0c44bf0039\"}"
},
"receiver": {
"company_name": "Shopify",
"receiver_type": "shopify",
"token": "H11gwIjMzEpVn85RfEwU9R8BUNO",
"hostnames": "https://elb.deposit.shopifycs.com/",
"state": "retained",
"created_at": "2019-09-12T15:54:13Z",
"updated_at": "2019-09-12T15:54:13Z",
"credentials": [
{
"name": "app-id",
"value": 1234,
"safe": true
},
{
"name": "app-secret",
"safe": "false"
}
]
},
"payment_method": {
"token": "THHaYZg4FXeEtV1qzKlS7j8RBbW",
"created_at": "2019-09-12T16:06:06Z",
"updated_at": "2019-09-12T16:06:44Z",
"email": "joey@example.com",
"data": {
"my_payment_method_identifier": "448",
"extra_stuff": {
"some_other_things": "Can be anything really"
}
},
"storage_state": "used",
"test": false,
"metadata": null,
"callback_url": null,
"last_four_digits": "4242",
"first_six_digits": "424242",
"card_type": "visa",
"first_name": "Joe",
"last_name": "Cardholder",
"month": 10,
"year": 2020,
"address1": null,
"address2": null,
"city": null,
"state": null,
"zip": null,
"country": null,
"phone_number": null,
"company": null,
"full_name": "Joe Cardholder",
"eligible_for_card_updater": true,
"shipping_address1": null,
"shipping_address2": null,
"shipping_city": null,
"shipping_state": null,
"shipping_zip": null,
"shipping_country": null,
"shipping_phone_number": null,
"payment_method_type": "credit_card",
"errors": [],
"fingerprint": "149d1f4cfe740bf11ccec969297e47c2e37a",
"verification_value": "",
"number": "XXXX-XXXX-XXXX-4242"
}
}
}
Using the checkoutCompleteWithCreditCardV2 mutation with the vault ID
After you get the Shopify payment vault ID, you can complete the payment using the checkoutCompleteWithCreditCardV2.
To complete the checkout, send the payment information in the payment
argument of the checkoutCompleteWithCreditCardV2 mutation. Send the vault 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-5dc7e488afe4fea418036b0c44bf0039"
}
}
JSON response:
The response includes the payment ID of the completed checkout:
{
"data": {
"checkoutCompleteWithCreditCardV2": {
"checkout": {
"id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC9hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMj9rZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY="
},
"checkoutUserErrors": [],
"payment": {
"id": "Z2lkOi8vc2hvcGlmeS9QYXltZW50LzgwNTY3MDg3OTI4OD9jaGVja291dD1hOGE0MWU4Y2I4MDU4YjdmOTI1MTcxZDUwMzhjYmZmMiZrZXk9ZTQ4NGFlNjdlZDE4MmYzN2Y0ODZkZjkxNDE1MDMyYTY="
}
}
}
}
Next steps
You might find the following resources useful if you want to know more about the concepts introduced in this guide: