This is the early access documentation preview for Custom Views. This documentation might not be in sync with our official documentation.
Customers overview
Overview of the concepts related to customers purchasing products offered in your Composable Commerce Project.
A Customer is a person (uniquely identified by an email address) purchasing Products. For this, the Carts and Orders containing the Products are associated to one Customer. Furthermore, Customers can provide Reviews for Products.
Especially in B2B scenarios, Products are often purchased by individuals representing a business or a department of a business. Composable Commerce supports these scenarios with Business Units for Companies and their Divisions.
If your Project is structured with Stores, you can manage Customers that can purchase Products across all Stores or in particular Stores only. Furthermore, Stores allow you to offer Products for customer-specific prices.
Customer uniqueness
In commercetools Composable Commerce, customers are identified by their email address that must be unique across the Project. Emails are treated as case-insensitive in some API methods. You can have Customers globally in the Project or only for specific Stores.
Email case-insensitivity
The API preserves letter case when storing a customer's email. However, during the following operations, email addresses are treated as case-insensitive:
For example: if a customer signs up with Email@example.com
...
- Authenticating with
email@example.com
orEMAIL@example.com
succeeds - Sign-up attempts with
email@example.com
orEMAIL@example.com
fail unless Stores are in use - Generating a password reset token with
email@example.com
orEMAIL@example.com
succeeds
To perform a case-insensitive query for emails, convert the given email address to lowercase and use the additional query field lowercaseEmail.
Global versus Store-specific Customers
In Composable Commerce, Customers can either be global or Store-specific.
Global Customers are unique across a Project. Store-specific Customers are unique in a specific Store in your Project. That means, any Customer signed up for a specific Store can sign up on another Store using the same email address. Signing up with the same email address as a global Customer would fail though.
For example, if you do the following:
- Register
email@example.com
as a global customer. - Try to register
email@example.com
in a specific Store.
The second registration fails. Similarly, if you register email@example.com
in a Store in a Project, then attempt to register email@example.com
globally, the second attempt to register fails.
If you create a Customer in a Store their email is only unique to the Store. You can register the same customer using the same email in another store in the same Project. For example, if you do the following:
- Register
email@example.com
in a Store. - Register
email@example.com
in a different Store.
The second registration succeeds. However, if you try to register the same customer globally, the registration fails.
We recommend that you decide whether or not to create Customers on a per-store basis or globally as a part of your initial Project configuration.
Due to this, global and Store-specific Customers use two different authorization flows. For more information, see:
Customer authentication (sign-in)
Customer authentication endpoints differentiate between global versus store-specific Customers. To authenticate a global Customer not associated to a Store, use the authenticate a Customer endpoint. For Store-specific Customers, use the authenticate a Store-specific Customer endpoint.
During the sign-in process, Customers may be assigned resources created prior to the sign-in. With anonymousCart
, a single anonymous Cart can be assigned. With anonymousId
, all Carts, Orders, ShoppingLists and Payments with the same anonymousId
can be assigned to the Customer. If both anonymousCart
and anonymousId
are defined, the anonymous Cart must have the same anonymousId
assigned.
Customers can have one or more Carts assigned from an earlier session. Therefore, Cart assignment can happen in one of two ways:
- If the Customer does not have a Cart yet, or the value of AnonymousCartSignInMode is set to
UseAsNewActiveCustomerCart
, then the anonymous Cart becomes the Customer's Cart. - If the Customer already has one or more Carts and the value of AnonymousCartSignInMode is set to
MergeWithExistingCustomerCart
, then the content of the anonymous Cart will be copied to the Customer's least-recently modified active Cart. This process is referred to as cart merge and results in a specific set of changes for both Carts.
Upon successfully signing-in a Customer, a CustomerSignInResult is returned. If the CustomerSignInResult contains a Cart, the Cart is recalculated to have up-to-date prices, taxes, and discounts, line items.
Cart merge during sign-in
If a Customer is assigned an anonymous Cart during sign-in, but already has pre-existing Carts from a different session, a cart merge is executed. This only applies when the default MergeWithExistingCustomerCart
sign in mode is used. During a cart merge, the following updates apply:
- The CartState of the anonymous Cart updates to
Merged
while the customer's Cart remains theActive
Cart. - If the active Cart has a
shippingAddress
set, the anonymous Cart'sshippingAddress
is updated to match. However, if the active Cart does not have ashippingAddress
set, the anonymous Cart's Line Items are not added to the active Cart. - If a Line Item or Custom Line Item in the anonymous Cart matches an existing item in the active Cart, the highest given quantity is used as the new quantity. However, if either of the Line Items has
ExternalPrice
orExternalTotal
price mode, then both Line Items are added to the active Cart. - For matching Line Items, the ItemShippingDetails are copied from the Line Item with the higher quantity.
- If the
itemShippingAddresses
fields are different on the two Carts, then both sets of addresses are assigned to the active Cart.
Note, that it is not possible to merge Carts that differ in their currency or Store set during creation of the Cart.
Customer email verification
Email verification follows the same set of steps for global as well as Store-specific Customers. For global customers, use the general Customer endpoints. For Store-specific Customers, use the Customer in Store endpoints.
To verify a Customer's email, do the following:
- Send an email token embedded in a link to the Customer.
- For global Customers, use the Create email token for Customer endpoint.
- For Store-specific Customers, use Create email token for Customer in Store endpoint.
- When the Customer clicks the link, optionally retrieve the Customer by the email token.
- For global Customers, use the Get Customer by email token endpoint.
- For Store-specific Customers, use the Get Customer in Store by email token endpoint.
- Verify the Customer's email. This sets the Customer's
isEmailVerified
field totrue
.- For global Customers, use the Verify email of Customer endpoint.
- For Store-specific Customers, use the Verify email of Customer in Store endpoint.
- These methods are also provided on the My Customer Profile with their respective Scopes.
When using the Change Email update action, even if the email address remains the same, the Customer's isEmailVerified
property is set to false
.
Customer password reset
Password reset follows the same set of steps for global as well as Store-specific Customers. For global customers, use the general Customer endpoints. For Store-specific Customers, use the Customer in Store endpoints.
To reset a Customer's password, do the following:
- Send a password reset token embedded in a link to the Customer.
- For global Customers, use the Create password reset token for Customer endpoint.
- For Store-specific Customers, use Create password reset token for Customer in Store endpoint.
- When the Customer clicks the link, optionally retrieve the Customer by the password token.
- For global Customers, use the Get Customer by password token endpoint.
- For Store-specific Customers, use the Get Customer in Store by password token endpoint.
- When the Customer enters the new password, reset the Customer's password.
- For global Customers, use the Password reset of Customer endpoint.
- For Store-specific Customers, use the Password of Customer in Store endpoint.
- These methods are also provided on the My Customer Profile with their respective Scopes.
Customer permissions
Customer information can contain sensitive data, therefore you need to ensure that a customer can only access their own personal information.
Composable Commerce resources that may contain or refer to customer data:
- BusinessUnit
- Cart
- Customer
- CustomObject
- DiscountCode
- Message
- Order
- OrderEdit
- Payment
- Quote
- QuoteRequest
- Review
- ShoppingList
- StagedQuote
In your shopfront, you have to implement this data protection yourself because an API Client with the view_customers
scope provides access to all Customers in your Project. Another way of data fencing is to provide access through the Me endpoints as described in the following section.
Hierarchies within Business Units
Business Units allow you to create and manage representations of businesses in your Composable Commerce Project. They are especially useful in B2B use cases because they allow you to represent a company's structure and the access rights of its members. As illustrated in the diagram below, Business Units are organized hierarchically in tree structures, with a single Business Unit on top. The top-level Business Unit must be of type Company. Units that are organized below are of type Division. Divisions contain a reference to their parent Company or to a higher-order order Division.
Roles in Business Units
Composable Commerce allows you to define the different roles that Associates can hold in a Business Unit. These roles can allow Associates to manage the Business Unit, manage other Associates, and to make purchases on behalf of the Business Unit. Composable Commerce verifies that the Customer referenced on the Cart is an Associate of the Business Unit. If not, the Cart cannot be ordered.
For any Cart and Order, the API sets the Product Selection and Prices based on the Business Unit referenced in the Cart. The Store of the Customer is disregarded in this instance. Therefore it is important to model company-specific products or pricing at the Business Unit level as explained in section Customer-specific prices.
Store-specific permissions
If you have Store-specific Customers in your Project, you can provide Store-specific access to those. Not only can Customers be managed per Store through the Get, Query, Create, Update, and Delete Customer in Store endpoints, but the Carts associated with them can be retrieved per Store.
The Me endpoints are provided as Customer in Store variations with restricted access for one Store-specific Customer.
Customer-specific products, prices, and discounts
Composable Commerce allows several ways to specify customer-specific prices. Depending on your customer base, Customer Groups are one approach to model group-specific prices. If you negotiate prices with each B2B customer individually, the Business Units approach might be more scalable.
Customer Groups
Customers can be assigned to Customer Groups to offer them the same prices or promotions. This feature is more targeting B2C cases in which the number of Customer Groups is limited to 1 000
.
Business Units
Especially for B2B scenarios, in which you need to be able to specify bespoke prices for each Business Unit individually, Customer Groups might not be sufficient. Stores give you more flexibility in customer-specific price models since you are able to assign Channels and Product Selections to a Business Unit. To learn how these concepts work together, see our tutorial on setting up company-specific products, pricing, and discounts.
The below table summarizes which Composable Commerce APIs you can utilize for which purpose in your use case.
Composable Commerce API | Use it for |
---|---|
Cart Discounts | specifying the customer-specific cart discount on each Cart object |
Channels | specifying the customer-specific price on each Price object |
Stores | specifying the customer-specific distribution channel used on each Price object, scoping the permission to the particular Customer |
Product Selections | specifying a customer-specific assortment of Products. B2B companies frequently have restrictions on which subset of their products they can make available to customers due to, for instance, purchase regions or legal restrictions. Not needed if all Products should be available for all Customers |
Business Units | letting companies act as customers (mainly used in B2B scenarios) |
When placing an Order, the Cart's customerId
has to reference an Associate in the Business Unit. To ensure that you apply the correct pricing, reference the customer-specific Channel in the distributionChannel
of the Cart's Line Item Drafts. Without specifying the Channel, Composable Commerce would select the base price instead of the customer-specific price.
It may be that multiple divisions of the same company get the same negotiated prices, but their Orders need to be separate for administrative purposes. In this case, you can create the Divisions as child Business Units of the same Company with their own individual buyers. A single Store can be referenced on all Divisions of the Company.
Depending on your use case, you may not need to use Stores at all, or you can decide to use Stores only with Channels or Product Selections.
Depending on how many different prices you want to represent, you may choose to use Standalone Prices instead of Embedded Prices. Standalone Prices allow you to store 50 000
distinct Prices, in contrast to the maximum of 100
Prices per Product Variant limit on Embedded Prices. To use Standalone Prices set the ProductPriceMode to Standalone
and create Prices for every Channel.
If you have volume-based price bands, we recommend creating a Store and Channel per price band and populating each Channel with the appropriate pricing for each Product you want to sell. Assigning a price-band-specific Store to a Business Unit gives that Business Unit access to the correct pricing.
The aforementioned approach is not recommended for checkout flows utilizing the My Carts and My Orders APIs, since this will allow the Customer to pick the Channel and hence the pricing option for their Orders. In this case, we recommend creating one Store each per all possible product restrictions and price combinations. Furthermore, the use of external prices or taxes is not supported with those APIs.