In this tutorial we will be creating a more complex checkout, with variants, shipping options, and tax support. For this tutorial we will be using a dummy Chec account we've already setup, Feel free to replace the api keys and product permalink with your own. We'll also be using the Javascript SDK, but will include the cURL commands where we can for your reference.

What you'll accomplish in this tutorial.

  1. Setup Commerce.js
  2. Creating a checkout token for a product
  3. Creating a checkout form
  4. Capture an order that has shipping options, variants, and tax enabled.

1. Setup Commerce.js

Install

First let's install the Commerce.js Javascript SDK and authenticate by using the following code

<script type="text/javascript" src="https://cdn.chec.io/v1/commerce.js"></script>

Authenticate

Next, to authenticate and get going, call Commerce.js with your public API key and store it as a variable.

//This is the public API key created for our Chec Dummy Account, we have also turned on the console debugger
var myStore = new Commerce('pk_test_1101361e43dd408534afd852d22f128d0b7aab34d59d6', true);

2. Creating your checkout token

We've already created a test product with the permalink commerce-js-advanced, let's go ahead an create a Checkout Token for it.

Request

$ curl https://api.chec.io/v1/checkouts/commerce-js-advanced?type=permalink \
    -H "X-Authorization: pk_test_1101361e43dd408534afd852d22f128d0b7aab34d59d6"

myStore.Checkout.generateToken('commerce-js-advanced', { type: 'permalink' }, function(resp){
  //Render Checkout
  var token_id = resp.id; //e.g. chkt_959gvxcZ6lnJ7
  //...
  },
  function(error){
  //Error handler
  }
);

#Todo
#Todo

Response

The checkout token returned should look similar to this.

