> 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 Customer Flow in Postman

Plan: Developer Foundations

Lesson 27 of 28 · 45 min

## Introduction

In this exercise, you'll build a workflow in Postman that mimics the standard operations a headless storefront would utilize to allow customer registration, address management, and login.

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

### Form Fields Configuration

To get the full benefit from this workflow, you should make sure that you have configured one to three custom Form Fields for customer account signup.

In your BigCommerce control panel, manage Form Fields in Settings > Advanced > Account sign up form. You'll be building support for Account Signup Fields, not Address Fields. The following field types will be supported in your Postman logic, so make sure to set up one to three custom fields of one or more of these types.

* Pick List
* Radio Buttons
* Date Field
* Text Field

## 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 GraphQL headers preset

Before beginning the following exercise, make sure to run "REST Create Private Token (server-to-server)" to populate `private_storefront_token` on the environment with a valid token.

## Query Custom Form Fields

In order to provide appropriately formatted custom field values for the account, you'll first need to inspect the details of those form fields.

### Step 1: Create the Request

1. **Create** a new "GQL Get Form Fields" 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}
query GetFormFields
{
  site {
    settings {
      formFields {
        customer(
          filters: {isBuiltIn: false}
        ) {
          __typename
          entityId
          label
          sortOrder
          isBuiltIn
          isRequired
          ... on RadioButtonsFormField {
            options {
              entityId
              label
            }
          }
          ... on PicklistFormField {
            options {
              entityId
              label
            }
          }
          ... on DateFormField {
            defaultDate
            minDate
            maxDate
          }
          ... on TextFormField {
            defaultText
            maxLength
          }
        }
      }
    }
  }
}
```

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

### Step 2: Add Tests and Store Values

This query inspects the details of the user-defined customer account registration Form Fields. Specifically, the details of the types `RadioButtonsFormField`, `PicklistFormField`, `DateFormField` and `TextFormField`.

The post-response script you'll set up next will not only verify that at least one custom Form Field exists, but will also store collection variables with appropriate values for the fields that were found, in a format ready for the customer registration mutation you'll configure later.

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 customerFields = pm.response.json().data?.site
    ?.settings?.formFields?.customer;
pm.test('Response includes at least one customer field', () => {
    pm.expect(
        customerFields?.length
    ).to.be.above(0);
});
```

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

```js showLineNumbers={false}
const customerMultipleChoices = [];
const customerDates = [];
const customerTexts = [];
if (customerFields) {
    customerFields.forEach(field => {
        switch (field.__typename) {
            case "PicklistFormField":
            case "RadioButtonsFormField":
                pm.test('Multiple choice field has at least one option', () => {
                    pm.expect(
                        field.options?.length
                    ).to.be.above(0);
                });
                customerMultipleChoices.push({
                    "fieldEntityId": field.entityId,
                    "fieldValueEntityId": field.options[0].entityId,
                });
                break;

            case "DateFormField":
                let date = new Date();
                if (field.minDate) {
                    date = field.minDate;
                } else if (field.defaultDate) {
                    date = field.defaultDate;
                } else if (field.maxDate) {
                    date = field.maxDate;
                }
                customerDates.push({
                    "fieldEntityId": field.entityId,
                    "date": date,
                });
                break;

            case "TextFormField":
                customerTexts.push({
                    "fieldEntityId": field.entityId,
                    "text": "Test Value",
                });
        }
    });
}

pm.collectionVariables.set(
    "customer_multiple_choices",
    JSON.stringify(customerMultipleChoices)
);
pm.collectionVariables.set(
    "customer_dates",
    JSON.stringify(customerDates)
);
pm.collectionVariables.set(
    "customer_texts",
    JSON.stringify(customerTexts)
);
```

This script adds one more test in the case of multi-choice style fields, verifying that at least one option exists.

From here, the script will store three different collection variables with values that will be expected by customer account registration. Which variables contain values will depend on the types of Form Fields you configured in your control panel.

