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

# Companies and Addresses

Plan: B2B Developer

Lesson 5 of 18 · 30 min

## Introduction

The B2B storefront experience starts with the ability to register and log in with a company account. In this section, we'll look at the core GraphQL workflow supporting company creation, as well as the other component needed for a minimal buying experience: a company address book.

## Company Registration

### The Admin Customer

Creating a B2B company requires an existing customer account to serve as the company's **admin user**. This means the first step in the registration workflow is to create the customer account if it doesn't exist already, using the `customerCreate` mutation.  The customerEmail as well as customerId will be required to use the companyCreate mutation.

#### Example Mutation, Variables, and Response:

#### Mutation

```graphql showLineNumbers={false}
mutation CreateCustomer(
    $storeHash: String!,
    $email: String!,
    $password: String,
    $firstName: String!,
    $lastName: String!,
    $phone: String,
    $channelId: Int
) {
    customerCreate(
        customerData: {
            storeHash: $storeHash,
            email: $email,
            firstName: $firstName,
            lastName: $lastName,
            phone: $phone,
            originChannelId: $channelId,
            channelIds: [$channelId],
            authentication: {
                forcePasswordReset: false,
                newPassword: $password
            }
        }
    ) {
        customer {
            id
            email
        }
    }
}
```

#### Variables

```json showLineNumbers={false}
{
    "storeHash": "aaaaabbbbb",
    "email": "johndoe@example.com",
    "password": "Password123",
    "firstName": "John",
    "lastName": "Doe",
    "phone": "111-222-3333",
    "channelId": 1
}
```

#### Response

```json showLineNumbers={false}
{
    "data": {
        "customerCreate": {
            "customer": {
                "id": 5,
                "email": "johndoe@example.com"
            }
        }
    }
}
```

* The store hash, email, first name, and last name are required.
* If multi-storefront is enabled, specify the BigCommerce `originChannelId` and `channelIds` as an array. `channelIds` specifies the channels in which the customer can operate, which might include multiple channels if your store configuration allows this.
* The `authentication` field can be used to set the new customer's password (`newPassword`). This should be paired with setting `forcePasswordReset` to FALSE to ensure the customer is not forced to reset their password on their first login.

Once a BigCommerce customer account exists, you can proceed with the registration of a company.

> **Info**
>
> The `registerCustomer` mutation in the BigCommerce GraphQL Storefront API can be used instead for this operation. Review the [Authentication](/developer/learn/courses/graphql-storefront-api/auth/authentication) lesson for details on the credentials required with this API.

### Creating the Company

The `companyCreate` mutation is an anonymous operation; no existing authentication token is required for the request; however customerEmail as well as customerId are now required.

#### Example Mutation, Variables, and Response:

#### Mutation

```graphql showLineNumbers={false}
mutation CreateCompany(
    $storeHash: String!,
    $customerId: String!,
    $customerEmail: String!,
    $companyName: String!,
    $companyEmail: String,
    $addressLine1: String!,
    $city: String!,
    $country: String!,
    $state: String!,
    $zipCode: String!
) {
    companyCreate(
        companyData: {
            storeHash: $storeHash,
            customerId: $customerId,
            customerEmail: $customerEmail,
            companyName: $companyName,
            companyEmail: $companyEmail,
            addressLine1: $addressLine1,
            city: $city,
            country: $country,
            state: $state,
            zipCode: $zipCode
        }
    ) {
        company {
            id
            companyName
        }
    }
}
```

#### Variables

```json showLineNumbers={false}
{
    "storeHash": "aaaaabbbbb",
    "customerId": "27",
    "companyName": "John's Widgets",
    "companyEmail": "johnswidgets@example.com",
    "addressLine1": "123 Park Central",
    "city": "Austin",
    "country": "United States",
    "state": "Texas",
    "zipCode": "78726"
}
```

#### Response

```json showLineNumbers={false}
{
    "data": {
        "companyCreate": {
            "company": {
                "id": "1112233",
                "companyName": "John's Widgets"
            }
        }
    }
}
```

* The store hash, a valid BigCommerce customer ID, and the basic address fields are required.
* The `companyEmail` field does *not* need to match the email address of the customer corresponding with `customerId`. This will be the email associated directly with the company record, not with an individual user.
* All companies created with this mutation will initially be in the "Pending" state.

The "Default customer group" configured in your B2B Edition settings, if any, will determine the customer group that is assigned to a company registered via GraphQL. The customer group set on the existing Admin customer will automatically be updated to reflect this.

> **Info**
>
> If your B2B Edition has not been upgraded with the Independent Company feature, a new customer group specific to the company will instead be created.

> **Info**
>
> The `registerCompany` mutation in the BigCommerce GraphQL Storefront API can be used instead for this operation. Unlike `companyCreate`, `registerCompany` requires a logged-in customer context. Review the [Authentication](/developer/learn/courses/graphql-storefront-api/auth/authentication) lesson for details on the credentials required with this API.

### Logging In

