Klasses
Define custom object types and add namespaced attributes to customers, companies, conversations, messages and users from an app definition.
The klasses array does two jobs. An entry with a new name creates a custom Klass: a type of custom object, such as an order, whose records (KObjects) appear on the customer timeline. An entry named after a standard object, with metadata.standard: true, adds custom attributes to customers, companies, conversations, messages or users instead.
For how KObjects behave once they exist (creating them, linking them to customers and companies, searching them) see Custom objects.
Choose a Klass or an attribute
Define a custom Klass
{
"klasses": [
{
"name": "acme_orders-order",
"icon": "cart",
"color": "#5B6CF9",
"metadata": {
"properties": {
"orderNumberStr": { "displayName": "Order number" },
"statusStr": { "displayName": "Status" },
"totalNum": { "displayName": "Total" },
"placedAt": { "displayName": "Placed" },
"giftMessageTxt": { "displayName": "Gift message" },
"isGiftBool": { "displayName": "Gift" },
"trackingUrl": { "displayName": "Tracking" }
}
}
}
]
}namestringrequired- Letters, digits,
_and-. Prefix it with your app name, such asacme_orders-order, because names are unique per org and aren't namespaced for you. It must stay the same in every version: renaming a Klass creates a second one. iconstring- A Material Design Icons name, such as
cart,truck-deliveryorcalendar-check. colorstring- Any CSS color for the icon.
metadata.propertiesobject- The Klass's attributes, keyed by system name. See below.
After install, admins can change the icon, color and attribute display names, and turn attributes on and off, in Settings › Platform › Klasses. They can't rename the Klass or its attributes.
Metadata properties
Each key is an attribute's system name in camelCase. Its suffix sets the type, exactly as for any custom attribute:
Each value is { "displayName": "…" }, the label agents see. The system name is what the API, KViews, workflows and search use, so choose it carefully: you can't rename it later without migrating data.
Set more attribute metadata, such as allowed values or a reference target for Id attributes, with PUT /v1/metadata/kobject.<klass> after install.
Write and read records
KObjects belong to a customer or company. Use the Klass name from your definition (it isn't namespaced) in the path:
post/v1/customers/{id}/klasses/{name}
curl -X POST "https://acme.api.kustomerapp.com/v1/customers/$CUSTOMER_ID/klasses/acme_orders-order" \
-H "Authorization: Bearer $KUSTOMER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"externalId": "4417",
"title": "Order #4417",
"description": "2 items · shipped",
"custom": {
"orderNumberStr": "4417",
"statusStr": "shipped",
"totalNum": 86.5,
"placedAt": "2026-10-19T14:02:00Z",
"trackingUrl": "https://track.example/1Z999"
}
}'Set externalId to your own ID so you can find and update the record later with GET /v1/klasses/{name}/externalId={externalId}. Most apps write records from a workflow instead, with the kustomer.kobject.create-with-customer and kustomer.kobject.update actions; see Workflows, actions and triggers.
Add attributes to standard objects
Name the entry after a standard object and set metadata.standard to true:
{
"identifier": "acmeord",
"klasses": [
{
"name": "customer",
"metadata": {
"standard": true,
"properties": {
"loyaltyTierStr": { "displayName": "Acme loyalty tier" },
"lifetimeValueNum": { "displayName": "Acme lifetime value" }
}
}
},
{
"name": "conversation",
"metadata": {
"standard": true,
"properties": {
"orderNumberStr": { "displayName": "Acme order number" }
}
}
}
]
}name must be company, conversation, customer, message or user.
Attributes are namespaced
Several apps can each add a sectorStr attribute to companies. To keep them apart, Kustomer renames every attribute an app adds to a standard object to @ + the app's identifier + the name with its first letter capitalized:
Use the namespaced name everywhere you read or write the value: the API, KViews, workflows and search.
{
"custom": {
"@acmeordLoyaltyTierStr": "gold",
"@acmeordLifetimeValueNum": 1240
}
}{
"action": "kustomer.conversation.update",
"params": {
"id": "/#steps.1.id",
"custom": { "@acmeordOrderNumberStr": "/#steps.lookup.body.orderNumber" }
}
}Set identifier yourself: 2 to 8 lowercase letters, digits or underscores, ideally an abbreviation of the app name. If you leave it out, Kustomer generates one at first registration. Either way it's permanent, so every version keeps the same attribute names.
Only displayName is kept for attributes on standard objects; other keys in each property are dropped.
Changes between versions
Plan names before your first release, because you can't take them back. To retire an attribute, stop writing to it and tell admins they can deactivate it.