* For multi-choice style fields (Pick List and Radio Button fields), the first available option will be stored.
* For Date fields, the value stored will be the minimum date/time if one is configured. In order of precedence, the value tried will then be the field's default value, any configured maximum date/time, or the current time.
* Any Text fields will have a hard-coded test value stored.

**Send** the request again and **verify** that the variables `customer_multiple_choices`, `customer_dates`, and `customer_texts` are populated on the collection, with appropriate values depending on the types of your fields.

## Register a Customer

### Step 1: Configure New Collection Variables

1. **Add** the following variables to your Postman collection, with appropriate values for the customer account you wish to create.

| Variable            | Value                                                                |
| ------------------- | -------------------------------------------------------------------- |
| `customer_email`    | `{Any email address not already associated with a customer account}` |
| `customer_password` | `{Any password}`                                                     |

These values will be used both for account registration and for login, which is why you're storing them in a persistent location.

### Step 2: Create the Request

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Register Customer".
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 RegisterCustomer(
  $firstName: String!,
  $lastName: String!,
  $email: String!,
  $password: String!,
  $multipleChoices: [MultipleChoiceFormFieldInput!],
  $dates: [DateFormFieldInput!],
  $texts: [TextFormFieldInput!]
) {
  customer {
    registerCustomer(
      input: {
        firstName: $firstName,
        lastName: $lastName,
        email: $email,
        password: $password,
        formFields: {
          multipleChoices: $multipleChoices,
          dates: $dates,
          texts: $texts
        }
      }
    ) {
      customer {
        entityId
      }
      errors {
        ... on EmailAlreadyInUseError {
            message
        }
        ... on AccountCreationDisabledError {
            message
        }
        ... on CustomerRegistrationError {
            message
        }
        ... on ValidationError {
            message
        }
      }
    }
  }
}
```

4. **Enter** the following in the GraphQL Variables section of the Body tab. Feel free to change the customer name details. The values previously prepared when customer Form Fields were queried will be passed in for the various field entries; any value types for which you do not have corresponding fields will simply receive an empty array.

```json showLineNumbers={false}
{
    "firstName": "John",
    "lastName": "Doe",
    "email": "{{customer_email}}",
    "password": "{{customer_password}}",
    "multipleChoices": {{customer_multiple_choices}},
    "dates": {{customer_dates}},
    "texts": {{customer_texts}}
}
```

Don't send the request just yet, as you'll want to have post-response scripts in place before registering the new account.

### Step 3: Add Tests and Store Values

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 customer = pm.response.json().data?.customer?.registerCustomer?.customer;
pm.test('Response includes a customer ID', () => {
    pm.expect(
        customer?.entityId
    ).to.be.a('number');
});
```

2. **Send** the request and **verify** that tests are successful.
3. In your BigCommerce control panel, **navigate** to the store's customers and **verify** the details of the new customer record have been set correctly, including for custom fields.

## Authenticate Customer

In this request, you'll use the `login` mutation to authenticate the newly created customer account, using the same email and password you first used to register the customer.

In addition to verifying the user credentials, this request will also capture the Customer Access Token for use in the `X-Bc-Customer-Access-Token` header for the subsequent customer requests.

### Step 1: Create the Request

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

```graphql showLineNumbers={false}
mutation Login(
  $email: String!,
  $password: String!
) {
  login(
    email: $email,
    password: $password
  ) {
    result
    customer {
      entityId
      firstName
      lastName
    }
    customerAccessToken {
        value
        expiresAt
    }
  }
}
```

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

```json showLineNumbers={false}
{
    "email": "{{customer_email}}",
    "password": "{{customer_password}}"
}
```

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

### 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 result = pm.response.json().data?.login?.result;
pm.test('Login was successful', () => {
    pm.expect(result).to.equal("success");
});

const customer = pm.response.json().data?.login?.customer;
pm.test('Response includes a customer ID', () => {
    pm.expect(
        customer?.entityId
    ).to.be.a('number');
});

