Sell through the Checkout API

The Checkout API makes it possible to purchase products from a Shopify store programmatically. A checkout in Shopify is the object used to manage a customer’s cart as it transitions to a paid checkout. This includes calculating taxes, shipping rates, attaching the customer’s information, and finally completing a purchase by submitting a payment. Use this API if you want a fully customized checkout user experience, while taking full advantage of the commerce engine used to power every Shopify store.

Caution

The Checkout API is only for use with the Sales Channel SDK. It is not possible to use it to create a new checkout for an individual store — for that you can use our JavaScript, iOS, and Android Buy SDKs.

How it works

Using a series of API calls, your platform can create a checkout, and update it a few times to programatically execute Shopify's checkout process, pictured below:

Checkout api flow

Authentication

Authentication for the Checkout API is performed via OAuth. All requests to this API must include the permanent access token in an X-Shopify-Access-Token request header. For more information, please read the OAuth Documentation

POST /admin/checkouts.json HTTP/1.1
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Host: channelsrule.myshopify.com
Content-Type: application/json

Protocol and hostname

The Checkout API is accessible via the store’s {subdomain}.myshopify.com or the store’s primary domain using https only.

Reservation

Reservations are done on a per-checkout basis. For the duration of the reservation, the line items in the checkout will be reserved for the given checkout. Upon creating a checkout, the default and maximum reservation time is 300 seconds (five minutes.) The reservation can be manually set during creation and extended when editing a checkout using the attribute reservation_time which is the amount of seconds to reserve the items for. A checkout can still be completed when the reservation has expired, but in the event that a line item is no longer available the call to /payments.json will fail.

Polling

Most operations on checkout will cause asynchronous recalculation; this requires the API consumer to poll until all attributes are updated. The checkout is still returned, but information such as prices, tax lines, and shipping rates might not be complete, until all available information is loaded. Polling is indicated through an HTTP 202 accepted response code, a Location header (indicating the url to poll) and a Retry-After header that suggests an interval delay in seconds.

Creating a checkout

In order for a customer to be able to purchase a desired product variant, a checkout must be created. The checkout can be updated partially at any time with the information provided by the customer.

The checkout provides information like tax lines, shipping costs, shipping requirements and more. You can display this to the customer and use it to complete other checkout requirements like updating the shipping rate that the customer chooses.

Example request to create a checkout

POST /admin/checkouts.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

{
  "checkout":{
    "email": "john.smith@example.com",
    "line_items": [{
      "variant_id": 11184583431,
      "quantity": 1
    }],
    "shipping_address": {
      "first_name": "John",
      "last_name": "Smith",
      "address1": "126 York St.",
      "city": "Ottawa",
      "province_code": "ON",
      "country_code": "CA",
      "phone": "(123)456-7890",
      "zip": "K1N 5T5"
    }
  }
}

View Response

HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
Location: https://channelsrule.myshopify.com/admin/checkouts/f9604c3f13b35c7ba36932436310ef09.json
Retry-After: 1

{
  "checkout":{
    "created_at":"2016-03-18T13:21:39-04:00",
    "currency":"CAD",
    "customer_id":2475498631,
    "email":"john.smith@example.com",
    "location_id":null,
    "order_id":null,
    "requires_shipping":true,
    "reservation_time":300,
    "source_name":"1257344",
    "source_identifier":null,
    "source_url":null,
    "taxes_included":false,
    "token":"f9604c3f13b35c7ba36932436310ef09",
    "updated_at":"2016-03-18T13:21:39-04:00",
    "payment_due":"28.25",
    "payment_url":"https:\/\/elb.deposit.shopifycs.com\/sessions",
    "reservation_time_left":300,
    "subtotal_price":"25.00",
    "total_price":"28.25",
    "total_tax":"3.25",
    "attributes":[],
    "note":"",
    "order":null,
    "privacy_policy_url":"https:\/\/checkout.shopify.com\/10890068\/policies\/16561415.html",
    "refund_policy_url":"https:\/\/checkout.shopify.com\/10890068\/policies\/16561351.html",
    "terms_of_service_url":"https:\/\/checkout.shopify.com\/10890068\/policies\/16561479.html",
    "user_id":null,
    "web_url":"https:\/\/checkout.shopify.com\/10890068\/checkouts\/f9604c3f13b35c7ba36932436310ef09",
    "tax_lines":[
      {
        "price":"3.25",
        "rate":0.13,
        "title":"HST"
      }
    ],
    "line_items":[
      {
        "id":"5a022a40c46d1e19",
        "key":"5a022a40c46d1e19",
        "product_id":3669728775,
        "variant_id":11184596679,
        "sku":"RUBY-001",
        "vendor":"channelsrule",
        "title":"Ruby Girls Tee",
        "variant_title":"small",
        "taxable":true,
        "requires_shipping":true,
        "price":"25.00",
        "compare_at_price":"30.00",
        "line_price":"25.00",
        "properties":{

        },
        "quantity":1,
        "grams":200,
        "fulfillment_service":"manual",
        "applied_discounts":[

        ]
      }
    ],
    "gift_cards":[

    ],
    "shipping_rate":null,
    "shipping_address":{
      "id":3763006023,
      "first_name":"John",
      "last_name":"Smith",
      "phone":"(123)456-7890",
      "company":null,
      "address1":"126 York St.",
      "address2":null,
      "city":"Ottawa",
      "province":"Ontario",
      "province_code":"ON",
      "country":"Canada",
      "country_code":"CA",
      "zip":"K1N 5T5"
    },
    "credit_card":null,
    "billing_address":null,
    "discount":null
  }
}

