> 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 - Postman Company Management Workflow

Plan: B2B Developer

Lesson 9 of 18 · 45 min

## Introduction

In the previous lab, you created a workflow to simulate a customer login. Now you'll use that authentication process as you build out common storefront tasks for managing addresses and customers.

### Prerequisites

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

### In this lab, you will:

* Create API requests to handle company address and user management
* Implement Postman scripts to automate values used in API requests

## Postman Recap

As a reminder, the "Admin Login" and "User Company" requests you created in the previous lab should authenticate the Admin user (per the `admin` email\_and `admin` password\_variables set on your collection) and store the following environment variables, which will be needed for various future requests:

* `b2b_storefront_token`
* `b2b_logged_in_email`
* `b2b_logged_in_id`
* `bc_logged_in_id`
* `b2b_logged_in_company_id`

If you don't currently have values set for these environment variables, or if at any time you find your current authentication token has expired, re-run the "Admin Login" and "User Company" requests.

## Step 1: Get Company Addresses

Like most of the requests you'll practice with from here out, the following request to fetch a list of addresses relies on the user context of the authentication token obtained from `login` to return only the address records relevant to the user's company.

1. **Create** a new HTTP request and **save** it to your collection with the name "Get Addresses."
2. **Set** the same configuration that was used for the previous requests, including the HTTP method, URL, Auth Type, Headers (using your previously created "GraphQL" preset), and Body type.
3. **Enter** the following query.

```graphql showLineNumbers={false}
query GetAddresses(
    $companyId: Int!,
    $limit: Int,
    $after: String
) {
    addresses(
        companyId: $companyId,
        first: $limit,
        after: $after
    ) {
        pageInfo {
            hasNextPage
            hasPreviousPage
            startCursor
            endCursor
        }
        totalCount
        edges {
            node {
                id
                firstName
                lastName
                isShipping
                isDefaultShipping
                isBilling
                isDefaultBilling
                addressLine1
                addressLine2
                city
                state
                stateCode
                country
                countryCode
                zipCode
                phoneNumber
                label
            }
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables panel.

```json showLineNumbers={false}
{
    "companyId": {{b2b_logged_in_company_id}},
    "limit": 5,
    "after": null
}
```

The GraphQL arguments and variables are configured to easily facilitate pagination; just replace the value of "after" with a valid `endCursor` from a previous response.

5. In the Scripts tab, **enter** the following "Post-response" code.

```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?.addresses;
pm.test('Total count includes at least one address', () => {
    pm.expect(
        result?.totalCount
    ).to.be.greaterThan(0);
});