{
  "id": "chkt_zoBqmp2rZJ6Prw",
  "created": 1473455960,
  "expires": 1473628760,
  "analytics": {
    "google": {
      "settings": {
        "tracking_id": null,
        "linked_domains": null
      }
    }
  },
  "conditionals": {
    "collects_fullname": true,
    "collects_shipping_address": true,
    "collects_billing_address": false,
    "has_physical_delivery": true,
    "has_digital_delivery": true,
    "has_available_discounts": false,
    "has_pay_what_you_want": false,
    "collects_extrafields": false,
    "is_cart_free": false
  },
  "collects": {
    "fullname": true,
    "shipping_address": true,
    "billing_address": false,
    "extrafields": false
  },
  "has": {
    "physical_delivery": true,
    "digital_delivery": true,
    "available_discounts": false,
    "pay_what_you_want": false
  },
  "is": {
    "cart_free": false
  },
  "line_items": [
    {
      "id": "item_7RyWOwmK5nEa2V",
      "product_id": "prod_ypbroEzJn58n4e",
      "name": "Test Product (Advanced)",
      "image": null,
      "description": "This product has both physical and digital fulfillment, as well as variants available.",
      "quantity": 1,
      "price": {
        "raw": 79,
        "formatted": "79.00",
        "formatted_with_symbol": "$79.00",
        "formatted_with_code": "79.00 USD"
      },
      "subtotal": {
        "raw": 79,
        "formatted": "79.00",
        "formatted_with_symbol": "$79.00",
        "formatted_with_code": "79.00 USD"
      },
      "variants": [
        {
          "id": "vrnt_bO6J5apWnVoEjp",
          "name": "Color",
          "options": [
            {
              "id": "optn_A12JwreeYlPjnk",
              "name": "Red",
              "price": {
                "raw": 0,
                "formatted": "0.00",
                "formatted_with_symbol": "$0.00",
                "formatted_with_code": "0.00 USD"
              }
            },
            {
              "id": "optn_Op1YoVppylXLv9",
              "name": "Blue",
              "price": {
                "raw": 0,
                "formatted": "0.00",
                "formatted_with_symbol": "$0.00",
                "formatted_with_code": "0.00 USD"
              }
            },
            {
              "id": "optn_4WJvlKppawbYV1",
              "name": "Green",
              "price": {
                "raw": 0,
                "formatted": "0.00",
                "formatted_with_symbol": "$0.00",
                "formatted_with_code": "0.00 USD"
              }
            }
          ]
        },
        {
          "id": "vrnt_4WJvlKpg7pwbYV",
          "name": "Size",
          "options": [
            {
              "id": "optn_zkK6oL99G5Xn0Q",
              "name": "Small",
              "price": {
                "raw": 0,
                "formatted": "0.00",
                "formatted_with_symbol": "$0.00",
                "formatted_with_code": "0.00 USD"
              }
            },
            {
              "id": "optn_DWy4oG44z56Jx2",
              "name": "Medium",
              "price": {
                "raw": 1,
                "formatted": "1.00",
                "formatted_with_symbol": "$1.00",
                "formatted_with_code": "1.00 USD"
              }
            },
            {
              "id": "optn_RyWOwmddglnEa2",
              "name": "Large",
              "price": {
                "raw": 2,
                "formatted": "2.00",
                "formatted_with_symbol": "$2.00",
                "formatted_with_code": "2.00 USD"
              }
            }
          ]
        }
      ],
      "conditionals": {
        "is_active": true,
        "is_free": false,
        "is_pay_what_you_want": false,
        "is_preorder": false,
        "is_quantity_limited": false,
        "is_sold_out": false,
        "has_digital_delivery": true,
        "has_physical_delivery": true,
        "has_images": false,
        "has_video": false,
        "has_rich_embed": false,
        "collects_fullname": true,
        "collects_shipping_address": true,
        "collects_billing_address": false,
        "collects_extrafields": false
      },
      "is": {
        "active": true,
        "free": false,
        "pay_what_you_want": false,
        "preorder": false,
        "quantity_limited": false,
        "sold_out": false
      },
      "has": {
        "digital_delivery": true,
        "physical_delivery": true,
        "images": false,
        "video": false,
        "rich_embed": false
      },
      "collects": {
        "fullname": true,
        "shipping_address": true,
        "billing_address": false,
        "extrafields": false
      }
    }
  ],
  "merchant": {
    "id": 11013,
    "business_name": "Commerce.js Test Account",
    "business_description": "Commerce.js is a full-stack eCommerce api for designers and developers",
    "currency": {
      "symbol": "$",
      "code": "USD"
    },
    "support_email": "sandbox@commercejs.com",
    "logo": "https://cdn.chec.io/merchants/11013/images/icon/22cef3acab8fb6ca004f388df18066cdf851603357d1d54e251b5|csj.logo.white.png",
    "logo_shape": "circle",
    "cover": "https://cdn.chec.io/merchants/11013/images/cover/ba3250991947bff6c6d55e044d150644b1a16ee157d1d54e25278|Comjs.Twitter.Header.png",
    "statement_descriptor": null,
    "has": {
      "logo": true,
      "cover": true,
      "business_description": true
    }
  },
  "extrafields": [],
  "gateways": {
    "available": {
      "test_gateway": true,
      "stripe": false,
      "chec": false,
      "paypal": true
    },
    "available_count": 2,
    "test_gateway": {
      "type": "card",
      "settings": []
    },
    "paypal": {
      "type": "third_party",
      "settings": {
        "email": "paypal@trychec.com"
      }
    }
  },
  "shipping_methods": [
    {
      "id": "ship_7RyWOwmK5nEa2V",
      "description": "Airmail",
      "price": {
        "raw": 10,
        "formatted": "10.00",
        "formatted_with_symbol": "$10.00",
        "formatted_with_code": "10.00 USD"
      },
      "region": "international"
    },
    {
      "id": "ship_1ypbroE658n4ea",
      "description": "USPS Ground",
      "price": {
        "raw": 3,
        "formatted": "3.00",
        "formatted_with_symbol": "$3.00",
        "formatted_with_code": "3.00 USD"
      },
      "region": "domestic"
    }
  ],
  "live": {
    "merchant_id": 11013,
    "currency": {
      "code": "USD",
      "symbol": "$"
    },
    "line_items": [
      {
        "id": "item_7RyWOwmK5nEa2V",
        "product_id": "prod_7RyWOwmK5nEa2V",
        "product_name": "Test Product (Advanced)",
        "quantity": 1,
        "price": {
          "raw": 79,
          "formatted": "79.00",
          "formatted_with_symbol": "$79.00",
          "formatted_with_code": "79.00 USD"
        },
        "line_total": {
          "raw": 79,
          "formatted": "79.00",
          "formatted_with_symbol": "$79.00",
          "formatted_with_code": "79.00 USD"
        },
        "variants": [],
        "tax": {
          "is_taxable": false,
          "taxable_amount": null,
          "amount": null,
          "breakdown": null
        }
      }
    ],
    "subtotal": {
      "raw": 79,
      "formatted": "79.00",
      "formatted_with_symbol": "$79.00",
      "formatted_with_code": "79.00 USD"
    },
    "discount": [],
    "shipping": {
      "price": {
        "raw": 0,
        "formatted": "0.00",
        "formatted_with_symbol": "$0.00",
        "formatted_with_code": "0.00 USD"
      }
    },
    "tax": {
      "amount": {
        "raw": 0,
        "formatted": "0.00",
        "formatted_with_symbol": "$0.00",
        "formatted_with_code": "0.00 USD"
      }
    },
    "total": {
      "raw": 79,
      "formatted": "79.00",
      "formatted_with_symbol": "$79.00",
      "formatted_with_code": "79.00 USD"
    },
    "total_with_tax": {
      "raw": 79,
      "formatted": "79.00",
      "formatted_with_symbol": "$79.00",
      "formatted_with_code": "79.00 USD"
    },
    "pay_what_you_want": {
      "enabled": false,
      "minimum": null,
      "customer_set_price": null
    }
  }
}

