The Customer sign-up process involves two main steps:
- Customer sign-up: your application collects the user's details and sends a request to the Composable Commerce API to create a Customer record.
- Email verification: the user verifies ownership of their email address by clicking a unique link sent to them. This activates the account and enables features such as password recovery.
Customer sign-up flow
To create a Customer, your application collects the user's information and sends it to the Composable Commerce API.
POST /{projectKey}/customers
. The following example shows a request to create a Customer account for a user named Alice, including her address information and a custom field for marketing preferences.Endpoint and key request fields
-
Endpoint:
POST /{projectKey}/customers
-
Key request fields:
email
: the Customer's email address, which serves as their unique identifier for login.password
: the Customer's chosen password. Your backend for frontend (BFF) must enforce password complexity rules. Composable Commerce securely hashes and stores the password.firstName
: the Customer's first name.lastName
: the Customer's last name.addresses
: an array of address objects.defaultShippingAddress
: the index of the address in theaddresses
array to be used as the default for shipping.defaultBillingAddress
: the index of the address in theaddresses
array to be used as the default for billing.stores
(optional): for multi-Store projects, this array of Store references associates the Customer with specific Stores. If omitted, this means that the Customer is global.custom
: an object for custom fields defined in your Composable Commerce project. In this example, a boolean fieldmarketingOptIn
captures marketing consent.
-
Outcome:
- After a successful
POST /{projectKey}/customers
request, Composable Commerce creates a Customer record with theisEmailVerified
flag set asfalse
. This initiates the email verification process.
- After a successful
How Stores affect Customer sign-up
stores
array in the Customer creation request is critical for managing brand separation and data segregation.Store architecture
A project can contain multiple Stores, such as Electronics High Tech for smartphones and Zenith Living for smart home devices. The Customer-to-Store relationship determines authentication, data access, and user experience.
- Customer type: Global Customer
stores
array value: omitted or empty ([]
).- Login behavior: can log in via the global
/login
endpoint or any Store-specific/in-store/key={storeKey}/login
endpoint. This is suitable for Customers who shop across all brands.
- Customer type: Store-specific Customer.
stores
array value: contains one Store reference. For example,[{"typeId": "store", "key": "electronics-high-tech-store"}]
.- Login behavior: can log in only via the
/in-store/key={storeKey}/login
endpoint for their assigned Store. They can't log in via the global/login
endpoint or an in-Store endpoint for a Store to which they aren't assigned.
- Customer type: Multi-Store Customer
stores
array value: contains multiple Store references. For example,[{"typeId": "store", "key": "electronics-high-tech-store"}, {"typeId": "store", "key": "zenith-living-store"}]
.- Login behavior: can log in via the in-Store endpoint for any of their assigned Stores, but can't use the global
/login
endpoint.
This separation is essential to maintain distinct Customer bases for different brands or regions.
Why use Stores?
Using Stores provides the following advantages:
- Multi-brand management: operate distinct brands with separate Customer bases, catalogs, and pricing.
- Regional variations: manage different legal entities, currencies, and languages for international expansion.
- B2B vs. B2C: run separate storefronts for different Customer segments.
- Data segmentation: segment Customer data for targeted analysis and marketing.
- Access control: inherently control authentication against specific storefronts.
Proper implementation of the Customer-to-Store relationship enables a flexible, scalable, and secure e-commerce platform.
Example - Create a global Customer account
The following example creates a global Customer account, including address details and a custom field for marketing opt-in.
import { CustomerDraft, Customer } from "@commercetools/platform-sdk";
import { apiRoot } from "../../client";
// Function to create a new customer
async function createCustomer(customerData: CustomerDraft): Promise<Customer> {
try {
const customer = await apiRoot
.customers()
.post({ body: customerData })
.execute();
console.log("Customer created successfully:", customer.body);
return customer.body;
} catch (error) {
console.error("Error creating customer:", error);
throw error;
}
}
// Alice's sign-up data
const aliceSignUpData: CustomerDraft = {
email: "alice.smith@example.com",
password: "StrongPassword123!", // Ensure your BFF enforces password compliance e.g. min. password length, usage of special characters, etc.
firstName: "Alice",
lastName: "Smith",
addresses: [
{
streetName: "Main St",
streetNumber: "123",
postalCode: "90210",
city: "Beverly Hills",
state: "CA",
country: "US",
},
{
streetName: "Oak Ave",
streetNumber: "45",
postalCode: "10001",
city: "New York",
state: "NY",
country: "US",
},
],
defaultShippingAddress: 0, // Index of the first address
defaultBillingAddress: 0, // Index of the first address
custom: {
type: {
key: "customer-marketing-opt-in", // Assuming you have a Custom Type defined with this key
typeId: "type",
},
fields: {
marketingOptIn: true,
},
},
};
// Execute the customer creation
(async () => {
try {
const newCustomer = (await createCustomer(aliceSignUpData)).customer;
// At this point, newCustomer.isEmailVerified will be false
console.log(
`Customer account created. Email verification status: ${newCustomer.isEmailVerified}`
);
} catch (err) {
console.error("Failed to create customer account.");
}
})();
Key takeaways
- Use
POST /{projectKey}/customers
to create a Customer. - The
isEmailVerified
flag isfalse
by default upon creation. - The
stores
array determines if a Customer is global or Store-specific. - Global Customers can log in anywhere; Store-specific Customers are restricted to their assigned Store's login endpoint.
- Stores are a powerful feature for managing multiple brands, regions, and business models within a single Project.
Email verification flow
After a Customer record is created, their email address must be verified. This is a critical step for security and user experience.
Why email verification is crucial
- Data accuracy: ensures that the email address is valid and owned by the user.
- Spam prevention: reduces fake or bot accounts, maintaining a clean Customer database.
- Password recovery: a verified email address is essential for secure password resets.
- Communication channel: establishes a trusted channel for Order updates, notifications, and marketing.
- Account security: prevents unauthorized users from registering with an email address they don't own.
The email verification process involves creating a verification token and then confirming the email with that token.
Create the verification token
After sign-up, your application must generate a unique token to be sent to the Customer's email.
-
Endpoint:
POST /{projectKey}/customers/email-token
-
Request: provide the Customer
id
andttlMinutes
(Time To Live) details for the token.id
: unique identifier of the Customer.ttlMinutes
: the token's validity duration in minutes. A short TTL (for example, 120 minutes) is recommended for security.
-
Response: the API returns a
value
, which is the token. -
Action: your backend or an integrated email service provider (ESP) sends this token to the Customer's email, typically embedded in a verification link. For example,
https://yourshop.com/verify-email?token=TOKEN_VALUE
. When the Customer clicks this link, they are redirected to your application to process the verification.
Example - Generate an email verification token
customerId
.import { apiRoot } from "../../client";
// Assuming newCustomer.id from the previous step
const aliceCustomerId = "customer-id-of-alice"; // Replace with actual ID obtained after creation
// Function to create an email verification token
async function createEmailVerificationToken(
customerId: string,
ttlMinutes: number = 120
) {
try {
const tokenResponse = await apiRoot
.customers()
.emailToken()
.post({
body: {
id: customerId,
ttlMinutes: ttlMinutes,
},
})
.execute();
// Note to learner: Avoid logging tokens in the logs, specially on production env
if (process.env.NODE_ENV !== "production") {
console.log(
"Email verification token generated:",
tokenResponse.body.value
);
}
return tokenResponse.body.value;
} catch (error) {
// Note to learner: Implement proper error handling
console.error("Error generating email verification token:", error);
throw error;
}
}
// Execute token generation and simulate sending verification email
(async () => {
try {
const verificationToken = await createEmailVerificationToken(
aliceCustomerId
);
const verificationLink = `https://www.zenelectron.com/verify-email?token=${verificationToken}`;
const emailData = {
toName: "Alice",
toEmail: "alice@example.com",
subject: "Verify your Zen Electron Account",
body: `
Dear Alice,
Thank you for signing up with Zen Electron!
Please click the following link to verify your email address:
${verificationLink}
This link expires in 2 hours.
If you did not create an account, please ignore this email.
`.trim(),
};
// Note to learner: Implement actual email sending logic inside sendVerificationEmail()
sendVerificationEmail(emailData);
} catch (err) {
console.error("Failed to generate or send verification email.");
}
})();
Confirm the email address
When the Customer clicks the verification link, your application's backend extracts the token and sends it to Composable Commerce for confirmation.
-
Endpoint:
POST /{projectKey}/customers/email/confirm
-
Request: provide the
tokenValue
from the verification link. -
Outcome: If the token is valid and not expired, then Composable Commerce sets the Customer's
isEmailVerified
flag astrue
. The account is now fully activated. If the token is invalid or expired, then the API returns an error message.
Example - Confirm a Customer's email address
This example shows how your backend confirms the email address by using a token received from the frontend.
import { apiRoot } from "../../client";
// Assuming `tokenValue` is received from the URL parameter (e.g., from the front-end)
const receivedTokenValue = "GENERATED_TOKEN_FROM_PREVIOUS_STEP"; // Replace with the actual token
// Function to confirm email verification
async function confirmEmailVerification(token: string) {
try {
const customer = await apiRoot
.customers()
.emailConfirm()
.post({
body: {
tokenValue: token,
},
})
.execute();
console.log(
"Email successfully confirmed for customer:",
customer.body.email
);
console.log("isEmailVerified status:", customer.body.isEmailVerified);
return customer.body;
} catch (error) {
console.error("Error confirming email:", error);
throw error;
}
}
// Execute email confirmation
(async () => {
try {
const verifiedCustomer = await confirmEmailVerification(receivedTokenValue);
// You can now proceed with logging Alice in or directing her to a welcome page
} catch (err) {
console.error("Email verification failed.");
}
})();
Considerations for email verification
- Token expiry (TTL): set a reasonable TTL for tokens (1-2 hours is secure). Your application should handle expired tokens by prompting the user to request a new one.
- User experience: provide clear instructions. After sign-up, inform the user to check their email. Offer a resend verification email option, which triggers a new
POST /{projectKey}/customers/email-token
request. - Email templates: email templates are managed by an external email service provider (ESP) like SendGrid, not by Composable Commerce. Customize these templates to match your brand.
CustomerEmailTokenCreated
message contains the tokenValue
only if the ttlMinutes
is 60 minutes or fewer. For longer token validity, the tokenValue
is omitted due to security reasons. For more information, see the CustomerEmailTokenCreated
message documentation.Considerations for migrating verified customers
isEmailVerified
flag set as true
to bypass the verification flow.isEmailVerified
flag in Composable Commerce might be redundant.Key takeaways
- Email verification uses a two-step process: token creation and email confirmation.
- Use
POST /{projectKey}/customers/email-token
to generate a secure, time-limited token for a Customer. - Your application is responsible for sending the verification link with the token to the Customer's email.
- Use
POST /{projectKey}/customers/email/confirm
with thetokenValue
to verify the email address. - A successful verification sets the
isEmailVerified
flag for the Customer astrue
.
Sign-up and email verification flow diagram
The following diagram illustrates the sign-up and email verification flow:
You've now learned how to create Customer accounts and implement email verification. Next, we'll cover how Customers can securely log in to their accounts.