Creating a Headless BigCommerce Cart and Checkout Flow with Postman

Patrick Puente
BigCommerce Developer Blog
29 min readFeb 3, 2020

--

Postman is a powerful tool. Most developers I work with are already familiar with it to some extent. If you’re a Postman pro or if you’re just getting started, this article is intended to walk you through creating a Postman collection that demonstrates a cart and checkout sequence using BigCommerce Server to Server APIs.

But first, what is Postman? It’s a lot of things: you can use it to design and mock an API, automate API monitoring, and collaborate with team members. As an Enterprise Solutions Architect at BigCommerce, I personally use Postman on a daily basis to explore the new APIs we release, experiment quickly to validate new application design ideas, and automate a series of requests. But for this article, Postman will be the client for BigCommerce APIs.

In this tutorial, you will configure an environment in Postman with BigCommerce API credentials, and you will create a collection that demonstrates a headless cart and checkout sequence on BigCommerce. But, if you want to skip all the fun of building it and just want the collection, you can get it here.

BigCommerce Environment Setup

Before getting started in Postman, make sure you have the appropriate BigCommerce environment configured. To complete this example, you will need a BigCommerce store where you can create orders and safely modify the catalog and payments settings. If you do not already have a BigCommerce store where you can safely test, you may set up a free trial at https://www.bigcommerce.com/essentials.

Products

  • One of the first 250 products must be in stock and purchasable

This is because the final collection will only require the store hash and API credentials to be set manually. All other variables like product and cart IDs will be automatically created by scripts. So an example product will be retrieved from the Catalog Products API before it’s added to the cart. Since the maximum number of products per response is 250, one of the first 250 products must meet the criteria. The collection could paginate through responses until it finds an in-stock product, but that is outside of the scope of this article.

The product must not have any required modifiers because the script that retrieves option values from the Catalog Products API does so by observing the option_selections array on a variant. The collection could be extended to retrieve Modifiers and Modifier Values, but that is outside of the scope of this article.

Shipping

  • The product must be able to be shipped to an address of your choosing (the example uses an address in Austin, TX)

The shipping step in checkout is not strictly required: a digital product does not require a shipping address or shipping option. But, this article assumes the store is selling physical products and the shipping step is required to complete checkout. In order to complete checkout, BigCommerce must be able to provide a shipping quote for the product in the cart to the shipping address supplied by Postman. More information on configuring shipping: https://support.bigcommerce.com/s/article/Shipping-Setup

A Payment Gateway in Test Mode

  • Run tests without real money
  • The test payment gateway is not supported by Payments API

In this example, I will use Stripe because my Stripe account automatically comes with a test environment, and because BigCommerce provides a setting to swap between Stripe’s production and test environments.

When using Stripe’s test environment, a shopper or API consumer can complete payment with the test Visa card number 4111111111111111

Consider using a sandbox account for one of the following payment gateways where BigCommerce provides a similar Test Mode setting:

API Credentials

This example will use a BigCommerce API token and the accompanying client ID generated in your store’s control panel. See the BigCommerce documentation for information on creating an API account.

The API account will require the following scopes:

  • Orders: read-only
  • Create Payments: create
  • Get Payment Methods: read-only
  • Products: read-only
  • Carts: modify
  • Checkouts: modify

Postman Environment Setup

Download Postman for Mac, Windows, or Linux at https://www.getpostman.com/downloads/. For this article, I used the Postman app for Mac.

It bears repeating: Postman is a lot of things. But, here’s a quick overview of the features and tools you’ll use in this article. After you first install Postman and launch it, you can open a new request to get a screen that looks something like this:

Enable the Dark theme in Postman’s preferences for this super cool color scheme

Environments
Postman is capable of storing variables for use in your requests or scripts. You’ll use these to store things like your BigCommerce API token, cart ID, and shipping options. You can manually or programmatically create and modify environment variables.

Tip
It is a good practice to use a separate environment for each BigCommerce store, and even for each you’re building with that store.

Collections
Collections are a way to group requests. You can also use Collection Runner to automate requests, scripts, and tests in a collection. In this article, you will create a BigCommerce Cart and Checkout collection. Just like environments, you can manually or programmatically create and modify collection variables.

Headers
You will add request headers from the Headers tab. You can save header presets for frequently used headers. In this example, you will create a header preset to authenticate your requests to BigCommerce using the API tokens stored in your environment.

