> This page is for Developer.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.bigcommerce.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.bigcommerce.com/_mcp/server.

# Lab - Create a Cart and Checkout Flow in Postman

Plan: Developer Foundations

Lesson 23 of 28 · 45 min

## Introduction

In this exercise, you'll build on the Postman workflows from previous labs with a workflow that will mimic the way common cart/checkout operations interact with the BigCommerce APIs in a headless context; this kind of prototyping is an essential first step toward understanding and implementing such a workflow in your own code.

Certain catalog data and shipping/payment configuration must be present in your BigCommerce store in order for the exercise queries to succeed. We'll detail the requirements below.

### Prerequisites

* A BigCommerce [sandbox store](/developer/docs/overview/sandboxes) or [trial store](https://www.bigcommerce.com/essentials/), or a full production store
* [Postman](https://www.postman.com/)
* An existing Postman environment and collection as configured in previous labs

### Shipping Configuration

Your store must be configured with a shipping zone that:

* Includes Austin, TX (or you can feel free to change the details of the shipping address we use)
* Has at least one available shipping method

For more about configuring shipping, see the article below:

**Shipping Setup**

KB Article

[View Resource](https://support.bigcommerce.com/s/article/Shipping-Setup)

### Product Prerequisites

Your store should contain at least one product that:

* Is physical
* Is in stock and purchasable
* Has at least one in-stock variant option
* Has no required modifier options
* Qualifies for the available shipping method

The *first* product found and captured by the previous "Get Paginated Products" request must qualify for the available shipping method.

## Postman Recap

As a reminder, your work in previous labs should have resulted in the following Postman configuration, which will be important for the following exercise steps:

* An environment with variables set for `v3_token`, `store_hash`, `storefront_channel_id` and `private_storefront_token`
* A collection with Bearer Token authentication using the value of `private_storefront_token`
* A "REST Create Private Token (server-to-server)" request
* A "GQL Get Paginated Products" request

Before beginning the following exercise, make sure to:

1. Run "REST Create Private Token (server-to-server)" to populate `private_storefront_token` on the environment with a valid token.
2. Run "GQL Get Paginated Products" until all tests pass and `product_id` and `variant_id` are populated on the collection.

## Sequence Overview

The workflow we'll be building is an example of the requests potentially involved for a headless storefront to manage carts, checkouts, and payments. The steps involved include retrieving information about a product, adding it to the cart, and completing the billing, shipping and payment steps of checkout. Most of the requests we'll be building use the GraphQL Storefront API, though certain steps like generating a GraphQL token and performing payment processing will require REST API actions.

At a high level, our Postman collection will follow this sequence:

1. **Create** a cart and **add** the product found previously, **storing** the cart and line item IDs.
2. **Get** checkout redirect URLs for the new cart, which would be used if your storefront will direct the customer to BigCommerce native checkout.
3. **Add** a shipping consignment to the checkout with a hard-coded shipping address, then **store** the first available shipping option form the response.
4. **Update** the shipping consignment to **select** the shipping method.
5. **Add** a billing address to the checkout with hard-coded details.
6. **"Complete"** the checkout, resulting in a new order record that will be considered incomplete until payment is applied.

## Create a Cart

### Step 1: Create the Request

This initial request to create a cart requires the values for `product_id` and `variant_id` stored on the collection by the "Get Paginated Products" request.

> **Info**
>
> When a cart should be associated with a registered customer, which is necessary in order to access stored credit cards in the payment steps, you must use the [assignCartToCustomer](/developer/api-reference/graphql/storefront#definition-CartMutations) mutation after the cart is created.

1. **Create** a new "GQL Create Cart" HTTP request and **save** it to your collection. This request requires the following details

| Field                         | Value                                                                              |
| ----------------------------- | ---------------------------------------------------------------------------------- |
| Method                        | POST                                                                               |
| URL                           | `https://store-{{store_hash}}-{{storefront_channel_id}}.mybigcommerce.com/graphql` |
| Authorization                 | Inherit auth from parent                                                           |
| Settings > Disable cookie jar | On                                                                                 |
| Body type                     | GraphQL                                                                            |

2. In the Headers tab, **select** your GraphQL headers preset to apply "Accept" and "Content-Type" headers
3. **Enter** the following query in the Body tab:

```graphql showLineNumbers={false}
mutation CreateCart(
    $itemQty: Int = 1,
    $productId: Int!,
    $variantId: Int
) {
    cart {
        createCart(
            input: {
                lineItems: [
                    {
                        quantity: $itemQty,
                        productEntityId: $productId,
                        variantEntityId: $variantId
                    }
                ]
            }
        ) {
            cart {
                entityId
                lineItems {
                    physicalItems {
                        entityId
                    }
                }
            }
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables section of the Body tab:

```json showLineNumbers={false}
{
    "itemQty": 1,
    "productId": {{product_id}},
    "variantId": {{variant_id}}
}
```

5. **Send** the request and **observe** the results.

### Step 2: Add Tests and Store Values

We'll once again add tests to ensure we got the response we expected, and also store information we'll need in subsequent requests. In this case, we need to store the cart ID and the line item ID.

1. **Enter** the following "Post-response" value in the Scripts tab:

```js showLineNumbers={false}
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")
});


const cart = pm.response.json().data?.cart?.createCart?.cart;
pm.test('Response includes a cart ID', () => {
    pm.expect(
        cart?.entityId
    ).to.be.a('string')
});
```

2. **Send** the request again and make sure the tests are successful
3. **Add** the following script after the initial code in Scripts:

```java showLineNumbers={false}
pm.collectionVariables.unset("cart_id");
pm.collectionVariables.unset("line_item_id");
pm.collectionVariables.set("cart_id", cart?.entityId);
pm.collectionVariables.set(
  "line_item_id",
  cart?.lineItems?.physicalItems[0]?.entityId
);
```

4. **Send** the request again, and **verify** that the `cart_id` and `line_item_id` variables are populated on the collection

## Fetch the Cart

1. **Create** a new "GQL Get Cart" HTTP request and **save** it to your collection
2. **Set** the same configuration that was used for the previous request, including the HTTP method, URL, Authorization, Headers, Body type and "Disable cookie jar" setting
3. **Enter** the following query:

```graphql showLineNumbers={false}
query GetCart(
  $cartId: String!
) {
    site {
        cart(entityId: $cartId) {
            id
            entityId
            currencyCode
            baseAmount {
                value
            }
            amount {
                value
            }
            lineItems {
                physicalItems {
                    entityId
                    productEntityId
                    variantEntityId
                    sku
                    name
                    imageUrl
                    quantity
                    listPrice {
                        value
                    }
                    originalPrice {
                        value
                    }
                    salePrice {
                        value
                    }
                }
                digitalItems {
                    entityId
                    productEntityId
                    variantEntityId
                    sku
                    name
                    imageUrl
                    quantity
                    listPrice {
                        value
                    }
                    originalPrice {
                        value
                    }
                    salePrice {
                        value
                    }
                }
            }
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables section of the Body tab:

```json showLineNumbers={false}
{
    "cartId": "{{cart_id}}"
}
```

5. **Send** the request and observe the result.

## Create Cart Redirect URLs

The following request simulates the workflow that would be used if directing customers to the BigCommerce native checkout.

### Step 1: Create the Request

1. **Create** a new "GQL Get Cart Redirect URLs" HTTP request and **save** it to your collection.
2. **Set** the same configuration that was used for the previous request, including the HTTP method, URL, Authorization, Headers, Body type and "Disable cookie jar" setting.
3. **Enter** the following query:

```graphql showLineNumbers={false}
mutation GetCartRedirectUrls(
    $cartId: String!
) {
    cart {
        createCartRedirectUrls(
            input: {
                cartEntityId: $cartId
            }
        ) {
            redirectUrls {
                redirectedCheckoutUrl
                embeddedCheckoutUrl
            }
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables section of the Body tab:

```json showLineNumbers={false}
{
    "cartId": "{{cart_id}}"
}
```

5. **Send** the request and observe the result.

### Step 2: Add Tests

1. **Enter** the following "Post-response" value in the Scripts tab:

```js showLineNumbers={false}
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")
});


const urls = pm.response.json().data?.cart?.createCartRedirectUrls?.redirectUrls;
pm.test('Response includes redirect URLs', () => {
    pm.expect(
        urls?.redirectedCheckoutUrl
    ).to.not.be.empty;
    pm.expect(
        urls?.embeddedCheckoutUrl
    ).to.not.be.empty;
});
```

2. **Send** the request again and make sure the tests are successful.

When checkout will take place on the BigCommerce hosted checkout, this is where the GraphQL workflow would end. The following requests in your workflow simulate the necessary operations for building out a full checkout experience in your own application.

## Fetch Checkout Details

The request to get the checkout will use the same ID as the cart.

1. **Create** a new "GQL Get Checkout" HTTP request and **save** it to your collection.
2. **Set** the same configuration that was used for the previous request, including the HTTP method, URL, Authorization, Headers, Body type and "Disable cookie jar" setting.
3. **Enter** the following query:

```graphql showLineNumbers={false}
query GetCart(
  $cartId: String!
) {
    site {
        checkout(entityId: $cartId) {
            cart {
                id
                entityId
                currencyCode
                baseAmount {
                    value
                }
                amount {
                    value
                }
            }
            shippingCostTotal {
                value
            }
            handlingCostTotal {
                value
            }
            taxTotal {
                value
            }
            subtotal {
                value
            }
            grandTotal {
                value
            }
            billingAddress {
                firstName
                lastName
                email
                address1
                city
                stateOrProvince
                countryCode
                postalCode
                phone
            }
            shippingConsignments {
                address {
                    firstName
                    lastName
                    email
                    address1
                    city
                    stateOrProvince
                    countryCode
                    postalCode
                    phone
                }
                availableShippingOptions {
                    description
                    type
                }
                selectedShippingOption {
                    description
                    type
                }
                shippingCost {
                    value
                }
                handlingCost {
                    value
                }
                lineItemIds
            }
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables section of the Body tab:

```json showLineNumbers={false}
{
    "cartId": "{{cart_id}}"
}
```

## Create a 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.

### Step 1: Create the Request

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Create Consignment."
2. **Set** the same configuration that was used for the previous request, including the HTTP method, URL, Authorization, Headers, Body type and "Disable cookie jar" setting.
3. **Enter** the following query:

```graphql showLineNumbers={false}
mutation AddConsignments(
    $cartId: String!,
    $lineItemId: String!,
    $lineItemQty: Int = 1
) {
    checkout {
        addCheckoutShippingConsignments(
            input: {
                checkoutEntityId: $cartId,
                data: {
                    consignments: [{
                        address: {
                            firstName: "John",
                            lastName: "Doe",
                            email: "john.doe@example.org",
                            address1: "11305 Four Points Dr",
                            city: "Austin",
                            stateOrProvince: "Texas",
                            stateOrProvinceCode: "TX",
                            countryCode: "US",
                            postalCode: "78726",
                            phone: "5128654500",
                            shouldSaveAddress: false
                        },
                        lineItems: [{
                            lineItemEntityId: $lineItemId,
                            quantity: $lineItemQty
                        }]
                    }]
                }
            }
        ) {
            checkout {
                shippingConsignments {
                    entityId
                    availableShippingOptions {
                        entityId
                    }
                }
            }
        }
    }
}
```

4. Enter the following in the GraphQL Variables section of the Body tab. Note that we're relying on the values we've stored from the previous request to supply the details of our consignment creation.

```json showLineNumbers={false}
{
    "cartId": "{{cart_id}}",
    "lineItemId": "{{line_item_id}}",
    "lineItemQty": 1
}
```

5. **Send** the request. If you have a valid shipping method configured for a zone that applies to our hard-coded address, you should see available shipping options in the response.

### Step 2: Add Tests and Store Values

Let's apply the usual sorts of tests to this response. This time around, we also need to make sure to store the IDs of the consignment and the first available shipping option.

1. **Enter** the following "Post-response" value in the Scripts tab:

```js showLineNumbers={false}
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")
});

const consignments = pm.response.json()
    .data?.checkout?.addCheckoutShippingConsignments
    ?.checkout?.shippingConsignments;

pm.test('Response includes exactly one consignment', () => {
    pm.expect(consignments?.length).to.equal(1);
});
pm.test('Consignment includes at least one available shipping option', () => {
    pm.expect(
      consignments[0]?.availableShippingOptions?.length
    ).to.be.above(0);
});
```

2. **Send** the request again and make sure the tests are successful.

Don't worry about creating a consignment multiple times. When a new consignment is created with the same line item as a previous consignment, the previous record is destroyed.
3\. **Add** the following script after the initial code:

```js showLineNumbers={false}
const consignmentId = consignments[0]?.entityId;
const shippingOptionId = consignments[0]?.availableShippingOptions[0]?.entityId;
pm.collectionVariables.unset("consignment_id");
pm.collectionVariables.unset("shipping_option_id");
pm.collectionVariables.set("consignment_id", consignmentId);
pm.collectionVariables.set("shipping_option_id", shippingOptionId);
```

4. **Send** the request again, and **verify** that the `consignment_id` and `shipping_option_id` variables are populated on the collection.

## Add a Shipping Selection to the Consignment

### Step 1: Create the Request

After creating the consignment and retrieving the available shipping options, we must update the consignment with the selected shipping option's ID.

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Select Shipping."
2. **Set** the same configuration that was used for the previous request, including the HTTP method, URL, Authorization, Headers, Body type and "Disable cookie jar" setting.
3. **Enter** the following query:

```graphql showLineNumbers={false}
mutation SelectShipping(
    $cartId: String!,
    $consignmentId: String!,
    $shippingOptionId: String!
) {
    checkout {
        selectCheckoutShippingOption(
            input: {
                checkoutEntityId: $cartId,
                consignmentEntityId: $consignmentId,
                data: {
                    shippingOptionEntityId: $shippingOptionId
                }
            }
        ) {
            checkout {
                shippingConsignments {
                    selectedShippingOption {
                        entityId
                    }
                }
            }
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables section of the Body tab:

```json showLineNumbers={false}
{
    "cartId": "{{cart_id}}",
    "consignmentId": "{{consignment_id}}",
    "shippingOptionId": "{{shipping_option_id}}"
}
```

5. **Send** the request.

### Step 2: Add Tests

Unlike the previous requests, we don't need to store any data from this response. We just need to include the right tests to make sure the shipping option was selected as intended.

1. **Enter** the following "Post-response" value in the Scripts tab:

```js showLineNumbers={false}
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");
})

const consignments = pm.response.json()
    .data?.checkout?.selectCheckoutShippingOption
    ?.checkout?.shippingConsignments;

pm.test('Response includes exactly one consignment', () => {
    pm.expect(consignments?.length).to.equal(1);
});
pm.test(
    'Selected shipping option ID matches stored shipping option ID',
    () => {
        pm.expect(
            consignments[0]?.selectedShippingOption?.entityId
        ).to.equal(
            pm.collectionVariables.get('shipping_option_id')
        )
    }
);
```

2. **Send** the request again and **verify** the tests are successful.

## Create a Billing Address

### Step 1: Create the Request

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

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Create Billing Address."
2. **Set** the same configuration that was used for the previous request, including the HTTP method, URL, Authorization, Headers, Body type and "Disable cookie jar" setting.
3. Enter the following query. Feel free to change any of the values in the billing address as long as you supply a valid address, name, and email address.

```graphql showLineNumbers={false}
mutation AddBillingAddress(
    $cartId: String!
) {
    checkout {
        addCheckoutBillingAddress(
            input: {
                checkoutEntityId: $cartId,
                data: {
                    address: {
                        firstName: "John",
                        lastName: "Doe",
                        email: "john.doe@example.org",
                        address1: "11307 Six Points Dr",
                        city: "Austin",
                        stateOrProvince: "Texas",
                        stateOrProvinceCode: "TX",
                        countryCode: "US",
                        postalCode: "78726",
                        phone: "5128654500",
                        shouldSaveAddress: false
                    }
                }
            }
        ) {
            checkout {
                billingAddress {
                    entityId
                    email
                    countryCode
                }
            }
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables section of the Body tab:

```json showLineNumbers={false}
{
    "cartId": "{{cart_id}}"
}
```

5. **Send** the request.

### Step 2: Add Tests

1. **Enter** the following "Post-response" value in the Scripts tab:

```js showLineNumbers={false}
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");
});

const billingAddress = pm.response.json()
    .data?.checkout?.addCheckoutBillingAddress
    ?.checkout?.billingAddress;

pm.test(
    'Billing address includes an id that is a string',
    () => {
        pm.expect(billingAddress?.entityId).to.be.a('string');
    }
);
pm.test(
    'Billing address includes an email that is a non-empty string',
    () => {
        pm.expect(
            billingAddress?.email
        ).to.be.a('string').that.is.not.empty;
    }
);
pm.test(
    'Billing address includes a country_code that is 2 characters',
    () => {
        pm.expect(
            billingAddress?.countryCode
        ).to.be.a('string').that.has.lengthOf(2);
    }
);
```

2. **Send** the request and **verify** the tests are successful.

## Create an Order

### Step 1: Create the Request

At this point, the checkout object should have all required fields to convert it into an order. We'll use the `completeCheckout` mutation to convert the checkout to an order, which defaults to the "Incomplete" status in BigCommerce until payment is applied.

This will be our last stop for this exercise, since the REST Payments API is required to capture payment and complete the order.

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Complete Checkout."
2. **Set** the same configuration that was used for the previous request, including the HTTP method, URL, Authorization, Headers, Body type and "Disable cookie jar" setting.
3. **Enter** the following query:

```graphql showLineNumbers={false}
mutation CompleteCheckout(
    $cartId: String!
) {
    checkout {
        completeCheckout(
            input: {
                checkoutEntityId: $cartId
            }
        ) {
            orderEntityId
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables section of the Body tab:

```json showLineNumbers={false}
{
    "cartId": "{{cart_id}}"
}
```

5. **Send** the request and observe the response. Until payment is processed on the current checkout, you can use this mutation to create multiple incomplete orders from the same checkout.

### Step 2: Add Tests and Store Values

In addition to the standard tests, you must store the resulting order ID if you intend to complete the checkout workflow with REST requests to capture payment.

1. **Enter** the following "Post-response" value in the Scripts tab:

```js showLineNumbers={false}
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 includes a numeric order ID', () => {
    pm.expect(
        pm.response.json()
        .data?.checkout?.completeCheckout?.orderEntityId
    ).to.be.a('number');
});
```

2. **Send** the request again and **verify** that tests are successful.
3. **Add** the following script after the initial tests:

```js showLineNumbers={false}
const orderId = pm.response.json()
    .data?.checkout?.completeCheckout?.orderEntityId;
pm.collectionVariables.unset("order_id");
pm.collectionVariables.set("order_id", orderId);
```

4. **Send** the request again and **verify** that the `order_id` variable is populated on the collection.

## Taking It Further

Try combining customer login with cart operations by providing a valid customer access token in the cart requests. Observe and test the effects of a `createCartRedirectUrls` request with a customer access token, which should result in a URL that automatically logs the customer in.