let firstAddress = null;
if (Array.isArray(result?.edges)) {
    firstAddress = result.edges[0]?.node;
}
pm.test('Response includes at least one address with an ID', () => {
    pm.expect(
        firstAddress?.id
    ).to.be.a('string');
});
```

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

You should see at least one address represented in the response: the initial address you configured in your initial "Create Company" request.

## Step 2: Create an Address

1. **Create** a new HTTP request and **save** it to your collection with the name "Create Shipping Address."
2. **Set** the same configuration that was used for the previous requests, including the HTTP method, URL, Auth Type, Headers (using your previously created "GraphQL" preset), and Body type.
3. **Enter** the following query.

```graphql showLineNumbers={false}
mutation CreateAddress(
    $companyId: Int!,
    $firstName: String!,
    $lastName: String!,
    $addressLine1: String!,
    $addressLine2: String,
    $country: String!,
    $countryCode: String!,
    $state: String!,
    $stateCode: String,
    $city: String!,
    $zipCode: String!,
    $phoneNumber: String,
    $isShipping: Int,
    $isBilling: Int,
    $isDefaultShipping: Int,
    $isDefaultBilling: Int,
    $label: String,
    $company: String
) {
    addressCreate(
        addressData: {
            companyId: $companyId,
            firstName: $firstName,
            lastName: $lastName,
            addressLine1: $addressLine1,
            addressLine2: $addressLine2,
            country: $country,
            countryCode: $countryCode,
            state: $state,
            stateCode: $stateCode,
            city: $city,
            zipCode: $zipCode,
            phoneNumber: $phoneNumber,
            isShipping: $isShipping,
            isBilling: $isBilling,
            isDefaultShipping: $isDefaultShipping,
            isDefaultBilling: $isDefaultBilling,
            label: $label,
            company: $company
        }
    ) {
        address {
            id
            label
            isShipping
            isBilling
            isDefaultShipping
            isDefaultBilling
        }
    }
}
```

4. **Enter** the following in the GraphQL Variables panel.

```json showLineNumbers={false}
{
    "companyId": {{b2b_logged_in_company_id}},
    "firstName": "Jack",
    "lastName": "Doe",
    "addressLine1": "456 Downtown Lane",
    "addressLine2": "Ste 1",
    "country": "United States",
    "countryCode": "US",
    "state": "Texas",
    "stateCode": "TX",
    "city": "Austin",
    "zipCode": "78726",
    "phoneNumber": "777-888-9999",
    "isShipping": 1,
    "isBilling": 0,
    "isDefaultShipping": 1,
    "isDefaultBilling": 0,
    "label": "Main Shipping",
    "company": "John's Widgets"
}
```

5. In the Scripts tab, **enter** the following "Post-response" code.

```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?.addressCreate?.address;
pm.test('Response includes address with ID', () => {
    pm.expect(
        address?.id
    ).to.be.a('string');
});

pm.collectionVariables.unset('address_id');
pm.collectionVariables.set('address_id', address?.id);
```

This script captures the newly created address's ID in the collection variable `address_id`, which will be used in the next requests to apply them automatically to the most recently created address. (Simply update the collection variable manually to manage a different address.)

6. **Send** the request, **verify** that all tests succeed, and **verify** that the `address_id` variable is set on your collection.
7. **Re-run** the "Get Addresses" query to observe the newly created address included in the results.

> **Info**
>
> Try out paginating the "Get Addresses" request by setting "limit" to a low enough value (1, if your company only has two addresses) and updating the "after" variable with the `endCursor` of the first page response.

You can view the company in your B2B Edition admin, or by logging into your storefront with the Admin user's credentials, to observe that the company now contains the new address, which is set as the default shipping address.

## Step 3: Update and Delete an Address

1. **Create** a new HTTP request and **save** it to your collection with the name "Update Address."
2. **Set** the same configuration that was used for the previous requests, including the HTTP method, URL, Auth Type, Headers (using your previously created "GraphQL" preset), and Body type.
3. **Enter** the following query.

```graphql showLineNumbers={false}
mutation UpdateAddress(
    $companyId: Int!,
    $addressId: Int!,
    $firstName: String!,
    $lastName: String!,
    $addressLine1: String!,
    $addressLine2: String,
    $country: String!,
    $countryCode: String!,
    $state: String!,
    $stateCode: String,
    $city: String!,
    $zipCode: String!,
    $phoneNumber: String,
    $isShipping: Int,
    $isBilling: Int,
    $isDefaultShipping: Int,
    $isDefaultBilling: Int,
    $label: String,
    $company: String
) {
    addressUpdate(
        addressData: {
            companyId: $companyId,
            addressId: $addressId,
            firstName: $firstName,
            lastName: $lastName,
            addressLine1: $addressLine1,
            addressLine2: $addressLine2,
            country: $country,
            countryCode: $countryCode,
            state: $state,
            stateCode: $stateCode,
            city: $city,
            zipCode: $zipCode,
            phoneNumber: $phoneNumber,
            isShipping: $isShipping,
            isBilling: $isBilling,
            isDefaultShipping: $isDefaultShipping,
            isDefaultBilling: $isDefaultBilling,
            label: $label,
            company: $company
        }
    ) {
        address {
            id
            label
            isShipping
            isBilling
            isDefaultShipping
            isDefaultBilling
        }
    }
}
```

4. **Enter** the following initial values in the GraphQL Variables panel.

```json showLineNumbers={false}
{
    "companyId": {{b2b_logged_in_company_id}},
    "addressId": {{address_id}},
    "firstName": "Jack",
    "lastName": "Doe",
    "addressLine1": "456 Downtown Lane",
    "addressLine2": "Ste 1",
    "country": "United States",
    "countryCode": "US",
    "state": "Texas",
    "stateCode": "TX",
    "city": "Austin",
    "zipCode": "78726",
    "phoneNumber": "777-888-9999",
    "isShipping": 1,
    "isBilling": 0,
    "isDefaultShipping": 1,
    "isDefaultBilling": 0,
    "label": "Main Shipping",
    "company": "John's Widgets"
}
```

5. **Update** the GraphQL Variables panel with several changed values to test the process of updating the recently created address.
6. In the Scripts tab, **enter** the following "Post-response" code.

```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?.addressUpdate?.address;
pm.test('Response includes address with ID', () => {
    pm.expect(
        address?.id
    ).to.be.a('string');
});
```

7. **Send** the request and **verify** that all tests succeed.
8. Use the "Get Addresses" query, or view the company details in the storefront or control panel, to **verify** the updated details of the address.

Now let's also practice deleting an address.

9. **Create** a new HTTP request and **save** it to your collection with the name "Delete Address."
10. **Set** the same configuration that was used for the previous requests, including the HTTP method, URL, Headers (using your previously created "GraphQL" preset), and Body type.
11. In the Authorization tab, **verify** that **Auth Type** is set to "Inherit auth from parent."
12. **Enter** the following query.

```graphql showLineNumbers={false}
mutation DeleteAddress(
    $companyId: Int!,
    $addressId: Int!
) {
    addressDelete(
        companyId: $companyId,
        addressId: $addressId
    ) {
        message
    }
}
```

13. **Enter** the following in the GraphQL Variables panel.

```json showLineNumbers={false}
{
    "companyId": {{b2b_logged_in_company_id}},
    "addressId": {{address_id}}
}
```

14. In the Scripts tab, **enter** the following "Post-response" code.

```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 message = pm.response.json().data?.addressDelete?.message
pm.test('Operation was successful', () => {
    pm.expect(
        message
    ).to.eq('Success');
});