const token = pm.response.json().data?.login?.customerAccessToken?.value;
pm.test('Response includes a token', () => {
    pm.expect(
        token
    ).to.be.a('string');
});
```

2. **Send** the request and **verify** that all tests succeed.
3. **Edit** your collection variables and change `customer_password` to a different value, then **re-send** the request. **Verify** that tests fail with these incorrect credentials, and observe the response.
4. **Reset** the `customer_password` collection variable to the correct password.

### Step 3: Store Values

To finish out this request, you'll capture both the "logged-in" customer's ID and the unique Customer Access Token in collection variables.

1. **Add** the following after the existing "Post-response" code in the Scripts tab.

```java showLineNumbers={false}
pm.collectionVariables.unset("customer_id");
pm.collectionVariables.set("customer_id", customer?.entityId);

pm.collectionVariables.unset("customer_access_token");
pm.collectionVariables.set("customer_access_token", token);
```

2. **Send** the request and **verify** that the `customer_id` and `customer_access_token` variables are set on your collection.

## Add a Customer Address

Customer addresses have the same support for custom Form Fields that customer accounts do, so you could use the same workflow we have already seen to discover and then populate these fields when adding a new address. For simplicity's sake, we'll skip these custom Form Fields for addresses, providing only built-in field values. In order for this request to work correctly, you'll need to make sure you **have no Form Fields configured for addresses that are required**.

You've captured a unique Customer Access Token identifying the "logged-in" customer in the previous request, and that context will be provided not in the body of the mutation or its variables, but in the `X-Bc-Customer-Access-Token` header.

### Step 1: Create the Request

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Add Customer 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. In the Headers, **add** a new header as follows.

| Header                     | Value                       |
| -------------------------- | --------------------------- |
| X-Bc-Customer-Access-Token | `{{customer_access_token}}` |

4. **Enter** the following query:

```graphql showLineNumbers={false}
mutation AddCustomerAddress(
  $firstName: String!,
  $lastName: String!,
  $address1: String!,
  $city: String!,
  $countryCode: String!,
  $stateOrProvince: String,
  $postalCode: String
) {
  customer {
    addCustomerAddress(
      input: {
        firstName: $firstName,
        lastName: $lastName,
        address1: $address1,
        city: $city,
        countryCode: $countryCode,
        stateOrProvince: $stateOrProvince,
        postalCode: $postalCode
      }
    ) {
      address {
        entityId
      }
      errors {
          ... on CustomerNotLoggedInError {
              message
          }
          ... on CustomerAddressCreationError {
              message
          }
          ... on ValidationError {
              message
          }
      }
    }
  }
}
```

5. **Enter** the following in the GraphQL Variables section of the Body tab. Feel free to change the address details as you please.

```json showLineNumbers={false}
{
    "firstName": "John",
    "lastName": "Doe",
    "address1": "123 Park Central East",
    "city": "Austin",
    "countryCode": "US",
    "stateOrProvince": "Texas",
    "postalCode": "78726"
}
```

### 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 address = pm.response.json().data?.customer?.addCustomerAddress?.address;
pm.test('Response includes an address ID', () => {
    pm.expect(
        address?.entityId
    ).to.be.a('number');
});
```

2. **Send** the request and **verify** that all tests succeed.
3. In your BigCommerce control panel, **navigate** to the matching customer account record and **verify** that the new address exists in the customer's address book.

## Fetch Customer Details

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Get Customer."
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. Make sure Headers includes X-Bc-Customer-Access-Token.
3. **Enter** the following query:

```graphql showLineNumbers={false}
query GetCustomer {
    customer {
        entityId
        customerGroupId
        email
        firstName
        lastName
        addresses {
            edges {
                node {
                    firstName
                    lastName
                    address1
                    city
                    countryCode
                    stateOrProvince
                    phone
                    postalCode
                }
            }
        }
    }
}
```

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

## OPTIONAL: Request Password Reset