As we've seen, the `login` mutation is used with a store hash and an existing customer's email and password. This mutation is key for performing many other queries and mutations, as it is used to retrieve a value used as the `Bearer` authentication token in subsequent requests.

* Note that both the B2B user ID (`id`) and the BigCommerce customer ID (`bcId`) can be queried on the `user` object in the response.
* Your application should retain not only the `token` from the response, for authenticating further requests, but also *user.id*, since the user's ID is required as an argument for a number of queries as well. The BigCommerce customer ID, which is available in *user.bcId*, might also be required for some queries.
* The `login` mutation will succeed even for a customer that is not associated with a company, but the `user` object will be empty.
* Login will also be successful for a customer associated with a company that is still in "Pending" status. However, most B2B operations performed with the resulting token will fail until the company is approved.

An easy way to verify that the token you've received from `login` is still valid, verify you are using the token correctly, and inspect the details of the user's associated company, is to use the `userCompany` query, passing the corresponding user ID in addition to including the appropriate Authorization header.

#### Example Request:

```graphql showLineNumbers={false}
query GetUserCompany(
    $userId: Int!
) {
    userCompany(
        userId: $userId
    ) {
        id
        companyName
        companyStatus
        addressLine1
        addressLine2
        city
        state
        zipCode
        country
        customerGroupId
    }
}
```

> **Info**
>
> `id` in this context is the ID of the company. Like the user ID, this is often an important value to retain for use in the arguments of other queries.

The possible values of `companyStatus` are:

* **0:** Pending
* **1:** Approved
* **2:** Rejected
* **3:** Inactive

## Managing Addresses

As seen above, you must provide an initial address when creating a company. This will become the first address in the company's address book, allowed for both shipping and billing.

### Creating New Addresses

Add new addresses with the `addressCreate` mutation.

> **Info**
>
> `addressCreate` is available only when the user associated with the Bearer token has the Admin role or a custom role with the "Addresses - Create, edit, delete" permission.

#### Example Request:

```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
        }
    }
}
```

* Note that `companyId` is a required argument.
* Addresses can be allowed for Shipping, Billing, or both. Use the `isShipping` and `isBilling` fields to indicate this.
* You can also use the `isDefaultShipping` and `isDefaultBilling` fields to indicate the new address should be the default Shipping or Billing address, respectively. Any newly created address with one or both of these set will override an address that was previously set as default.
* The `company` field is optional and is only for the context of the address. (It may or may not match the name of the B2B company.)

## Limited Example Variables:

```json showLineNumbers={false}
{
    ...
    "isShipping": 1,
    "isBilling": 0,
    "isDefaultShipping": 1,
    "isDefaultBilling": 0,
    "label": "Main Shipping Address"
}
```

### Fetching the Company's Addresses

Fetch the details of the addresses belonging to the user's company with the `addresses` query or (if you know the ID of a specific address) the `address` query.

> **Info**
>
> `addresses` and `address` are available for any built-in user role or for custom roles with the "Addresses - View" permission.

#### Example Query and Response:

#### Query

```graphql showLineNumbers={false}
query GetAddresses(
    $companyId: Int!
) {
    addresses(
        companyId: $companyId
    ) {
        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
            }
        }
    }
}
```

#### Response

```json showLineNumbers={false}
{
    "data": {
        "addresses": {
            "pageInfo": {
                "hasNextPage": true,
                "hasPreviousPage": false,
                "startCursor": "YXJy...",
                "endCursor": "YXJy..."
            },
            "totalCount": 12,
            "edges": [
                {
                    "node": {
                        "id": "11122233",
                        "firstName": "John",
                        "lastName": "Doe",
                        "isShipping": 1,
                        "isDefaultShipping": 0,
                        "isBilling": 1,
                        "isDefaultBilling": 0,
                        "addressLine1": "123 Park Central",
                        "addressLine2": "Ste 3",
                        "city": "Austin",
                        "state": "Texas",
                        "stateCode": "TX",
                        "country": "United States",
                        "countryCode": "US",
                        "zipCode": "78726",
                        "phoneNumber": "111-222-3333",
                        "label": "Main Billing Address"
                    }
                },
                ...
            ]
        }
    }
}
```

* `addresses` supports the typical pagination arguments (`offset`, `before`, `after`, `first`, `last`)
* `addresses` can also be filtered w\_addresses\_ith arguments matching the exact values of most address fields (for example, `firstName`, `country`, or `label`).

The `address` query returns the same GraphQL type as each node returned from `addresses`, so all the same fields can be queried.

#### Example Request:

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

### Other Address Management Operations

Updating and deleting company addresses is straightforward, using the `addressUpdate` and `addressDelete` mutations.

> **Info**
>
> `addressUpdate` and `addressDelete` are available only when the user associated with the Bearer token has the Admin role or a custom role with the "Addresses - Create, edit, delete" permission.

#### Example Update Request:

```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
        }
    }
}
```

#### Example Delete Request:

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

#### Example Delete Response:

```json showLineNumbers={false}
{
    "data": {
        "addressDelete": {
            "message": "Success"
        }
    }
}
```