Tests and Pre-request Scripts
Tests are JavaScript that is run after receiving a response to your request. Pre-request Scripts are JavaScript that is run before sending a request. Postman provides some built-in functions to facilitate writing tests and pre-request scripts.

You will access the response body with the pm.response object supplied by Postman. Similarly, you will use the built-in functions pm.collectionVariables.get() and pm.collectionVariables.set() to get and set collection variables from a test script, as well as the built-in pm.test() method to execute tests. You can also modify or interrupt the sequence of requests in a collection with the postman.setNextRequest() method, but that is outside of the scope of this article.

Tests and pre-request scripts may be created at the request level or at the collection level. This article will only demonstrate the use of scripts at the request level. Scripts at the collection level will execute before or after each request in the collection. For more information on scripts in Postman, check out the Postman documentation here.

Create an Environment

Click the Manage Environments button…

…then click the Add button.

Type a name for the environment, then create the following environment variables

  • store-hash: The unique and randomly generated string that identifies your BigCommerce store. This string is present in the API Path in the .txt file supplied by BigCommerce when you generate API credentials from the BigCommerce control panel.

Example API Path
https://api.bigcommerce.com/stores/<STORE-HASH>/v3/

  • token: The API token provided by BigCommerce
  • client-id: The BigCommerce Client ID provided with the API token
Example environment variables and BigCommerce API credentials .txt file

Click the Add button to save the environment, then close the environments window. Next, select the environment from the environments dropdown:

Sequence Overview

This example demonstrates how an application could use BigCommerce in a headless fashion to manage carts, checkouts, and payments. Postman will retrieve information about a product, add it to a cart, then complete the billing, shipping, and payment steps of checkout.

A(n important) Note about Payments
In the payment step, Postman will supply a test credit card number. Applications and developers that handle real credit card numbers must consider the implications for PCI compliance. If an application passes credit card information to BigCommerce, that application’s PCI compliance and Cardholder Data Environment (CDE) are not managed by BigCommerce.

You can minimize PCI compliance burden by using the Stored Credit Cards feature provided by BigCommerce. Assuming a cart has a customer ID associated with it, and the customer has previously stored a credit card with BigCommerce, the application can use the customer’s stored payment method to make a payment instead of using a credit card number.

Alternatively, applications may choose to redirect shoppers to a checkout page hosted by BigCommerce, or even embed the BigCommerce checkout page in another web app. With this approach, instead of using the BigCommerce Checkout APIs the shopper would use a page hosted by BigCommerce to pass the shipping information and credit card data directly from the browser to BigCommerce.

This article will point out where these alternative paths may be pursued, but it will not cover them in detail. Instead, this article will demonstrate how to pass credit card data to BC’s Payments API to process payment and assumes all card numbers are test card numbers supplied by the payment gateway such as the test Visa card number 4111111111111111 used by most payment gateway test environments.

At a high level, the collection will follow this sequence:

  1. Postman will retrieve the first 250 products in the store to find a product that is in stock, then store information about the product in a collection variable.
  2. Postman will create a cart with the product information.
  3. Postman will store the line item ID and the cart ID from the response in a collection variable.
  4. Postman will use the line item ID and cart ID to add a consignment to checkout with a hard-coded shipping address.
  5. BigCommerce will respond with the available shipping options.
  6. Postman will store the first available shipping option id in a collection variable, then update the consignment with the selection.
  7. Postman will use the cart ID to add a billing address to the checkout.
  8. Postman will convert the cart into an incomplete order and store the order id in a collection variable.
  9. Postman will retrieve a list of available payment methods from BigCommerce and store the payment method id in a collection variable
  10. Postman will generate a Payment Access Token and store it in a collection variable.
  11. Postman will use the Payment Access Token to supply hard-coded test credit card details to payments.bigcommerce.com
  12. BigCommerce will process payment and update the order accordingly

Create the Collection

Now, to actually do the thing! Start by making a new collection. Click the + New Collection button in Postman…

…enter a name and optionally a description for the collection, then click the “Add” button. Take note of the Variables tab. Just like you can set environment variables, you can set collection variables. This is where pre-request scripts and tests will store things like product and cart IDs.

Now, to create the requests.

Request #1: Retrieve First 250 Products with Variants (GET)

New Request tab

Click the New Request tab to open a new request tab in Postman.

Authentication Headers Preset
At this point, let’s take a moment to store some preset headers that we can use throughout the rest of the tutorial. Click the Headers tab under the request URL, then click Presets > Manage Presets.