As you can see the The Checkout Token Object returned by Chec contains a lot of information to help you generate your checkout.


3. Create a checkout form

There are many ways to go about this, but for this tutorial we are going to use javascript.

As you can see in the Checkout Token, we have supplied some useful verb conditionals about the checkout.

"conditionals": {
  "is_active": true,
  "is_free": false,
  "is_pay_what_you_want": false,
  "is_preorder": false,
  "is_quantity_limited": false,
  "is_sold_out": false,
  "has_digital_delivery": true,
  "has_physical_delivery": true,
  "has_images": false,
  "has_video": false,
  "has_rich_embed": false,
  "collects_fullname": true,
  "collects_shipping_address": true,
  "collects_billing_address": false,
  "collects_extrafields": false
},
"is": {
  "active": true,
  "free": false,
  "pay_what_you_want": false,
  "preorder": false,
  "quantity_limited": false,
  "sold_out": false
},
"has": {
  "digital_delivery": true,
  "physical_delivery": true,
  "images": false,
  "video": false,
  "rich_embed": false
},
"collects": {
  "fullname": true,
  "shipping_address": true,
  "billing_address": false,
  "extrafields": false
}

Using these conditionals and looping through the line_item, variants, and shipping options to generate you can create a checkout to show only the data and inputs required. Here's an example of how to render a select for a products variant using data from the checkout token.

(This example used jQuery, a full working example of this checkout is available at the bottom of this page)

$(document).ready(function(){
//Create a checkout token for the product with the permalink 'commerce-js-example'.
myStore.Checkout.generateToken('commerce-js-advanced',  { type: 'permalink' }, function(resp){
  //Store the checkout token id as a global variable
  checkout_token_id = resp.id;

        //Loop through each variant in the first line item (we only have one product for this checkout)
        $.each(resp.line_items[0].variants, function(k, variant) {
          //Open select
          var variant_html = "<select name=\"line_items["+resp.line_items[0].id+"][variants]["+variant.id+"]\">";
          //For each option in this variant create an <option> field
          $.each(variant.options, function(k, option) {
            //Set the <option> value as this option's id
            variant_html += "<option value=\""+option.id+"\">" + option.name + "</option>";
          });
          //Close the select
          variant_html += "</select><br>";
          //Append the new <select> in the variants <div>
          $('#variants').append(variant.name+': '+variant_html);
        });

  });
});

