B2B or B2C: how your organisation is set up
Your organisation is either B2B, where every user belongs to one of the businesses you serve, or B2C, where you serve the public. It decides what every call must send.
- What B2B and B2C mean, and who decides
- What to send on each call, with curl, TypeScript and Python
- How to register customers and link channels and phone numbers
- The error codes, and the roles and key scope for data requests
What each means
| B2B | B2C | |
|---|---|---|
| Who your users are | People who work for the businesses you sell to (your customers). Every user belongs to one customer. | Members of the public. There are no customers. |
| What a call names | The user (endUserId / X-End-User-Id) and their customer (customerGroupId / X-Customer-Group-Id). | The user only. |
| What you get per customer | Limits, tiers, documents, usage, billing lines, support access and data requests per customer. | Limits, usage and data requests per user. |
Who sets it
BUSINESS_TYPE_LOCKED. If you are unsure which you are, ask your Dezifi contact before onboarding.What to send on each call
# B2B: name the customer the user belongs to
curl -X POST https://api.dezifi.ai/api/v1/runtime/agents/<agentId>/session-tokens \
-H "Authorization: Bearer $DEZIFI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{ "endUserId": "user-123", "customerGroupId": "northwind" }'
# Server-side calls for that user carry both headers
curl -X POST https://api.dezifi.ai/api/v1/runtime/agents/<agentId>/sessions \
-H "Authorization: Bearer $DEZIFI_SECRET_KEY" \
-H "X-End-User-Id: user-123" \
-H "X-Customer-Group-Id: northwind" \
-H "Content-Type: application/json" -d '{}'# B2C: the user only; no customer
curl -X POST https://api.dezifi.ai/api/v1/runtime/agents/<agentId>/session-tokens \
-H "Authorization: Bearer $DEZIFI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{ "endUserId": "user-123" }'
curl -X POST https://api.dezifi.ai/api/v1/runtime/agents/<agentId>/sessions \
-H "Authorization: Bearer $DEZIFI_SECRET_KEY" \
-H "X-End-User-Id: user-123" \
-H "Content-Type: application/json" -d '{}'import { DezifiClient } from '@dezifi/client';
const dezifi = new DezifiClient({
baseUrl: 'https://api.dezifi.ai',
apiKey: process.env.DEZIFI_SECRET_KEY,
workspaceId: Number(process.env.DEZIFI_WORKSPACE_ID),
});
const agent = dezifi.agent(process.env.DEZIFI_AGENT_ID ?? '');
// B2B: the customer is required on every end-user call
const b2bToken = await agent.mintSessionToken('user-123', 900, { customerGroupId: 'northwind' });
const asB2bUser = dezifi.onBehalfOf({ endUserId: 'user-123', customerGroupId: 'northwind' });
// B2C: the user only
const b2cToken = await agent.mintSessionToken('user-123', 900);
const asB2cUser = dezifi.onBehalfOf({ endUserId: 'user-123' });from datetime import timedelta
# B2B: the customer is required on every end-user call
b2b_token = agent.mint_session_token("user-123", ttl=timedelta(minutes=15), customer_group_id="northwind")
as_b2b_user = client.on_behalf_of("user-123", "northwind")
# B2C: the user only
b2c_token = agent.mint_session_token("user-123", ttl=timedelta(minutes=15))
as_b2c_user = client.on_behalf_of_end_user("user-123")agent.mintSessionToken(SessionTokenRequest.forEndUser("user-123").inCustomerGroup("northwind")) and client.onBehalfOf("user-123", "northwind") for B2B; agent.mintSessionToken("user-123") and client.onBehalfOfEndUser("user-123") for B2C.B2B: register your customers first
- First load: a CSV. In Admin > Customers, click Import CSV and choose a file with the columns
externalId,displayNameand, optionally,region. You see the rows before anything is added; rows with a missing or malformed id are listed, not imported. - New customers afterwards: the API. When a business signs up to your product, add it from your backend with a secret key that has
customer-group:write(the SDKs:customerGroups().create()/customer_groups().create()). One at a time also works in Admin > Customers with Add customer. - The external id is your own id for the customer: letters, digits, dots, underscores, colons and dashes, up to 128 characters.
externalId,displayName,region
northwind,Northwind Traders,eu
globex,Globex Corporationcurl -X POST https://api.dezifi.ai/api/v1/customer-groups \
-H "Authorization: Bearer <secret key with customer-group:write>" \
-H "Content-Type: application/json" \
-d '{ "externalId": "northwind", "displayName": "Northwind Traders" }'B2B: channels and phone numbers belong to a customer
customerGroupId on a PhoneChannel (and on a schedule Trigger that runs for one customer) only in a B2B organisation.Anonymous widget visitors
Error codes and what to do
{ "error": { "code": "…", "message": "…" } }.| Code | HTTP | When | What to do |
|---|---|---|---|
CUSTOMER_REQUIRED | 400 | B2B: an end-user call (a token mint, a call on behalf of a user, a channel or phone number, a webhook end user) named no customer. | Send customerGroupId (token mint) or X-Customer-Group-Id with X-End-User-Id; link the channel or number to a customer. |
CUSTOMERS_NOT_USED | 403 | B2C: the call named a customer, or used a customer-only feature (customers, tiers, bulk changes, per-customer billing and usage, support access, customer datasets). | Leave the customer out. Those features are for B2B organisations only. |
INVALID_ARGUMENT | 400 | B2B: the customer you named is not registered in the workspace ("Customer group '…' does not exist in this workspace"). | Add it under Admin > Customers or with the API first, then retry. |
BUSINESS_TYPE_LOCKED | 409 | Someone tried to change the organisation's business type after onboarding. | It is set by Dezifi at onboarding and cannot be changed in the product. Contact your Dezifi contact. |
ACCESS_DENIED | 403 | The person or key lacks the permission, for example a key without privacy:manage forgetting an end user. | Give the role or the key the permission (see Roles below), or use a key that has it. |
With SDK 0.1.0-beta.3, read code from the error body in the exception message. The next SDK release adds a typed error for each, so you can catch it instead; each one is still the error type its HTTP status always produced (AuthError / DezifiAuthError / DezifiAuthException for a 403), so existing handling keeps working.
| Code | TypeScript | Python | Java |
|---|---|---|---|
CUSTOMER_REQUIRED | CustomerRequiredError | CustomerRequiredError | CustomerRequiredException |
CUSTOMERS_NOT_USED | CustomersNotUsedError | CustomersNotUsedError | CustomersNotUsedException |
BUSINESS_TYPE_LOCKED | BusinessTypeLockedError | BusinessTypeLockedError | BusinessTypeLockedException |
ACCESS_DENIED | PermissionDeniedError | PermissionDeniedError | PermissionDeniedException |
import { CustomerRequiredError, CustomersNotUsedError, PermissionDeniedError } from '@dezifi/client';
try {
await agent.mintSessionToken(user.id, 900, { customerGroupId: user.orgId });
} catch (err) {
if (err instanceof CustomerRequiredError) { /* B2B: send customerGroupId */ }
else if (err instanceof CustomersNotUsedError) { /* B2C: leave the customer out */ }
else if (err instanceof PermissionDeniedError) { /* the key lacks a permission */ }
else throw err;
}Roles for the people around your customers
| Role | Can | Cannot |
|---|---|---|
| Admin | Everything: build and run agents, set up customers, read usage and cost, export the per-customer invoice lines, answer data requests, manage users and roles. | — |
| Member | Build and run agents, read Monitor, read customers and their usage. A workspace admin also sets up the customers of their workspace. | Export billing, answer data requests or manage users. |
| Viewer | Read agents, runs and customers. | See usage or cost, export billing, answer data requests or change anything. |
Custom roles can combine the four customer permissions: customers:manage, usage:read, billing:export and privacy:manage. For someone in finance, make a role with customer-group:read, usage:read and billing:export; for someone who answers data requests, one with privacy:manage (and customer-group:read to pick the customer in Admin > Privacy). Admins have all four.
Support access limits a person, whatever their role, to the customers they support: set it under Admin > Customers > Support access. They then see only those customers' conversations, usage and Analytics, and every conversation they open is on that customer's audit trail.
Data requests from your backend need privacy:manage
privacy:manage and that belongs to a workspace Admin or Owner. A key with only agent:execute is refused with ACCESS_DENIED. Widget keys and session tokens can never do it.# B2B: name the person's customer. B2C: leave ?customerGroupId=... out.
curl -X POST "https://api.dezifi.ai/api/v1/end-users/user-123/forget?customerGroupId=northwind" \
-H "Authorization: Bearer <secret key with privacy:manage>"customerGroups().forgetEndUser(id, customer?) and exportEndUser (TypeScript, Java), customer_groups().forget_end_user(id, customer_group_id=None) and export_end_user (Python). Name the customer in B2B; leave it out in B2C.Frequently asked questions
- Can I switch from B2C to B2B later?
- Not in the product: the business type is set by Dezifi at onboarding and changes are refused (BUSINESS_TYPE_LOCKED). Talk to your Dezifi contact before onboarding if you are unsure.
- In B2B, what about a user who is not part of any customer?
- Every signed-in user of a B2B organisation belongs to a customer. Anonymous widget visitors are the exception: they name no customer.