Click the Add button, then name the preset and add the following headers:

  • Accept: application/json
  • Content-Type: application/json
  • X-Auth-Client: {{client-id}}
  • X-Auth-Token: {{token}}

Double Curly Brackets
This is the first time we’ve encountered the double curly bracket syntax. Postman uses double curly brackets to identify variables, so {{client-id}} and {{token}} reference the client-id and token environment variables you set earlier.

Orange variable names mean Postman can find a value, while red variable names indicate Postman can’t find the variable. If yours are red, check that you have selected the correct environment and the variable’s name is correct.

Click the Add button to save the preset, then close the presets window. Next, on the Headers tab of the Untitled Request tab open in Postman, click the Presets dropdown to select your new preset. You should now see your preset headers on the Untitled Request tab.

Request URL
In the text field with the suggestive text “Enter request URL”, type the following URL:

https://api.bigcommerce.com/stores/{{store-hash}}/v3/catalog/products?limit=250&include=variants

Notice the orange highlighting for the {{store-hash}} environment variable.

At this point, you should be able to send the request and get a response. Click the Send button and observe the Response pane below (or beside in two-pane view) the request headers. You should see the response body, a tab to view response headers, and some information about the response like the status code, response time, and size.

Now is a good time to save your work. Go ahead and click the Save button to open the Save Request window. Enter a request name, select your collection, then click the Save to [Collection Name] button.

You can also now expand your collection on the collections tab in the sidebar where you should see your new request. This pane is where we will navigate between requests in the collection.

Request #1 Tests
Before we start parsing the response body for the information the next request will need, let’s write some tests so that we know we got the correct response status, and the response includes at least one product in the collection. I won’t go into much detail about this code. See the Postman documentation for more information on tests.

You may be asking, “why do I need tests here”. You may not, but it’s a good practice to get in the habit of writing tests for your requests in a collection so that when/if something does go wrong down the road, you can give yourself hints about where the problem may be.

Click the Tests tab under the URL, then add the following code:

pm.test("Response is not an error", () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("error")
})
pm.test("Response is JSON with data", () => {
pm.response.to.have.jsonBody("data")
})
pm.test("Response includes at least one product", () => {
pm.expect(pm.response.json().data.length).to.be.above(0)
})

Let’s check the test output. Click the Test Results tab under the Tests panel, then click the Send button to send the request and execute the tests. Assuming all tests pass, you should see output similar to this:

Go ahead and click the Save button to save your work.

Identify a Saleable Product and Variant
Great, we can get the first 250 products in the store and validate the response automatically with tests. Now let’s write a script to iterate through the collection in the response until we find a saleable product. The criteria for a saleable product are:

  • availability is not “disabled”
  • if inventory_tracking is not “none”, then inventory_level must be greater than 0

In addition to selecting a product, we will need to select a saleable variant of that product. The criteria for a saleable variant is that the variant is in stock, or stock is not tracked at the variant level.

  • if inventory_tracking is not “variant”, then any (the first) variant is saleable
  • else, inventory_tracking is “variant” and we will iterate through the variants until we find one with an inventory_level that is greater than 0

Once we identify a saleable product and variant, we will store the product ID, variant ID, and variant’s option_values as collection variables for use in the next request.

Add the following code to the Tests field below the tests you added earlier:

const products = pm.response.json().data
const firstSaleableProduct = products.find(product => {
if (product.availability !== 'disabled')
if (product.inventory_tracking !== 'none')
return product.inventory_level > 0
else return true
})
const firstSaleableVariant = firstSaleableProduct.inventory_tracking !== 'variant'
? firstSaleableProduct.variants[0]
: firstSaleableProduct.variants.find(variant => variant.inventory_level > 0)

More Tests
Let’s add some tests to ensure the product and variant have the necessary information before we try to store it. Add the following code to the end of the Tests field:

// Test values before storing them
pm.test('Found a saleable product with a product ID', () => {
pm.expect(firstSaleableProduct.id).to.be.a('number')
})
pm.test('Found a saleable variant with a variant ID', () => {
pm.expect(firstSaleableVariant.id).to.be.a('number')
})
pm.test('Saleable variant\'s option values is an array', () => {
pm.expect(firstSaleableVariant.option_values).to.be.a('array')
})

Click the Send button to make sure your code is working as intended. You should now see three new tests on the Test Results tab:

Go ahead and click the Save button to save your work.

Store the Product ID, Variant ID, and Option Values
Now that you’ve found the right values in the response body, let’s store them in collection variables so the next request in the collection can access them. Add the following code to the end of the Tests field.

// Clear any previously stored collection variables
pm.collectionVariables.unset('product-id')
pm.collectionVariables.unset('variant-id')
pm.collectionVariables.unset('option-values')
// Store new collection variables
pm.collectionVariables.set('product-id', firstSaleableProduct.id)
pm.collectionVariables.set('variant-id', firstSaleableVariant.id)
pm.collectionVariables.set('option-values', JSON.stringify(firstSaleableVariant.option_values))

Now let’s ensure Postman is storing the variables with the collection. Click the Send button one more time to send the request and execute the code in the Tests field. Then, in the Collections pane click the ellipse for your collection, then click Edit

…and navigate to the Variables tab where you should see the variables set by pm.collectionVariables.set().

Go ahead and click the Save button to save your work.

Awesome! One request down, eight to go (the rest won’t be as complicated, I promise).

Request #2: Create a Cart (POST)

Having stored the product ID, variant ID, and option selections, we have everything we could possibly need to create a guest shopping cart. This example will not use a customer ID, but if you intend to use a stored credit card instead of passing credit card data in a request, this is where you would add a customer_id to the cart so Postman could later access that customer’s stored credit cards.

Start by opening a new request tab. You may close the previous request tab (make sure you saved your work first!).

Headers
We’ll use our handy headers preset to populate the headers this time. Click the Headers tab under the URL field, then click Presets and select your preset

You’ll do this step several more times, so this is the last time I’ll add a screenshot.

Method and URL
Click the method dropdown to the left of the URL field to select POST.

Next, add the following URL to the URL field:
https://api.bigcommerce.com/stores/{{store-hash}}/v3/carts

Request Body
Click the Body tab under the URL, then select the raw radio button. This should expose an empty text area beneath:

Add the following request body to the text field

{
"line_items": [
{
"quantity": 1,
"product_id": {{product-id}},
"variant_id": {{variant-id}},
"option_selections": {{option-selections}}
}
]
}

But wait, if you send the request now you’ll get a 400 response code with an error indicating the input is invalid. If you inspect the request Postman actually sent from Postman Console, you’ll see the variables are not populated. This is for two reasons:

  1. The request is not saved to the collection yet, so the request doesn’t have access to theproduct-id and variant-id collection variables.
  2. We never stored an option-selections variable. Instead, we stored an option-values variable with the data from the previous request. We’ll need to add a pre-request script to transform the option-values into the correct format.

Go ahead and click the Save button to save the request in your collection:

Pre-request Script
Let’s add a pre-request script to transform the option-values array from the previous response into an option_selection array for this request.

Kebab or Snake-case?
It’s just my personal preference, but I use kebab-case for variables in Postman so that I can easily tell them apart from the snake-case key names used by the BigCommerce Server to Server APIs, and the camel-case key names used by the BigCommerce Storefront APIs.

Click the Pre-request Script tab under the URL to expose an empty text area.

The script must transform the option_values array provided by the previous response from the Catalog Products API that looks something like…

"option_values": [
{
"id": 70,
"label": "M",
"option_id": 108,
"option_display_name": "Size"
},
{
"id": 7,
"label": "Silver",
"option_id": 109,
"option_display_name": "Color"
}
]

…into an option_selections for use by the Carts API that looks something like…

"option_selections": [
{
"option_id": 108,
"option_value": 70
},
{
"option_id": 109,
"option_value": 7
}
]

To do that, we first need to retrieve the option-values collection variable. Add this to the pre-request script:

const optionValues = JSON.parse(pm.collectionVariables.get('option-values'))

Next, we’ll transform optionValues into a new array:

const optionSelections = optionValues.map(value => ({
option_id: value.option_id,
option_value: value.id
}))

Finally, we’ll convert the array to a string and store it in a new collection variable named option-selections:

// unset any previous variable
pm.collectionVariables.unset('option-selections')
// set the new option selections
pm.collectionVariables.set('option-selections', JSON.stringify(optionSelections))

That’s it for the pre-request script. Now, if you send the request again, you should get a JSON response body with a new cart:

Go ahead and click the Save button to save your work.