The following requests will simulate the workflow required to allow a user to initiate a password reset request, then complete the password reset using the token provided in the resulting email.

If you wish to try out this workflow, this will require **the ability to receive the password reset email sent by BigCommerce** and retrieve the token provided in the reset link it contains.

You should therefore make sure that email address used previously to create the customer account is one for which you can successfully receive email. If needed, **update the `customer_email` collection variable and re-run the "GQL Register Customer" and "GQL Customer Login" requests** to capture the ID of a customer account with a valid email.

### Step 1: Create the Request

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Request Password Reset".
2. **Set** the same configuration that was used for the previous request, including the HTTP method, URL, Authorization, Headers (minus the "X-Bc-Customer-Access-Token" header), Body type and "Disable cookie jar" setting.
3. **Enter** the following query:

```graphql showLineNumbers={false}
mutation ChangePassword(
  $email: String!,
  $redirectPath: String
) {
  customer {
    requestResetPassword(
      input: {
        email: $email,
        path: $redirectPath
      }
    ) {
      errors {
        ... on ValidationError {
          path
          message
        }
      }
    }
  }
}
```

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

```json showLineNumbers={false}
{
    "email": "{{customer_email}}",
    "redirectPath": "/my-password-reset"
}
```

Note that you're entering a purely arbitrary URL path to serve as the "password reset" destination on a hypothetical storefront. Your own application would be in control of what URL route is appropriate for customers to be directed to.

### 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")
});
pm.test('200 response received', () => {
    pm.response.to.have.status(200);
});

const errors = pm.response.json().data?.customer?.requestResetPassword?.errors;
pm.test('No validation errors', () => {
    pm.expect(errors?.length).to.equal(0);
});
```

2. **Send** the request and **verify** that all tests succeed.

### Step 3: Verify Email Receipt

If your previous request succeeded, this should have initiated a reset email to the address associated with the customer account. The token needed for the password reset request can be obtained *only* from this email.

1. **Access** the inbox for the email address associated with the customer account using the appropriate email application.
2. **Open** the "Password Change Request" email that was received from your store.

This email should contain a link to a URL like the following:

`https://{store-domain}/my-password-reset?c={customer-ID}&t=**{token}**`

Note the URL path `/my-password-reset`, which was designated by the `requestPasswordReset` mutation itself. The part of the URL you are now concerned with is the `{token}` value passed to the `t` querystring parameter.

3. **Copy** the token value from the URL contained in the password reset email.
4. In Postman, **edit** your collection and **add** the variable `password_reset_token` with the token value you copied.

## OPTIONAL: Reset Password

In this request, you'll complete a customer password reset using the token value you previously captured.

### Step 1: Enter a New Password Value

The intent is to update the customer account password with a *new* value, so you'll need to start by providing this new value to Postman.

1. **Edit** your collection and **change** the value of the `customer_password` variable to a different password string.

### Step 2: Create the Request

1. **Create** a new HTTP request and **save** it in your collection with the name "GQL Reset Password"
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 ChangePassword(
  $customerId: Int!,
  $token: String!,
  $password: String!
) {
  customer {
    resetPassword(
      input: {
        customerEntityId: $customerId,
        token: $token,
        newPassword: $password
      }
    ) {
      errors {
        ... on ValidationError {
          path
          message
        }
      }
    }
  }
}
```

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

```json showLineNumbers={false}
{
    "customerId": {{customer_id}},
    "token": "{{password_reset_token}}",
    "password": "{{customer_password}}"
}
```

### Step 3: 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")
});
pm.test('200 response received', () => {
    pm.response.to.have.status(200);
});

const errors = pm.response.json().data?.customer?.resetPassword?.errors;
pm.test('No validation errors', () => {
    pm.expect(errors?.length).to.equal(0);
});
```

2. **Send** the request and **verify** that all tests succeed.

### Step 4: Re-Authenticate

1. **Re-send** the "GQL Customer Login" request to re-authenticate using the new password.
2. **Verify** that all tests once again succeed.