pm.collectionVariables.unset('address_id');
```

15. **Send** the request and **verify** that all tests succeed.
16. Use the "Get Addresses" query, or view the company details in the storefront or control panel, to **verify** the address was deleted.

You may choose to use the "Create Address" request again to restore the address or create multiple others.

## Step 4: Get Users

1. **Create** a new HTTP request and **save** it to your collection with the name "Get Users."
2. **Set** the same configuration that was used for the previous requests, including the HTTP method, URL, Auth Type, Headers (using your previously created "GraphQL" preset), and Body type.
3. **Enter** the following query.

```graphql showLineNumbers={false}
query GetUsers(
    $companyId: Int!,
    $limit: Int,
    $after: String
) {
    users(
        companyId: $companyId,
        first: $limit,
        after: $after
    ) {
        pageInfo {
            hasNextPage
            hasPreviousPage
            startCursor
            endCursor
        }
        totalCount
        edges {
            node {
                id
                bcId
                firstName
                lastName
                email
                phone
                role
                companyRoleId
                companyRoleName
            }
        }
    }
}
```

4. **Enter** the following initial values in the GraphQL Variables panel.

```json showLineNumbers={false}
{
    "companyId": {{b2b_logged_in_company_id}},
    "limit": 5,
    "after": null
}
```

5. In the Scripts tab, **enter** the following "Post-response" code.

```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?.users;
pm.test('Total count includes at least one user', () => {
    pm.expect(
        result?.totalCount
    ).to.be.greaterThan(0);
});