Tests
Just as in the previous request, we’ll add code to the Tests tab to both automatically execute tests to ensure we got the response we expected, and also to store information we’ll need in subsequent requests. Specifically, we’ll store the cart ID and line item ID.

To make sure the response looks correct, add the following tests to the Tests tab.

pm.test('Response is not an error', () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("error")
})
pm.test('Response is JSON with data', () => {
pm.response.to.have.jsonBody("data")
})
pm.test('Response includes a cart ID', () => {
pm.expect(pm.response.json().data.id).to.be.a('string')
})

Sending the request again should result in a new cart with three successful tests:

Now, let’s extract the cart ID and line item ID, then store them in new collection variables. Add the following code to the Tests field.

const cart = pm.response.json().data
const cartId = cart.id
// Check both physical_items and digital_items
const lineItemId = cart.line_items.physical_items.length
? cart.line_items.physical_items[0].id
: cart.line_items.digital_items[0].id

// Unset any previous variables
pm.collectionVariables.unset('cart-id')
pm.collectionVariables.unset('line-item-id')
// Set the new variables
pm.collectionVariables.set('cart-id', cartId)
pm.collectionVariables.set('line-item-id', lineItemId)

Now if you send the request again you should not only get a new cart in the response body, but you should also see the new variables when you edit your collection:

Go ahead and click the Save button to save your work.

Request #3: Create a Consignment (POST)

Redirecting/Embedding Checkout
If you wanted to embed or redirect to a BigCommerce-hosted checkout page for the shopper to complete checkout, this is the point where your sequence would diverge from this one. Instead of continuing with the next requests to complete the checkout, you would use the Cart Redirect URLs API to generate a redirect URL.

Now that we have a cart, we can begin the checkout process. We’ll start with the consignment. A consignment is an object that includes

  • at least one physical line item
  • exactly one shipping address
  • exactly one selected shipping method.

Each physical line item in the cart must be associated with a consignment before the checkout is complete and able to be converted into an order.

If the line item is a digital item, these requests and associated tests will fail, but it should not prevent the collection from completing the order.

Let’s create the request in a slightly different way so that it immediately has access to collection variables. Click the New button in the upper left of the screen, then click Request.

Enter a name for the request and select your collection, then click the Save button.

Headers
Add your headers preset from the Headers tab under the URL field.

Method and URL
Change the method dropdown to POST, and enter the following URL:

https://api.bigcommerce.com/stores/{{store-hash}}/v3/checkouts/{{cart-id}}/consignments?includes=consignments.available_shipping_options

Why ?includes=consignments.available_shipping_options?
By default, the Checkout APIs do not calculate shipping options for each response. To ask the API to return the available shipping options for use in the next request, we must specify that with the includes parameter.

Request Body
Click the Body tab under the URL, then select the raw radio button which should expose an empty text area beneath. Add the following request body to the text field.

[
{
"line_items": [
{
"item_id": "{{line-item-id}}",
"quantity": 1
}
],
"shipping_address": {
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.org",
"company": "",
"address1": "11305 Four Points Dr #300",
"address2": "",
"city": "Austin",
"state_or_province": "Texas",
"state_or_province_code": "TX",
"country_code": "US",
"postal_code": "78726",
"phone": "5128654500"
}
}
]

Feel free to change any of the values in the shipping address as long as you supply a valid shipping address, name, and email address.

If you send the request now, you should see a new object in the consignments array in the response body, complete with an available_shipping_options array. But we’re not done with this request yet.

Tests
Of course, we need more tests! Just like the last request, we will use the Tests field to not only validate the response but also to store the information we’ll need for the next request in collection variables. Specifically, we will store the consignment ID, and the first available shipping option ID.

To ensure the response looks right, add the following tests to the Tests field.

pm.test('Response is not an error', () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("error")
})
pm.test('Response is JSON with data', () => {
pm.response.to.have.jsonBody("data")
})
pm.test('Response includes exactly one consignment', () => {
pm.expect(pm.response.json().data.consignments.length).to.equal(1)
})
pm.test('Consignment includes at least one available shipping option', () => {
pm.expect(pm.response.json().data.consignments[0].available_shipping_options.length).to.be.above(0)
})

Sending the request again should result in a new consignment with four successful tests. If there was a previous consignment, it will be destroyed when the only line item associated with it is assigned to the new consignment.

FAIL Consignment includes at least one available shipping option
If your tests look like this…

…make sure the store is configured to provide shipping quotes for that product. See the BigCommerce documentation for more information on configuring shipping origin, zones, and methods.