4. Capturing the order

Important

We utilize key => value multidimensional arrays to immediately associate values with their parent(s) id when submitting data. For example with line items, the key would be the line_item_id and related values would be nested under that key.

  • Line item's quantity: line_item[{line_item_id}][quantity]
  • Line item's variant: line_item[{line_item_id}][variant][{variant_id}] = "{option_id}"

Tax Support

Tax support in Commerce.js is automatic, we calculate tax based on the shipping address submitted, If for whatever reason you're not submiting an address for the customer, you can supply the tax region with these arguments.

  • tax[ip_address] Required if only using IP address to set tax location. We will set the tax location to the estimated location of this IP
  • tax[country] Required If not using IP address to set tax location. Must be a valid ISO 3166-1 alpha-2 country code (e.g. GB - United Kingdom)
  • tax[region] Required if Canada (CA) or USA (CA) - Must be a valid short code for the region e.g. CA - California or QB - Quebec
  • tax[postal_zip_code] Required If Auto US Sales Tax turned on

EU VAT MOSS

If you have EU VAT MOSS enabled, you can use the helper function "Get buyers location from IP", and use this value to set tax[ip_address]

Important If you're working with PayPal, you should send both tax[ip_address] and tax[country] (by asking the buyer to select their tax country from a drop down) - We use both of these for evidence.

Request (with Test Gateway)

For this request we are simply going to the shipping address to calculate the tax for this order.

$ curl https://api.chec.io/v1/checkouts/{checkout_token_id} \
    -H "X-Authorization: pk_test_1101361e43dd408534afd852d22f128d0b7aab34d59d6" \
    -d line_items[item_7RyWOwmK5nEa2V][quantity]="1" \
    -d line_items[item_7RyWOwmK5nEa2V][variants][vrnt_bO6J5apWnVoEjp]="optn_Op1YoVppylXLv9" \
    -d line_items[item_7RyWOwmK5nEa2V][variants][vrnt_4WJvlKpg7pwbYV]="optn_zkK6oL99G5Xn0Q" \
    -d customer[firstname]="John" \
    -d customer[lastname]="Doe" \
    -d customer[email]="buyer@email.com" \
    -d shipping[name]="John Doe" \
    -d shipping[street]="161 Mission St" \
    -d shipping[town_city]="San Francisco" \
    -d shipping[county_state]="CA" \
    -d shipping[postal_zip_code]="94103" \
    -d shipping[country]="US" \
    -d fulfillment[shipping_method]="ship_1ypbroE658n4ea" \
    -d payment[gateway]="test_gateway" \
    -d payment[card][number]="4242 4242 4242 4242" \
    -d payment[card][expiry_month]="01" \
    -d payment[card][expiry_month]="2019" \
    -d payment[card][cvc]="123" \
    -d payment[card][postal_zip_code]="94107"