let firstUser = null;
if (Array.isArray(result?.edges)) {
    firstUser = result.edges[0]?.node;
}
pm.test('Response includes at least one user with an ID', () => {
    pm.expect(
        firstUser?.id
    ).to.be.a('string');
});
```

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

Like the "Get Addresses" query, this query is constrained to the context of the current user's authentication token. Your company should have at least one user: the Admin user that was initially associated with it.

## Step 5: Validate Junior Buyer Role and Email

In the next step, you'll create a new user with the "Junior Buyer" role, simulating this task from the context of an Admin storefront user. Before doing so, we'll take two steps to prepare:

* Fetch the ID of the "Junior Buyer" role.
* Check whether the email address of the new user is valid.

Junior Buyer is one of the pre-built roles that is assigned a hard-coded role ID (0). While you could create your Junior Buyer user using *role: 0*, a more forward compatible approach is to use `companyRoleId`. This approach will also support any custom roles you may create.

In order to specify `companyRoleId`, you'll first need to fetch the available company roles and find the record ID for "Junior Buyer."

1. **Create** a new HTTP request and **save** it to your collection with the name "Get User Roles."
2. **Set** the same configuration that was used for the previous requests, including the HTTP method, URL, Auth Type, Headers (using your previously created "GraphQL" preset), and Body type.
3. **Enter** the following query.

```graphql showLineNumbers={false}
query GetUserRoles(
    $companyId: Int!
) {
    companyRoles(
        companyId: $companyId
    ) {
        edges {
            node {
                id
                name
            }
        }
    }
}
```

4. **Enter** the following initial values in the GraphQL Variables panel.

```json showLineNumbers={false}
{
    "companyId": {{b2b_logged_in_company_id}}
}
```

5. In the Scripts tab, **enter** the following "Post-response" code.

```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 roles = pm.response.json().data?.companyRoles?.edges;
pm.test('Response includes roles', () => {
    pm.expect(
        roles?.length
    ).to.be.greaterThan(0);
});