Next, we’ll extract and store the consignment ID and available shipping option ID for use in the next request. Add the following code to the Tests field.

const checkout = pm.response.json().data
const consignmentId = checkout.consignments[0].id
const shippingOptionId = checkout.consignments[0].available_shipping_options[0].id
// Unset any existing variables
pm.collectionVariables.unset('consignment-id')
pm.collectionVariables.unset('shipping-option-id')
// Set new variables
pm.collectionVariables.set('consignment-id', consignmentId)
pm.collectionVariables.set('shipping-option-id', shippingOptionId)

Send the request again to see the new consignment ID and available shipping option ID stored in the collection variables.

Go ahead and click the Save button to save your work.

Request #4: Add a Shipping Option to the Consignment (PUT)

After creating the consignment and retrieving the available shipping options, we must update the consignment with the selected shipping option’s ID. In this example, we’re just selecting the first available shipping option.

Start by creating a new request and saving it in your collection.

Headers
Add your headers preset from the Headers tab under the URL field.

Method and URL
Change the method dropdown to PUT, and enter the following URL:

https://api.bigcommerce.com/stores/{{store-hash}}/v3/checkouts/{{cart-id}}/consignments/{{consignment-id}}

Request Body
Click the Body tab under the URL, then select the raw radio button which should expose an empty text area beneath. Add the following request body to the text field.

{
"shipping_option_id": "{{shipping-option-id}}"
}

If you send the request now, you should receive the checkout object in the response body, and the consignment therein should now have a value for selected_shipping_option. Now let’s add some tests.

Tests
Unlike the previous requests, we don’t need any data from this request in the next requests. So, instead the tests will simply be to ensure the request was processed as expected.

Add the following code to the Tests field:

pm.test('Response is not an error', () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("error")
})
pm.test('Response is JSON with data', () => {
pm.response.to.have.jsonBody("data")
})
pm.test('Response includes exactly one consignment', () => {
pm.expect(pm.response.json().data.consignments.length).to.equal(1)
})
pm.test('Selected shipping option ID matches stored shipping option ID', () => {
pm.expect(pm.response.json().data.consignments[0].selected_shipping_option.id).to.equal(pm.collectionVariables.get('shipping-option-id'))
})

Sending the request again should result in four successful tests.

Go ahead and click the Save button to save your work.

Request #5: Create a Billing Address (POST)

We’ve completed the shipping step! Now let’s add the billing address.

Start by creating a new request and saving it in your collection.

Headers
Add your headers preset from the Headers tab under the URL field.

Method and URL
Change the method dropdown to POST, and enter the following URL:

https://api.bigcommerce.com/stores/{{store-hash}}/v3/checkouts/{{cart-id}}/billing-address

Request Body
Click the Body tab under the URL, then select the raw radio button which should expose an empty text area beneath. Add the following request body to the text field.

{
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.org",
"company": "BigCommerce",
"address1": "11305 Four Points Dr #300",
"address2": "",
"city": "Austin",
"state_or_province": "Texas",
"state_or_province_code": "TX",
"country_code": "US",
"postal_code": "78726",
"phone": "5128654500"
}

Feel free to change any of the values in the billing address as long as you supply a valid address, name, and email address.

Sending this request now should result in a checkout object in the response body including your updated billing_address. Now let’s add some tests.

Tests
Just like the last request, we don’t need any data from this request in the next requests. So, the tests will simply be to ensure the request was processed as expected.

Add the following code to the Tests field:

pm.test('Response is not an error', () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("error")
})
pm.test('Response is JSON with data', () => {
pm.response.to.have.jsonBody("data")
})
pm.test('Billing address includes an id that is a string', () => {
pm.expect(pm.response.json().data.billing_address.id).to.be.a('string')
})
pm.test('Billing address includes an email that is a non-empty string', () => {
pm.expect(pm.response.json().data.billing_address.email).to.be.a('string').that.is.not.empty
})
pm.test('Billing address includes a country_code that is 2 characters', () => {
pm.expect(pm.response.json().data.billing_address.country_code).to.be.a('string').that.has.lengthOf(2)
})

Sending the request again should result in five successful tests.

Go ahead and click the Save button to save your work.

Request #6: Create an Order (POST)

At this point, the checkout object should have all required fields to convert it into an order. We’ll use the Checkout API to convert the checkout to an order which defaults to the “Incomplete” status in BigCommerce.

