Working with checkouts

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
            }
          }
        }
      }
    }
  }
}

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 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"
  }
}

View response

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 the nextActionUrl field so they can complete the 3D Secure authentication.
  • Poll the checkout until the payment is complete and the ready field returns true.

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 checkoutCompleteWithTokenizedPaymentV2 mutation.

Setup requirements

Shopify's integration with Stripe has the following requirements:

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.

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.

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 checkoutCompleteWithTokenizedPaymentV2 mutation

To complete the checkout, send the payment information in the payment argument of the checkoutCompleteWithTokenizedPaymentV2 mutation. Send the Stripe token in the paymentData 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="
      }
    }
  }
}

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:

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
      }
    ]
  }
}

View response

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"
            }
        }
    }
}

View response

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\":\"\"}}}"
    }
}

View response

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"
  }
}

View response

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:

Sign up for a Partner account to get started.

Sign up