# Customers overview Overview of the concepts related to customers purchasing products offered in your Project. A [Customer](/api/projects/customers.md) is a person ([uniquely identified by an email address](/api/customers-overview.md#customer-uniqueness)) purchasing [Products](/api/projects/products.md). For this, the [Carts](/api/projects/carts.md) and [Orders](/api/projects/orders.md) containing the Products are associated to one Customer. Furthermore, Customers can provide [Reviews](/api/projects/reviews.md) for Products. Especially in B2B scenarios, Products are often purchased by individuals representing a business or a department of a business. These scenarios are supported with [Business Units](/api/customers-overview.md#hierarchies-within-business-units) for Companies and their Divisions. If your Project is structured with [Stores](/api/projects/stores.md), 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](/api/customers-overview.md#customer-specific-products-prices-and-discounts). ## Customer uniqueness Customers are identified by their email address that must be unique across the [Project](/api/projects/project.md). Emails are treated as [case-insensitive](/api/customers-overview.md#email-case-insensitivity) in some API methods. You can have Customers [globally in the Project or only for specific Stores](/api/customers-overview.md#global-versus-store-specific-customers). ### 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**: - [Signing up](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers:POST) - [Authenticating](/api/customers-overview.md#customer-authentication-sign-in) - [Creating password reset tokens](/api/projects/customers.md#password-reset-of-customer) For example: if a customer signs up with `Email@example.com`... - Authenticating with `email@example.com` or `EMAIL@example.com` succeeds - Sign-up attempts with `email@example.com` or `EMAIL@example.com` fail unless [Stores](/api/customers-overview.md#global-versus-store-specific-customers) are in use - Generating a password reset token with `email@example.com` or `EMAIL@example.com` succeeds To perform a case-insensitive [query](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers:GET) for emails, convert the given email address to lowercase and use the additional query field [lowercaseEmail](/api/projects/customers.md#customer). ### Global versus Store-specific Customers Customers can either be global or Store-specific: - Global Customers are unique to a [Project](/api/projects/project.md). A Customer is considered global when the [Customer](/search.md?urn=ctp:api:type:Customer) `stores` field is empty. Since global Customers are not assigned to any particular Store, they have broad access to all Stores within the Project. A global Customer cannot create an account in a Store using the same email address. - Store-specific Customers are unique to a specific [Store](/api/projects/stores.md) in your Project. A Customer is considered Store-specific, when the [Customer](/search.md?urn=ctp:api:type:Customer) `stores` field contains one or more Stores. Store-specific Customers can create an account in another Store using the same email address. #### Example For example, if you do the following: 1. Register `email@example.com` as a global Customer. 2. Try to register `email@example.com` in a specific Store. The second registration fails because as a global Customer the same email address cannot be used to create an account in a specific Store. 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. We recommend deciding whether to create Customers per-store or globally during your initial Project configuration. Due to these differences, two different authorization flows are used depending on the type of Customer: - [Password Flow for global Customers](/api/authorization.md#password-flow-for-global-customers) - [Password Flow for Customers in a Store](/api/authorization.md#password-flow-for-customers-in-a-store) ## Customer authentication (sign-in) Customer authentication endpoints differentiate between [global and store-specific Customers](/api/customers-overview.md#global-versus-store-specific-customers). - To authenticate a global Customer (not associated with a Store), use the [general](/search.md?urn=ctp:api:endpoint:/{projectKey}/login:POST) or [Store-specific](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/login:POST) endpoint. - To authenticate a Store-specific Customer, use the [Store-specific](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/login:POST) endpoint. During the sign-in process, Customers may be assigned resources created prior to the sign-in. With `anonymousCart`, a single anonymous [Cart](/search.md?urn=ctp:api:type:Cart) can be assigned. With `anonymousId`, all [Carts](/api/projects/carts.md#cart), [Orders](/api/projects/orders.md#order), [ShoppingLists](/api/projects/shoppingLists.md#shoppinglist), and [Payments](/api/projects/payments.md#payment) 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](/search.md?urn=ctp:api:type: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](/search.md?urn=ctp:api:type:AnonymousCartSignInMode) is set to `MergeWithExistingCustomerCart`, then the items of the anonymous Cart will be merged into the Customer's most recently modified active Cart. This process is referred to as [Cart merge](/api/customers-overview.md#cart-merge-during-sign-in-and-sign-up) and results in a specific set of changes for both Carts. Upon successfully signing-in a Customer, a [CustomerSignInResult](/search.md?urn=ctp:api:type:CustomerSignInResult) is returned. If the CustomerSignInResult contains a Cart, the Cart is [recalculated](/api/projects/carts.md#recalculate) to have up-to-date prices, taxes, discounts, and line items. ### Cart merge during sign-in and sign-up A Customer with an active Cart may continue shopping in an anonymous session. The API provides the capability to merge the anonymous Cart with the Customer's active Cart when the Customer signs in or signs up at the storefront. For detailed information about the merging process, including merge criteria and behavior, see [Merge a Cart](/api/carts-orders-overview.md#merge-a-cart) on the Carts and Orders overview page. Cart merge during sign-in and sign-up is only available for Customers authenticating through the [Internal OAuth](/api/authorization.md#request-an-access-token-using-the-internal-oauth-20-service). To merge Carts belonging to externally authenticated Customers, use the [Merge Cart](/search.md?urn=ctp:api:endpoint:/{projectKey}/carts/customer-id={customerId}/merge:POST) and [Merge Cart in Store](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/carts/customer-id={customerId}/merge:POST) endpoints on the Carts API. Cart merge is applied by default on the following endpoints: - [Create (sign up) Customer](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers:POST) - [Create (sign up) Customer in Store](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/customers:POST) - [Authenticate (sign-in) Customer](/search.md?urn=ctp:api:endpoint:/{projectKey}/login:POST) - [Authenticate (sign in) Customer in Store](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/login:POST). To deactivate this feature, set the `anonymousCartSignInMode` field on the [CustomerSignin](/search.md?urn=ctp:api:type:CustomerSignin) to `UseAsNewActiveCustomerCart`. The response to a sign-in or sign-up contains the Customer's most recently modified active Cart. They can then modify this Cart and place an order. Learn how to manage the complete Customer authentication lifecycle with commercetools in our self-paced [Manage sign-ups and sign-ins](/learning-implement-carts-and-shopping-lists/manage-signups-and-signins/overview.md) module. ## 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](/api/projects/customers.md#email-verification-of-customer). For Store-specific Customers, use the [Customer in Store endpoints](/api/projects/customers.md#email-verification-of-customer-in-store). To verify a Customer's email, do the following: 1. Send an email token embedded in a link to the Customer. - For global Customers, use the [Create email token for Customer endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers/email-token:POST). - For Store-specific Customers, use [Create email token for Customer in Store endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/customers/email-token:POST). If the token is valid for 60 minutes or less, its value can be retrieved through the [CustomerEmailTokenCreated](/api/projects/messages/customer-messages.md#customer-email-token-created) Message—enabling asynchronous flows. By default, creating an email token does not invalidate older tokens; to invalidate older tokens, use the [CustomerCreateEmailToken](/search.md?urn=ctp:api:type:CustomerCreateEmailToken) update action. 2. 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](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers/email-token={emailToken}:GET). - For Store-specific Customers, use the [Get Customer in Store by email token endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/customers/email-token={emailToken}:GET). 3. Verify the Customer's email. This sets the Customer's `isEmailVerified` field to `true`. - For global Customers, use the [Verify email of Customer endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers/email/confirm:POST). - For Store-specific Customers, use the [Verify email of Customer in Store endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/customers/email/confirm:POST). - These methods are also provided on the [My Customer Profile](/search.md?urn=ctp:api:endpoint:/{projectKey}/me/email/confirm:POST) with their respective [Scopes](/api/scopes.md). When using the [Change Email](/api/projects/customers.md#change-email) update action, even if the email address remains the same, the Customer's `isEmailVerified` property is set to `false`. After the email is verified, all email tokens issued previously through this flow are invalidated. This invalidation of tokens is [eventually consistent](/api/general-concepts.md#eventual-consistency). ## 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](/api/projects/customers.md#password-reset-of-customer). For Store-specific Customers, use the [Customer in Store endpoints](/api/projects/customers.md#password-reset-of-customer-in-store). To reset a Customer's password, do the following: 1. Send a password reset token embedded in a link to the Customer. - For global Customers, use the [Create password reset token for Customer endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers/password-token:POST). - For Store-specific Customers, use [Create password reset token for Customer in Store endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/customers/password-token:POST). If the token is valid for 60 minutes or less, its value can be retrieved through the [CustomerPasswordTokenCreated](/api/projects/messages/customer-messages.md#customer-password-token-created) Message—enabling asynchronous flows. By default, creating a password token does not invalidate older tokens; to invalidate older tokens, use the [CustomerCreatePasswordResetToken](/search.md?urn=ctp:api:type:CustomerCreatePasswordResetToken) update action. 2. 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](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers/password-token={passwordToken}:GET). - For Store-specific Customers, use the [Get Customer in Store by password token endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/customers/password-token={passwordToken}:GET). 3. When the Customer enters the new password, reset the Customer's password. - For global Customers, use the [Reset password of Customer endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/customers/password/reset:POST). - For Store-specific Customers, use the [Reset password of Customer in Store endpoint](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/customers/password/reset:POST). - These methods are also provided on the [My Customer Profile](/search.md?urn=ctp:api:endpoint:/{projectKey}/me/password/reset:POST) with their respective [Scopes](/api/scopes.md). After the password is reset, all password tokens issued previously through this flow are invalidated. In addition, any access and refresh tokens issued previously through the [password flow](/api/authorization.md#password-flow) and [refresh token flow](/api/authorization.md#refresh-token-flow) are invalidated. This invalidation of tokens is [eventually consistent](/api/general-concepts.md#eventual-consistency). ## Customer permissions Customer information can contain sensitive data, therefore you need to ensure that a customer can only access their own personal information. Resources that may contain or refer to customer data: - [BusinessUnit](/search.md?urn=ctp:api:type:BusinessUnit) - [Cart](/search.md?urn=ctp:api:type:Cart) - [Customer](/search.md?urn=ctp:api:type:Customer) - [CustomObject](/search.md?urn=ctp:api:type:CustomObject) - [DiscountCode](/search.md?urn=ctp:api:type:DiscountCode) - [Message](/search.md?urn=ctp:api:type:Message) - [Order](/search.md?urn=ctp:api:type:Order) - [OrderEdit](/search.md?urn=ctp:api:type:OrderEdit) - [Payment](/search.md?urn=ctp:api:type:Payment) - [Quote](/search.md?urn=ctp:api:type:Quote) - [QuoteRequest](/search.md?urn=ctp:api:type:QuoteRequest) - [Review](/search.md?urn=ctp:api:type:Review) - [ShoppingList](/search.md?urn=ctp:api:type:ShoppingList) - [StagedQuote](/search.md?urn=ctp:api:type:StagedQuote) An API Client with the `view_customers` scope provides access to all Customers in your Project. Therefore, you must implement your own data protection in your storefront or use the [Me endpoints](/api/me-endpoints-overview.md) as described in the next section. ### Hierarchies within Business Units [Business Units](/api/projects/business-units.md) allow you to create and manage representations of businesses in your 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](/search.md?urn=ctp:api:type:Company). Units that are organized below are of type [Division](/search.md?urn=ctp:api:type:Division). Divisions contain a reference to their parent Company or to a higher-order Division. ```mermaid graph BT; B(Division) --> A[Company]; C(Division) --> A; D(Division) --> A; E(Division) --> C; ``` ### Roles in Business Units You can define the different roles that [Associates](/api/associates-overview.md#associate) 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. The API 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](/search.md?urn=ctp:api:type:Cart) and [Order](/search.md?urn=ctp:api:type:Order), the API sets the [Product Selection](/api/projects/product-selections.md) and Prices based on the Business Unit referenced in the Cart. The [Store](/api/projects/stores.md) 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](/api/customers-overview.md#customer-specific-products-prices-and-discounts). ### Store-specific permissions If you have [Store-specific Customers](/api/customers-overview.md#global-versus-store-specific-customers) in your Project, you can provide Store-specific access to those. Customers can be managed per Store through the Customer in Store endpoints. Carts associated with these Customers can also be [retrieved per Store](/search.md?urn=ctp:api:endpoint:/{projectKey}/in-store/key={storeKey}/carts/customer-id={customerId}:GET). The [Me endpoints](/api/me-endpoints-overview.md) are provided as Customer in Store variations with restricted access for one Store-specific Customer. ## Customer-specific products, prices, and discounts Several ways are available to specify customer-specific prices. Depending on your customer base, [Customer Groups](/api/customers-overview.md#customer-groups) are one approach to model group-specific prices. If you negotiate prices with each B2B customer individually, the [Business Units](/api/customers-overview.md#business-units) approach might be more scalable. ### Customer Groups Use [Customer Groups](/api/projects/customerGroups.md) to offer specific Customers the same prices or promotions. For example, you can give all your gold members a discount on a specific product. The number of Customer Groups per project is limited to 10000. The [Customer](/search.md?urn=ctp:api:type:Customer) `customerGroup` field allows assigning one Customer Group per Customer, while the `customerGroupAssignments` field supports assigning up to 500 Customer Groups and better supports complex pricing scenarios. Although both fields can be used together in existing projects, we recommend using only the `customerGroupAssignments` field in new projects. In addition to supporting assigning multiple Customer Groups to Customers, it provides greater flexibility in complex pricing scenarios. To migrate existing Projects from using a single Customer Group per Customer to using multiple Customer Groups, see our [migration guide](/tutorials/migration-guides/multiple-customer-groups.md). You can assign up to 500 Customer Groups to a Business Unit via the `customerGroupAssignments` field. When updating the Customer Group assignments for a Customer or Business Unit, the prices in the Customer's or Associate's existing Carts are not recalculated automatically, and must be [recalculated](/api/projects/carts.md#recalculate) manually. ### Business Units Typical B2B scenarios require specifying bespoke prices for each Business Unit individually. To help support this, there are other pricing dimensions in addition to Customer Groups. Stores give you more flexibility in customer-specific price models since you are able to assign [Channels](/api/projects/channels.md) and [Product Selections](/api/projects/product-selections.md) to a Business Unit. The following table summarizes which APIs you can utilize for which purpose in your use case. | API | Use it for | | --- | --- | | [Cart Discounts](/api/projects/cartDiscounts.md) | specifying the customer-specific cart discount on each Cart object | | [Channels](/api/projects/channels.md) | specifying the customer-specific price on each Price object | | [Stores](/api/projects/stores.md) | specifying the customer-specific distribution channel used on each Price object, scoping the permission to the particular Customer | | [Product Selections](/api/projects/product-selections.md) | 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](/api/projects/business-units.md) | letting companies act as customers | | The following steps provide a high-level approach to setting up company-specific products, prices, and discounts. The steps can vary depending on your Project model. | | 1. Create a Channel to represent a specific set of Prices. 2. Create a Product and assign it a different Price inside the new Channel. 3. Create a Product Selection and add the Product to it. 4. Create a Store and assign the Channel and Product Selection to it. 5. Assign the Store to the Business Unit that represents the customer. 6. Create a Cart Discount in the Store. 7. Create a Cart in the Store and add the Product. 8. Place an Order for the customer. When [placing an Order](/search.md?urn=ctp:api:endpoint:/{projectKey}/orders:POST), the [Cart's](/api/projects/carts.md#cart) `customerId` has to reference an [Associate](/search.md?urn=ctp:api:type: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](/api/projects/carts.md#lineitemdraft). Without specifying the Channel, the base price is selected instead of the customer-specific price. It may be that multiple divisions of the same company get the same negotiated prices, but their [Orders](/api/projects/orders.md) need to be separate for administrative purposes. In this case, you can create the Divisions as child [Business Units](/api/projects/business-units.md) 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 Stores at all. You can use Channels only. If you want to use Product Selections, you must use them together with Stores. Depending on how many different prices you want to represent, you may choose to use Standalone Prices instead of Embedded Prices. To use Standalone Prices, set the [ProductPriceMode](/api/projects/products.md#productpricemode) to `Standalone` and [create Prices](/search.md?urn=ctp:api:endpoint:/{projectKey}/standalone-prices:POST) for every Channel. For more information about the difference between Embedded Prices and Standalone Prices, see [Pricing](/api/pricing-and-discounts-overview.md#pricing). To handle volume-based pricing, we recommend creating a [Store](/api/projects/stores.md) and [Channel](/api/projects/channels.md) per price band. Then add the appropriate price to each Channel for each Product you want to sell. Assigning a price-band-specific Store to a [Business Unit](/api/projects/business-units.md) gives that Business Unit access to the correct pricing. This approach is not recommended for checkout flows that use the [My Carts](/api/projects/me-carts.md) and [My Orders](/api/projects/me-orders.md) APIs. It allows the Customer to select the Channel and, therefore, the pricing option for their Orders. Instead, create one Store for each product restriction and price combination. External [prices](/api/projects/carts.md#lineitempricemode) and [taxes](/api/projects/carts.md#taxmode) are not supported with those APIs. ## Related pages - [Area overview page with navigation](/api.md) - [Next page: Customers](/api/projects/customers.md) - [Search documentation and API specs](/search.md)