Polling for shipping rates

When a checkout requires shipping, polling is required to associate the selected shipping method with a shipping rate. When shipping rates are not available polling is required, as indicated with the Retry-After and Location headers.

GET /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3/shipping_rates.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

View Response

HTTP/1.1 202 ACCEPTED
Content-Type: application/json; charset=utf-8
Location: https://channelsrule.myshopify.com/admin/checkouts/f9604c3f13b35c7ba36932436310ef09/shipping_rates.json
Retry-After: 1

{
  "shipping_rates": []
}

Once ready, a list of shipping rates is returned.

GET /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3/shipping_rates.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

View Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Location: https://channelsrule.myshopify.com/admin/checkouts/f9604c3f13b35c7ba36932436310ef09/shipping_rates.json
Retry-After: 1

{
  "shipping_rates": [
    {
      "handle": "shopify-GROUND-10.00",
      "price": "10.00",
      "title": "Ground",
      "checkout": {
        "total_tax": "35.00",
        "total_price": "28.25",
        "subtotal_price": "25.00"
      },
      "phone_required": false,
      "delivery_range": []
    }
  ]
}

Updating a checkout

During the checkout process, it’s possible to update the checkout with the data received from the customer. A validation, specific only to the fields that have changed, will be provided so you can give feedback to the customer that is updating their information. This is especially useful to assign the shipping rates, add line items, add gift cards, and so on.

Example request to update the line items

PATCH /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

{
  "checkout":{
    "line_items": [
      {
        "variant_id": 11184583431,
        "quantity": 1
      },
      {
        "variant_id": 11184596679,
        "quantity": 1
      }
    ]
  }
}

View Response

HTTP/1.1 202 ACCEPTED
Content-Type: application/json; charset=utf-8
Location: https://channelsrule.myshopify.com/admin/checkouts/f9604c3f13b35c7ba36932436310ef09.json
Retry-After: 1

{
  "checkout":{
    ...
    "line_items":[
      {
        "id":"d4afb7b2a7668ec7",
        "key":"d4afb7b2a7668ec7",
        "product_id":3669721031,
        "variant_id":11184583431,
        "sku":"HOOT-001",
        "vendor":"channelsrule",
        "title":"Graphic Owl Guys Tee",
        "variant_title":"small",
        "taxable":true,
        "requires_shipping":true,
        "price":"25.00",
        "compare_at_price":"30.00",
        "line_price":"25.00",
        "properties":{},
        "quantity":1,
        "grams":200,
        "fulfillment_service":"manual",
        "applied_discounts":[

        ]
      },
      {
        "id":"e01a627d3f611bdc",
        "key":"e01a627d3f611bdc",
        "product_id":3669728775,
        "variant_id":11184596679,
        "sku":"RUBY-001",
        "vendor":"channelsrule",
        "title":"Ruby Girls Tee",
        "variant_title":"small",
        "taxable":true,
        "requires_shipping":true,
        "price":"25.00",
        "compare_at_price":"30.00",
        "line_price":"25.00",
        "properties":{},
        "quantity":1,
        "grams":200,
        "fulfillment_service":"manual",
        "applied_discounts":[]
      }
    ],
    ...
  }
}

Example request to update the shipping line