pm.collectionVariables.unset('junior_role_id');
if (Array.isArray(roles)) {
    const juniorRole = roles.find(role => role?.node?.name === 'Junior Buyer');
    pm.test('Junior role found', () => {
        pm.expect(
            juniorRole?.node?.id
        ).to.be.a('string');
    });

    pm.collectionVariables.set('junior_role_id', parseInt(juniorRole?.node?.id));
}
```

This script searches the results set for the role with the name "Junior Buyer" and captures its ID with the collection variable `junior_role_id`, which can subsequently be used to create the new user.

6. **Send** the request, **verify** that all tests succeed, and **confirm** that the `junior_role_id`variable is set on your collection.

For your second step, you'll validate the new user's email address. To easily facilitate running the `login` mutation for the Junior Buyer user, you'll store the email and password for this user on collection variables, just as you previously did with the Admin user.

7. **Open** the collection and **navigate** to the Variables tab.
8. **Add** the following variables. (Don't forget to save the collection.)

| Variable Name    | Value                                                                           |
| ---------------- | ------------------------------------------------------------------------------- |
| junior\_email    | Your chosen email for a Junior Buyer user (different from the Admin user email) |
| junior\_password | Your chosen password                                                            |

9. **Create** a new HTTP request and **save** it to your collection with the name "Check Junior User Email."
10. **Set** the same configuration that was used for the previous requests, including the HTTP method, URL, Headers (using your previously created "GraphQL" preset), and Body type.
11. In the Authorization tab, **verify** that\*\*\*\*Auth Type is set to "Inherit auth from parent."
12. **Enter** the following query.

```graphql showLineNumbers={false}
query CheckUserEmail(
    $email: String!
) {
    userEmailCheck(
        email: $email
    ) {
        userType
    }
}
```

13. **Enter** the following initial values in the GraphQL Variables panel.

```json showLineNumbers={false}
{
    "email": "{{junior_email}}"
}
```

14. In the Scripts tab, **enter** the following "Post-response" code.

```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 userType = pm.response.json().data?.userEmailCheck?.userType;
pm.test('User type exists', () => {
    pm.expect(
        userType
    ).to.be.a('number');
});
pm.test('Email is valid for new user', () => {
    pm.expect(
        [1, 2]
    ).to.include(userType);
});
```

The above script will ensure the response will only succeed on all tests if the user type is 1 or 2 (indicating the email address doesn't match an existing user or matches a user not associated with a company).

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

## Step 6: Create the Junior Buyer User

Having captured the ID of the "Junior Buyer" role and validated the intended email address, you can now proceed with creating the user.

1. **Create** a new HTTP request and **save** it to your collection with the name "Create Junior User."
2. **Set** the same configuration that was used for the previous requests, including the HTTP method, URL, Auth Type, Headers (using your previously created "GraphQL" preset), and Body type.
3. **Enter** the following query.

```graphql showLineNumbers={false}
mutation CreateUser(
    $companyId: Int!,
    $email: String!,
    $firstName: String!,
    $lastName: String!,
    $companyRoleId: Int
) {
    userCreate(
        userData: {
            companyId: $companyId,
            email: $email,
            firstName: $firstName,
            lastName: $lastName,
            companyRoleId: $companyRoleId
        }
    ) {
        user {
            id
            firstName
            lastName
            email
            role
            companyRoleId
            companyRoleName
        }
    }
}
```

4. **Enter** the following initial values in the GraphQL Variables panel. (Feel free to change the user details.)

```json showLineNumbers={false}
{
    "companyId": {{b2b_logged_in_company_id}},
    "email": "{{junior_email}}",
    "firstName": "Jack",
    "lastName": "Doe",
    "companyRoleId": {{junior_role_id}}
}
```

5. In the Scripts tab, **enter** the following "Post-response" code.

```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 user = pm.response.json().data?.userCreate?.user;
pm.test('Response includes user with ID', () => {
    pm.expect(
        user?.id
    ).to.be.a('string');
});
```

6. **Send** the request and **verify** that all tests succeed.
7. **Re-run** the "Get Users" request to observe the new Junior Buyer in the response.

## Step 7: Log In as Junior Buyer

With your Junior Buyer user now assigned to your company, you can easily create a "Junior Login" request similar to your original "Admin Login" request, to allow for easily "toggling" your authentication between the two users.

Note, however, that your request to create the Junior Buyer user did not include setting a password. This reflects storefront behavior, where an Admin user can create a new user, but their password will ultimately be set when the user receives and acts on a welcome email.

1. In the BigCommerce control panel, **navigate** to Customers and **select** the new Junior Buyer customer.
2. **Set** the customer's password (make sure it matches the value you have set for `junior_password` in your collection) and **save** the customer.
3. **Duplicate** your "Admin Login" request and **set** the name of the new request to "Junior Buyer Login."
4. In the GraphQL Variables panel of the Body tab, **change** the JSON to the following.

```json showLineNumbers={false}
{
    "storeHash": "{{store_hash}}",
    "email": "{{junior_email}}",
    "password": "{{junior_password}}"
}
```

With the post-response script copied directly from the "Admin Login" request, this request will update the same environment variables, capturing the authentication token and other details when you "log in" as the Junior Buyer.

5. **Send** the request and **verify** that all tests succeed.
6. **Re-run** the "Get Users" request.

With your environment variables updated with an authentication token matching the Junior Buyer user, you should now see a "Permission denied" error in the response, since Junior Buyers do not have permission to view a company's users.

With both an "Admin Login" and "Junior Buyer Login," you can now easily switch between the two users, establishing the user context for any other requests you choose to run. Utilize this capability to observe the effects of different roles/permissions on the GraphQL behavior.

## Taking It Further

Finish out your Users workflow by creating an "Update User" request utilizing the `userUpdate` mutation and a "Delete User" request utilizing the `userDelete` mutation.