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

You need to storeUse
One value per customer, such as a loyalty tierAn attribute on customer
One value per conversation, such as an order number the customer asked aboutAn attribute on conversation
Many records per customer, such as orders, shipments or bookingsA custom Klass
A record with its own lifecycle and several fields that agents review togetherA custom Klass
Data a KView or workflow needs to look up by its own externalIdA custom Klass

Define a custom Klass

klasses (excerpt)
{
  "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" }
        }
      }
    }
  ]
}
Klass
namestringrequired
iconstring
colorstring
metadata.propertiesobject

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:

SuffixTypeExample
StrShort stringstatusStr
TxtLong textgiftMessageTxt
NumNumbertotalNum
AtDate and timeplacedAt
BoolBooleanisGiftBool
UrlURLtrackingUrl

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:

klasses (excerpt)
{
  "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:

In your definitionWith "identifier": "acmeord"
loyaltyTierStr@acmeordLoyaltyTierStr
lifetimeValueNum@acmeordLifetimeValueNum
orderNumberStr on conversation@acmeordOrderNumberStr

Use the namespaced name everywhere you read or write the value: the API, KViews, workflows and search.

PATCH /v1/customers/{id}
{
  "custom": {
    "@acmeordLoyaltyTierStr": "gold",
    "@acmeordLifetimeValueNum": 1240
  }
}
Workflow step params
{
  "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

ChangeEffect when an org updates
Add an attributeAdded to the Klass
Stop declaring an attributeValues already written stay on existing records
Remove a whole Klass from the definitionThe Klass and its records stay. Kustomer never deletes Klasses when an app updates.
Rename a KlassA new, empty Klass is created next to the old one

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.

Troubleshooting

SymptomCheck
An attribute isn't on the recordIs its suffix valid? Is it active in Settings › Platform › Klasses? Did you write the namespaced name for a standard object?
A second Klass named after a standard object appearedmetadata.standard: true is missing.
400 writing a KObjectThe Klass name in the path doesn't match the definition, or a value doesn't match its suffix's type.
Search or a workflow condition finds nothingUse the system name, not the display name, such as kobject_custom_acme_orders-order_statusStr. For standard objects, include the @identifier prefix.