PATCH /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

{
  "checkout":{
    "shipping_line": {
      "handle": "shopify-Standard%20Shipping-8.00"
    }
  }
}

View Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "checkout": {
    ...
    "shipping_line":{
      "handle":"shopify-Standard%20Shipping-8.00",
      "price":"8.00",
      "title":"Standard Shipping"
    }
    ...
  }
}

Card vaulting

To ensure customer confidentiality, we process transactions on credit cards by relying on a separate card vaulting endpoint. It's a two step process where the credit card is submitted to the vault, and the vault returns a payment session_id that can be used to create a payment for the credit card.

For more information, please read the Card Vault Documentation

Example request to vault a credit card

POST /sessions HTTP/1.1
Host: https://elb.deposit.shopifycs.com
Content-Type: application/json
Accept: application/json

{
  "payment": {
    "amount": "100.00",
    "unique_token": "my-client-generated-idempotency-token",
    "credit_card":{
      "number": "1",
      "month": "12",
      "year": "2019",
      "verification_value": "123",
      "first_name":"John",
      "last_name":"Smith"
    }
  }
}

View Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "id":"east-44a400ef20b36e38f10b882cb7260796"
}

Completing the purchase

Direct payment

To complete the purchase, a payment must be created using the session_id created in the previous step. The request must also include the total_price of the checkout and a client-generated idempotency token.

POST /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3/payments.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

{
  "payment": {
    "session_id": "east-44a400ef20b36e38f10b882cb7260796",
  }
}

View Response

HTTP/1.1 202 ACCEPTED
Content-Type: application/json; charset=utf-8
Location: https://channelsrule.myshopify.com/admin/checkouts/f9604c3f13b35c7ba36932436310ef09/payments/123456789.json
Retry-After: 1

{
  "payment" : {
    "id": 123456789,
    "unique_token": "my-client-generated-idempotency-token",
    "transaction": null
  }
}

Polling is mandatory to retrieve the status of the transaction processed through the merchant's payment gateway. When the asynchronous processing is completed, the following request returns the transaction associated with the payment request.

GET /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3/payments/123456789.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

View Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "payment" : {
    "id": 123456789,
    "unique_token": "my-client-generated-idempotency-token",
    "transaction": {
      ...
    }
  }
}

Complete free checkouts

A call to the complete action asynchronously claims the inventory and transforms the checkout into an order. When the asynchronous processing is completed, the following request returns the checkout and associated order.

POST /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3/complete.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

{
  "checkout": {
    "token": "0aff29a2c5ab826fe623ebf8588617b3",
    "order": null,
  }
}

View Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Location: https://channelsrule.myshopify.com/admin/checkouts/f9604c3f13b35c7ba36932436310ef09.json
Retry-After: 1

{
  "checkout" : {
    "token": "f9604c3f13b35c7ba36932436310ef09",
    "order": {
      "id": 987654321,
      "name": "# 987654321",
      "status_url": "https://checkout.shopify.com/12345678/checkouts/f9604c3f13b35c7ba36932436310ef09/thank_you"
    }
    ...
  }
}

Handling errors

Validation errors

PATCH /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

{
  "checkout": {
    "email": "not a valid email"
  }
}

View Response

HTTP/1.1 422 OK
Content-Type: application/json; charset=utf-8

{
  "errors":  {
    "checkout":  {
      "email": [{"code": "invalid", "message": "is invalid", "options": {}}]
    }
  }
}

For a list of elements, the errors will be accessible by their 0-based index under the list. For example, when there is an error only on the second line item, the errors will be accessible under key "1" within the line_items key.

PATCH /admin/checkouts/0aff29a2c5ab826fe623ebf8588617b3.json HTTP/1.1
Host: channelsrule.myshopify.com
X-Shopify-Access-Token: d833234ea788000e7aba6af8b1b9a282
Content-Type: application/json

{
  "checkout":{
    "line_items": [
      {
        "variant_id": 11184583431,
        "quantity": 1
      },
      {
        "variant_id": 11184596679,
        "quantity": 255
      }
    ]
  }
}

View Response

HTTP/1.1 422 OK
Content-Type: application/json; charset=utf-8

{
  "errors": {
    "checkout": {
      "line_items": {
        "1": {
          "quantity": [{
            "code": "not_enough_in_stock",
            "message": "Not enough items available. Only 30 left.",
            "options": {
              "remaining": 30
            }
          }]
        }
      }
    }
  }
}