myStore.Checkout.capture('{checkout_token_id}',
  {
    "line_items": {
      //Key is the line item id for "Test Product (Advanced)"
      "item_7RyWOwmK5nEa2V": {
        "quantity": 1,
        "variants": {
          "vrnt_bO6J5apWnVoEjp": "optn_Op1YoVppylXLv9", //Key is the variant id for "Color", value is the option id for "Blue"
          "vrnt_4WJvlKpg7pwbYV": "optn_zkK6oL99G5Xn0Q"  //Key is the variant id for "Size", value is the option id for "Small"
        }
      }
    },
    "customer": {
      "firstname": "John",
      "lastname": "Doe",
      "email": "buyer@email.com"
    },
    "shipping": {
      "name": "John Doe",
      "street": "1161 Mission St",
      "town_city": "San Francisco",
      "county_state": "CA",
      "postal_zip_code": "94103",
      "country": "US"
    },
    "fulfillment": {
      "shipping_method": "ship_1ypbroE658n4ea" //The value is thee shipping id for "USPS Ground"
    },
    "payment": {
      "gateway": "test_gateway",
      "card": {
        "number": "4242 4242 4242 4242",
        "expiry_month": "01",
        "expiry_year": "2019",
        "cvc": "123",
        "postal_zip_code": "94107"
      }
    }
  },
  function(resp) {
      console.log(resp)
  },
  function(error) {
    console.log(error)
  }

);
#Todo
#Todo

Response (Receipt)

If successful, The Receipt Object will be returned!

