CRM
Customers, customer authentication, and audience subscriptions
The CRM module manages customer records and audience subscriptions for your business. Customers are business-scoped — each business has its own customer list. A customer can be linked to orders, bookings, reactions, and audience subscriptions, and can authenticate via email magic codes.
Key Concepts
Customer vs Account
- Account — platform-level auth identity. One person, one Account across all businesses.
- Customer — business-level CRM record (emails, blocks, taxonomies, audience subscriptions). Each business has its own view of a customer.
Blocks and Taxonomies
Customer data (name, phone, addresses, notes, tags, etc.) is stored as blocks and taxonomies — the same content model used by the CMS. This lets a business define its own custom customer fields instead of being locked into a fixed schema.
Multiple Emails
Customers support multiple emails. The initialize flow creates an anonymous guest customer; emails are attached once the customer authenticates with requestCode / verify or is updated by an admin.
Customer Endpoints
Create Customer (Admin)
/v1/businesses/{businessId}/customers sdk.crm.create() Creates a new customer. If a customer with the same email already exists, returns the existing one (idempotent).
Parameters
| Name | Type | Description |
|---|---|---|
email required | string | Primary email for the customer |
blocks optional | Block[] | Structured content blocks (name, phone, addresses, notes, etc.) |
taxonomies optional | TaxonomyEntry[] | Taxonomy entries — tags, segments, lifecycle stage |
Initialize Customer (Public)
/v1/businesses/{businessId}/customers/initialize sdk.crm.initialize() Public endpoint for end users. Creates an anonymous guest customer and returns an auth token. No email required — use this to get a customer session before any identity is known. The returned token can later be upgraded by calling connect or requestCode + verify.
Connect Customer (Public)
/v1/businesses/{businessId}/customers/connect sdk.crm.connect() Attaches an email to the current customer session (or returns/creates a customer matching the email). Returns a fresh auth token.
Request Auth Code (Public)
/v1/businesses/{businessId}/customers/auth/code sdk.crm.requestCode() Sends a verification code to the given email address. Use this to start a customer login flow.
Verify Auth Code (Public)
/v1/businesses/{businessId}/customers/auth/verify sdk.crm.verify() Exchanges a verification code for an auth token, marking the customer as verified.
Refresh Token (Public)
/v1/businesses/{businessId}/customers/auth/refresh sdk.crm.refreshToken() Exchanges a refresh token for a new access token.
Get Current Customer
/v1/businesses/{businessId}/customers/me sdk.crm.getMe() Returns the currently authenticated customer based on the bearer token.
Get Customer
/v1/businesses/{businessId}/customers/{id} sdk.crm.get() Find Customers
/v1/businesses/{businessId}/customers sdk.crm.find() Search and list customers.
Parameters
| Name | Type | Description |
|---|---|---|
query optional | string | Search across customer emails and blocks |
limit optional | number | Items per page |
cursor optional | string | Pagination cursor |
sortField optional | string | Field to sort by (e.g. createdAt) |
sortDirection optional | string | asc or desc |
Update Customer
/v1/businesses/{businessId}/customers/{id} sdk.crm.update() Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Customer ID |
emails optional | string[] | Replace the customer's email list |
blocks optional | Block[] | Replace customer blocks |
taxonomies optional | TaxonomyEntry[] | Replace taxonomy entries |
status optional | 'active' | 'archived' | Customer status |
Merge Customers
/v1/businesses/{businessId}/customers/{id}/merge sdk.crm.merge() Merges a source customer into the target. Source emails, blocks, and subscriptions are appended to the target. The source is permanently deleted (GDPR-compliant). All orders, bookings, reactions, and audience subscriptions are re-pointed to the target customer.
Revoke Session Token
/v1/businesses/{businessId}/customers/{id}/sessions/{tokenId} sdk.crm.revokeToken() Revokes a single active session for a customer.
Revoke All Session Tokens
/v1/businesses/{businessId}/customers/{id}/sessions sdk.crm.revokeAllTokens() Revokes every active session for a customer (logout everywhere).
Customer Object
{
"id": "uuid",
"businessId": "uuid",
"emails": ["john@example.com"],
"status": "active",
"blocks": [],
"taxonomies": [],
"promoUsage": [],
"authTokens": [],
"verificationCodes": [],
"audienceSubscriptions": [],
"reactions": [],
"createdAt": 1234567890,
"updatedAt": 1234567890
}
Audiences
Audiences are subscriber groups used for content gating, newsletters, and paid memberships. They live under the CRM module as sdk.crm.audiences.*.
Key Concepts
An audience is a subscriber group with two dimensions:
- Type:
standard(free) orpaid(Stripe checkout) - Confirmation: Optional double opt-in via an email template (
confirmTemplateId)
Use cases: newsletter subscriptions, premium memberships, course access, tiered content.
Create Audience
/v1/businesses/{businessId}/audiences sdk.crm.audiences.create() Parameters
| Name | Type | Description |
|---|---|---|
key required | string | Unique audience identifier (alphanumeric, hyphens, underscores) |
type optional | AudienceType | standard (default) or paid with prices |
confirmTemplateId optional | string | Email template ID for double opt-in. Omit for single opt-in. |
Get Audience
/v1/businesses/{businessId}/audiences/{id} sdk.crm.audiences.get() Look up an audience by ID or by key.
Find Audiences
/v1/businesses/{businessId}/audiences sdk.crm.audiences.find() Parameters
| Name | Type | Description |
|---|---|---|
ids optional | string[] | Filter by specific audience IDs |
status optional | string | Filter by status (active, archived) |
query optional | string | Search in audience keys |
limit optional | number | Items per page (default 50) |
cursor optional | string | Pagination cursor |
Update Audience
/v1/businesses/{businessId}/audiences/{id} sdk.crm.audiences.update() The type cannot be changed after creation, but you can update the key, status, and confirmation template.
Subscribe to Audience
/v1/businesses/{businessId}/audiences/{id}/subscribe sdk.crm.audiences.subscribe() Subscribe a customer to an audience. Behavior depends on the audience configuration:
- Standard, no confirmation: Subscription is immediately active
- Standard, with confirmation: Subscription is
pendinguntil the user clicks the confirmation link - Paid: Returns a Stripe checkout URL
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Audience ID |
customerId required | string | Customer ID (obtain via sdk.crm.initialize or sdk.crm.connect) |
priceId optional | string | Stripe price ID (required for paid audiences) |
successUrl optional | string | Redirect URL after successful payment |
cancelUrl optional | string | Redirect URL if user cancels payment |
confirmUrl optional | string | Base URL for the confirmation link (required for audiences with confirmTemplateId) |
Check Access
/v1/businesses/{businessId}/audiences/{id}/access sdk.crm.audiences.checkAccess() Check if the current customer has access to an audience.
Get Subscribers
/v1/businesses/{businessId}/audiences/{id}/subscribers sdk.crm.audiences.getSubscribers() List subscribers for an audience (admin only).
Add Subscriber
/v1/businesses/{businessId}/audiences/{id}/subscribers sdk.crm.audiences.addSubscriber() Add a subscriber by customer ID (admin only). Skips if already subscribed.
Remove Subscriber
/v1/businesses/{businessId}/audiences/{id}/subscribers/{customerId} sdk.crm.audiences.removeSubscriber() Typical Flows
E-commerce Checkout
// 1. Initialize a guest customer session
const token = await sdk.crm.initialize();
// 2. Attach the shopper's email
await sdk.crm.connect({ email: shippingAddress.email });
// 3. Checkout — the authenticated customer is resolved from the token
const order = await sdk.eshop.checkout({
items: [...],
shippingAddress: {...}
});
Newsletter Subscribe with Double Opt-in
// 1. Initialize + connect to get a customer
await sdk.crm.initialize();
const { id: customerId } = await sdk.crm.connect({ email: "user@example.com" });
// 2. Subscribe to the audience (sends confirmation email)
await sdk.crm.audiences.subscribe({
id: audienceId,
customerId,
confirmUrl: 'https://yoursite.com/confirm'
});
Customer Login (Magic Code)
// 1. Ask for a code
await sdk.crm.requestCode({ email: "user@example.com" });
// 2. User enters the code from their email
const token = await sdk.crm.verify({
email: "user@example.com",
code: "123456"
});
// 3. Persist token.refreshToken and use token.accessToken for subsequent calls
If you delete a confirmation email template, any audience referencing it will automatically lose its double opt-in and fall back to single opt-in.