# Custom objects (KObjects)

> Model orders, bookings, devices and other records from your systems with Klasses and KObjects, and attach them to customer timelines.

Source: https://developer.kustomer.com/docs/concepts/custom-objects

Custom objects bring records from your systems into Kustomer as first-class data. An e-commerce order, a flight booking, a subscription or a smart-home device can live on the customer's timeline, power search and workflows, and show up in agent views.

Two concepts work together:

- A **Klass** is a type, with a name, icon, color and typed attributes. For example, `ecomm-order`.
- A **KObject** is one record of that type, such as order `#4417` for Jane Doe.

```mermaid
flowchart LR
  K["Klass<br/><code>ecomm-order</code><br/>icon, color, attributes"] -. defines .-> O1["KObject<br/>Order #4417"]
  K -. defines .-> O2["KObject<br/>Order #4502"]
  O1 --> C[Customer<br/>Jane Doe]
  O2 --> C
  C --> T[(Timeline)]
  O1 --> T
  O2 --> T
```

## Choose a KObject or a custom attribute

| If you need to store                                        | Use                                                                                                  |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| One value about a customer, such as a loyalty tier          | A [custom attribute](https://developer.kustomer.com/docs/concepts/custom-attributes) on the customer |
| One value about a conversation, such as an order number     | A custom attribute on the conversation                                                               |
| Many records of the same shape, such as orders or shipments | A Klass with KObjects                                                                                |
| A structured record with several fields that agents review  | A Klass with KObjects                                                                                |

## Define a Klass

Apps usually ship their Klasses in the [app definition](https://developer.kustomer.com/docs/apps/klasses), so they're installed consistently in every org. You can also create one directly:

`POST /v1/klasses` ([reference](https://developer.kustomer.com/api/core-resources/create-klass))

```json title="Request body"
{
  "name": "ecomm-order",
  "displayName": "Order",
  "icon": "basket",
  "color": "#64943E"
}
```

- `name` is the system name used in API paths. It must be unique in the org and use only letters, digits, `_` and `-` (up to 255 characters). Prefix it with your app or company name, such as `ecomm-order`, to avoid collisions.
- `icon` is a [Material Design Icons](https://pictogrammers.com/library/mdi/) name such as `basket`, `truck-outline` or `airplane`.
- `color` is any CSS color.

Then give the attributes types and display names by setting metadata for the Klass:

`PUT /v1/metadata/{resource}` ([reference](https://developer.kustomer.com/api/core-resources/update-custom-attribute-metadata))

```bash title="cURL"
curl -X PUT "https://acme.api.kustomerapp.com/v1/metadata/kobject.ecomm-order" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "orderNumberStr": { "displayName": "Order number" },
      "orderStatusStr": { "displayName": "Status", "enumeration": ["placed", "shipped", "delivered", "returned"] },
      "totalPriceNum": { "displayName": "Total" },
      "orderedAt": { "displayName": "Ordered" },
      "trackingUrl": { "displayName": "Tracking link" }
    }
  }'
```

The suffix on each name (`Str`, `Num`, `At`, `Url`) sets its type. See [Custom attributes](https://developer.kustomer.com/docs/concepts/custom-attributes) for every suffix and option.

## Create KObjects

Create a KObject under the customer it belongs to:

`POST /v1/customers/{id}/klasses/{name}` ([reference](https://developer.kustomer.com/api/core-resources/create-customer-kobject-custom-object))

```bash title="cURL"
curl -X POST "https://acme.api.kustomerapp.com/v1/customers/$CUSTOMER_ID/klasses/ecomm-order" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Order #4417",
    "description": "2 items · Express shipping",
    "externalId": "order-4417",
    "custom": {
      "orderNumberStr": "4417",
      "orderStatusStr": "shipped",
      "totalPriceNum": 129.9,
      "orderedAt": "2026-10-18T09:12:00Z",
      "trackingUrl": "https://track.example.com/1Z999"
    },
    "data": { "lineItems": [{ "sku": "TEE-BLK-M", "qty": 2 }] },
    "tags": ["express"]
  }'
```

**KObject**

You can also create a KObject at `/v1/klasses/{name}` with `customer` or `company` in the body, or load many at once with the [bulk endpoint](https://developer.kustomer.com/api/core-resources/bulk-create-kobjects-custom-objects).

## Read and update

`GET /v1/klasses/{name}/externalId={externalId}` ([reference](https://developer.kustomer.com/api/core-resources/get-kobject-by-external-id))

`PUT /v1/klasses/{name}/{id}` ([reference](https://developer.kustomer.com/api/core-resources/update-kobject-custom-object-by-id))

`GET /v1/customers/{id}/klasses/{name}` ([reference](https://developer.kustomer.com/api/core-resources/find-customer-kobjects-custom-objects))

A typical sync looks up by `externalId`, then creates or updates:

```ts title="Node.js"
async function upsertOrder(customerId: string, order: Order) {
  const body = JSON.stringify({
    title: `Order #${order.number}`,
    externalId: `order-${order.number}`,
    custom: { orderNumberStr: order.number, orderStatusStr: order.status, totalPriceNum: order.total },
  })
  const found = await fetch(`${base}/v1/klasses/ecomm-order/externalId=order-${order.number}`, { headers })
  if (found.status === 404) {
    return fetch(`${base}/v1/customers/${customerId}/klasses/ecomm-order`, { method: 'POST', headers, body })
  }
  const { data } = await found.json()
  return fetch(`${base}/v1/klasses/ecomm-order/${data.id}`, { method: 'PUT', headers, body })
}
```

## Show KObjects to agents

KObjects appear on the customer timeline automatically, using the Klass icon, color, `title` and `description`. For a richer layout, such as a table of line items with a "Track package" button, build a [KView](https://developer.kustomer.com/docs/apps/kviews) for the Klass.

_Figure: An ecomm-order KObject card on a customer timeline with order number, status, total and a tracking link. A KObject on the timeline, rendered with a KView\._

## Limits

- A single client can create up to **120 KObjects per customer per minute**. Records with `importedAt` are exempt.
- Custom string attributes (`Str`) hold up to 1,024 characters.

The end-to-end [orders integration guide](https://developer.kustomer.com/docs/guides/kobject-orders-integration) puts all of this together.
