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.

Example Mutation, Variables, and Response:

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

Creating the Company

The companyCreate mutation is an anonymous operation; no existing authentication token is required for the request.

Example Mutation, Variables, and Response:

mutation CreateCompany(
$storeHash: String!,
$customerId: String!,
$companyName: String!,
$companyEmail: String,
$addressLine1: String!,
$city: String!,
$country: String!,
$state: String!,
$zipCode: String!
) {
companyCreate(
companyData: {
storeHash: $storeHash,
customerId: $customerId,
companyName: $companyName,
companyEmail: $companyEmail,
addressLine1: $addressLine1,
city: $city,
country: $country,
state: $state,
zipCode: $zipCode
}
) {
company {
id
companyName
}
}
}
  • 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.

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.

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.

Example Mutation, and Response:

mutation LogIn(
$storeHash: String!,
$email: String!,
$password: String!
) {
login(
loginData: {
storeHash: $storeHash,
email: $email,
password: $password
}
) {
result {
token
user {
id
bcId
firstName
lastName
email
}
}
}
}
  • 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:

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

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.

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:

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:

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

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 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
}
}
}
}
  • 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:

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.

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:

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:

mutation DeleteAddress(
$companyId: Int!,
$addressId: Int!
) {
addressDelete(
companyId: $companyId,
addressId: $addressId
) {
message
}
}

Example Delete Response:

{
"data": {
"addressDelete": {
"message": "Success"
}
}
}