Start by creating a new request and saving it in your collection.

Headers
Add your headers preset from the Headers tab under the URL field.

Method and URL
Change the method dropdown to POST, and enter the following URL:

https://api.bigcommerce.com/stores/{{store-hash}}/v3/checkouts/{{cart-id}}/orders

Request Body
There is none, skip it!

If you send the request now, you should get a response with an order ID. Until we complete the payment step, you can use this endpoint to create multiple orders from the same checkout.

Tests
Let’s add some tests to ensure the response includes an order ID. Add the following code to the Tests tab.

pm.test('Response is not an error', () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("error")
})
pm.test('Response is JSON with data', () => {
pm.response.to.have.jsonBody("data")
})
pm.test('Response includes a numeric order ID', () => {
pm.expect(pm.response.json().data.id).to.be.a('number')
})

Sending the request now should result in a new incomplete order with three successful tests.

We need to store the order ID in a collection variable for use in the next request. Add the following code to the Tests field.

const orderId = pm.response.json().data.id// Unset any previous variable
pm.collectionVariables.unset('order-id')
// Set the new variable
pm.collectionVariables.set('order-id', orderId)

Sending the request now should result in a new incomplete order, and a new collection variable for the order ID.

Request #7: Retrieve Accepted Payment Methods (GET)

Now that we have an incomplete order, we need to find out how we can process payment to complete that order. In this example, we assume that there is at least one payment provider in test mode, so we will retrieve the list of accepted payment methods, then store the ID of the first payment method with "test_mode": true.

Start by creating a new request and saving it in your collection.

Headers
Add your headers preset from the Headers tab under the URL field.

Method and URL
Leave the method dropdown at GET, and enter the following URL:

https://api.bigcommerce.com/stores/{{store-hash}}/v3/payments/methods?order_id={{order-id}}

Sending the request now should return a response body with a collection of payment methods. If the data array in your response is empty, or if none of the payment methods have "test_mode": true, ensure your store has at least one payment method that is not the test payment gateway enabled and configured to use test mode.

Paying with Stored Credit Cards
If you intend to use a stored payment instrument (e.g. credit card) to complete payment rather than passing credit card data to the Payments API, you will need to retrieve the customer’s stored payment instrument ID at this point. For the response to include a stored payment instrument, several conditions must be met:

• The payment method must support Stored Credit Cards on BigCommerce, and it must be configured to enable Stored Credit Cards.
• The cart must have a customer_id associated with it
• The customer must have previously stored a payment instrument with BigCommerce.

Observe the stored_instruments array in the response body to find stored payment instrument IDs.

Tests
We need to both validate this response, and store the ID for a payment method in test mode. Start by adding the following tests to the Tests field.

pm.test('Response is not an error', () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("error")
})
pm.test('Response is JSON with data', () => {
pm.response.to.have.jsonBody("data")
})
pm.test('At least one payment method is available', () => {
pm.expect(pm.response.json().data.length).to.be.above(0)
})

Now, let’s add some code to find the first method in test mode, and another test to validate that it was found. Add the following code to the Tests field.

const methodInTestMode = pm.response.json().data.find(method => method.test_mode)pm.test('At least one payment method is in test mode', () => {
pm.expect(methodInTestMode).not.to.be.an('undefined')
})

Sending the request now should result in four successful tests.

Finally, we need to store the payment method ID in a collection variable for use in a later request. Add the following code to the Tests field.

// Unset any previous variable
pm.collectionVariables.unset('payment-method-id')
// Set the new variable
pm.collectionVariables.set('payment-method-id', methodInTestMode.id)

Sending the request now should result in a new collection variable for the payment method ID.

Request #8 : Create a Payment Access Token (POST)

Before we can process a payment, we must generate a payment access token that Postman will use to authenticate with payments.bigcommerce.com.

Start by creating a new request and saving it in your collection.

Headers
Add your headers preset from the Headers tab under the URL field.

Method and URL
Change the method dropdown to POST, and enter the following URL:

https://api.bigcommerce.com/stores/{{store-hash}}/v3/payments/access_tokens

Request Body
Click the Body tab under the URL, then select the raw radio button which should expose an empty text area beneath. Add the following request body to the text field.

{
"order": {
"id": {{order-id}}
}
}

Sending the request now should result in a response body with a token.

Some notes about Payment Access Tokens (PATs)
- A PAT is a JWT.