{
  "id": "ord_zkK6oLDLKoXn0Q",
  "created": 1473456439,
  "redirect": false,
  "customer_reference": "CMMRCJSTS-26710",
  "status_payment": "paid",
  "status_fulfillment": "not_fulfilled",
  "customer": {
    "email": "buyer@email.com",
    "firstname": "John",
    "lastname": "Doe"
  },
  "extrafields": null,
  "shipping": {
    "name": "John Doe",
    "street": "161 Mission St",
    "town_city": "San Francisco",
    "county_state": "CA",
    "postal_zip_code": "94103",
    "country": "US"
  },
  "billing": null,
  "order": {
    "line_items": [
      {
        "id": "item_7RyWOwmK5nEa2V",
        "product_id": "prod_7RyWOwmK5nEa2V",
        "product_name": "Test Product (Advanced)",
        "quantity": 1,
        "price": {
          "raw": 79,
          "formatted": "79.00",
          "formatted_with_symbol": "$79.00",
          "formatted_with_code": "79.00 USD"
        },
        "line_total": {
          "raw": 79,
          "formatted": "79.00",
          "formatted_with_symbol": "$79.00",
          "formatted_with_code": "79.00 USD"
        },
        "variants": [
          {
            "variant_id": "vrnt_bO6J5apWnVoEjp",
            "option_id": "optn_Op1YoVppylXLv9",
            "variant_name": "Color",
            "option_name": "Blue",
            "price": {
              "raw": 0,
              "formatted": "0.00",
              "formatted_with_symbol": "$0.00",
              "formatted_with_code": "0.00 USD"
            }
          },
          {
            "variant_id": "vrnt_4WJvlKpg7pwbYV",
            "option_id": "optn_zkK6oL99G5Xn0Q",
            "variant_name": "Size",
            "option_name": "Small",
            "price": {
              "raw": 0,
              "formatted": "0.00",
              "formatted_with_symbol": "$0.00",
              "formatted_with_code": "0.00 USD"
            }
          }
        ],
        "tax": {
          "is_taxable": true,
          "taxable_amount": 79,
          "amount": 6.92,
          "breakdown": [
            {
              "amount": 4.94,
              "rate": 0.0625,
              "rate_percentage": "6.25%",
              "type": "state"
            },
            {
              "amount": 0,
              "rate": 0,
              "rate_percentage": "0%",
              "type": "city"
            },
            {
              "amount": 0.2,
              "rate": 0.0025,
              "rate_percentage": "0.25%",
              "type": "county"
            },
            {
              "amount": 1.78,
              "rate": 0.0225,
              "rate_percentage": "2.25%",
              "type": "district"
            }
          ]
        }
      }
    ],
    "subtotal": {
      "raw": 79,
      "formatted": "79.00",
      "formatted_with_symbol": "$79.00",
      "formatted_with_code": "79.00 USD"
    },
    "discount": [],
    "shipping": {
      "id": "ship_1ypbroE658n4ea",
      "description": "USPS Ground",
      "price": {
        "raw": 3,
        "formatted": "3.00",
        "formatted_with_symbol": "$3.00",
        "formatted_with_code": "3.00 USD"
      }
    },
    "tax": {
      "amount": {
        "raw": 6.92,
        "formatted": "6.92",
        "formatted_with_symbol": "$6.92",
        "formatted_with_code": "6.92 USD"
      },
      "included_in_price": false,
      "breakdown": [
        {
          "amount": 4.94,
          "rate": 0.0625,
          "rate_percentage": "6.25%",
          "type": "state"
        },
        {
          "amount": 0,
          "rate": 0,
          "rate_percentage": "0%",
          "type": "city"
        },
        {
          "amount": 0.2,
          "rate": 0.0025,
          "rate_percentage": "0.25%",
          "type": "county"
        },
        {
          "amount": 1.78,
          "rate": 0.0225,
          "rate_percentage": "2.25%",
          "type": "district"
        }
      ],
      "zone": {
        "country": "US",
        "region": "CA",
        "postal_zip_code": "94103",
        "ip_address": null
      }
    },
    "total": {
      "raw": 82,
      "formatted": "82.00",
      "formatted_with_symbol": "$82.00",
      "formatted_with_code": "82.00 USD"
    },
    "total_with_tax": {
      "raw": 88.92,
      "formatted": "88.92",
      "formatted_with_symbol": "$88.92",
      "formatted_with_code": "88.92 USD"
    },
    "pay_what_you_want": {
      "enabled": false,
      "minimum": null,
      "customer_set_price": null
    }
  },
  "payment": {
    "id": "pymnt_179aCKX74Nzq577",
    "transaction_id": 1473456439,
    "card_type": "visa",
    "gateway": "test_gateway",
    "reference": "4242"
  },
  "fulfillment": {
    "shipping": {
      "id": "ship_1ypbroE658n4ea",
      "description": "USPS Ground",
      "price": "3.00"
    },
    "digital": [
      {
        "line_item_id": "item_7RyWOwmK5nEa2V",
        "product_id": "prod_ypbroEzJn58n4e",
        "product_name": "Test Product (Advanced)",
        "packages": [
          {
            "id": "ful_0egY5ejgMl3QnA",
            "name": "holo.large.png",
            "access_link": "https://api.chec.io/fulfill/ord_zkK6oLDLKoXn0Q/ful_0egY5ejgMl3QnA",
            "ext": "PNG",
            "size": "267.14 KB",
            "size_in_bytes": "273554"
          }
        ],
        "lifespan": {
          "expires": true,
          "expiry_date": 1473715639,
          "duration": "3",
          "period": "days",
          "download_limit": "unlimited",
          "human": "Download links expire on September 12th, 2016, and can be accessed unlimited time(s)"
        }
      }
    ]
  },
  "conditionals": {
    "collects_fullname": true,
    "collects_shipping_address": true,
    "collects_billing_address": false,
    "fulfill_shipping": true,
    "fulfill_digital": true,
    "has_available_discounts": false,
    "has_pay_what_you_want": false,
    "collects_extrafields": false,
    "is_cart_free": false
  },
  "metadata": [],
  "fraud": [],
  "merchant": {
    "id": 11013,
    "business_name": "Commerce.js Test Account",
    "business_description": "Commerce.js is a full-stack eCommerce api for designers and developers",
    "currency": {
      "symbol": "$",
      "code": "USD"
    },
    "support_email": "sandbox@commercejs.com",
    "logo": "https://cdn.chec.io/merchants/11013/images/icon/22cef3acab8fb6ca004f388df18066cdf851603357d1d54e251b5|csj.logo.white.png",
    "logo_shape": "circle",
    "cover": "https://cdn.chec.io/merchants/11013/images/cover/ba3250991947bff6c6d55e044d150644b1a16ee157d1d54e25278|Comjs.Twitter.Header.png",
    "statement_descriptor": null,
    "has": {
      "logo": true,
      "cover": true,
      "business_description": true
    }
  }
}

And that's it!