- When I decoded the JWT that I received while writing this, the exp value was one hour ahead of the iat value meaning the token should be valid for an hour from when BigCommerce generated it.

- The JWT also includes information about the store, order id, and order amount meaning this token can only be used to authenticate payment for this order, and only if this order’s total amount hasn’t changed.

Tests
Add some tests to the Tests field to ensure you received a PAT…

pm.test('Response is not an error', () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("error")
})
pm.test('Response is JSON with data', () => {
pm.response.to.have.jsonBody("data")
})
pm.test('Response includes a PAT that is a string and is not empty', () => {
pm.expect(pm.response.json().data.id).to.be.a('string').that.is.not.empty
})

…and store the PAT in a collection variable

pm.collectionVariables.unset('PAT')
pm.collectionVariables.set('PAT', pm.response.json().data.id)

Request #9 : Process Payment(POST)

Alright, it’s time to do the thing you came here to do: complete a checkout with a payment. This example will pass a test credit card to the BigCommerce Payments API on the assumption that your store is configured to use a payment gateway like Stripe (not the Test Payment Gateway) in test mode, and that the payment gateway will accept the credit card number 4111111111111111.

And it’s worth noting again that you must consider the PCI compliance implications for your application and organization if you are building an application that passes credit card numbers to the BigCommerce API. Previously this article pointed out some alternative ways to process payment including embedding a BigCommerce-hosted checkout page in your web app, and using Stored Credit Cards with the Payments API.

Create a new request and saving it in your collection.

Headers
Add your headers preset, but we need to modify the Accept header’s value…

  • Accept: application/vnd.bc.v1+json

…and add one more header with the PAT from the previous request as well.

  • Authorization: PAT {{PAT}}

Method and URL
Change the method dropdown to POST, and enter the following URL:

https://payments.bigcommerce.com/stores/{{store-hash}}/payments

Request Body
Click the Body tab under the URL, then select the raw radio button which should expose an empty text area beneath. Add the following request body to the text field.

{
"payment": {
"instrument": {
"type": "card",
"number": "4111111111111111",
"cardholder_name": "John Doe",
"expiry_month": 12,
"expiry_year": 2027,
"verification_value": "123"
},
"payment_method_id": "{{payment-method-id}}"
}
}

Before sending the request, add some tests. You can send the request first, but if the payment is successful you will need to run each request in the collection from the beginning again to regenerate a valid checkout, order, and PAT.

Tests
Add the following tests to the Tests field.

pm.test('Response is not an error', () => {
pm.response.to.not.be.error
pm.response.to.not.have.jsonBody("errors")
})
pm.test('Response is JSON with data', () => {
pm.response.to.have.jsonBody("data")
})
pm.test('Response has a transaction_type that is not an empty string', () => {
pm.expect(pm.response.json().data.transaction_type).to.be.a('string').that.is.not.empty
})
pm.test('Response is JSON with status that is "pending" or "success"', () => {
pm.expect(pm.response.json().data).to.satisfy(data => data.status === 'pending' || data.status === 'success')
})

If you send the request now, you should get a response indicating the payment was successful…

…four successful tests…

…and a new order in the BigCommerce control panel under Orders > View Orders

Whoohoo!

Automate the Collection with Runner

At this point, the collection should be complete. You can try sending each request in the collection to generate a new paid order. But let’s take the next step and automate these requests. Postman makes that super simple with Collection Runner.

In the upper-left, click the Runner button to open Collection Runner

Select…

  • …your collection…
  • …your environment with the API credentials from the environment dropdown…
  • …and the number of iterations to complete.

Use the Run Collection button to start the run.

Once it’s complete, you’ll be given options to export the results which includes results for each test.

What else?

Now that you’ve demonstrated some requests with Postman, you have the blueprints you need to more quickly build an application that sends those requests. Or, you can just use your collection as quick starting point to try new things and test new ideas.

One of my favorite things about Postman is Newman, a CLI collection runner. After building the requests you need in a Postman collection, Newman can quickly access that collection from your command line, or even import Newman as a module to run the collection in a Node.js app. It’s made creating some limited-use utility scripts a breeze.

Or, you can use your collection to set up Postman monitoring where Postman servers will periodically run the requests in your collection and notify you when a test fails, allowing you to monitor the availability of a website or application. You can even integrate Postman monitors with an incident management system like PagerDuty to alert your team of new issues that need triage.

--

--