# Create tracking identity

> POST /v1/tracking/identity · Core resources API

Source: https://developer.kustomer.com/api/core-resources/create-tracking-identity

```http
POST https://{orgname}.api.kustomerapp.com/v1/tracking/identity
Authorization: Bearer <API key>
```

## Authorization

Requires any one of these roles: `org.tracking`. The API key or user must hold at least one of them.

Identifies a user.

## About Tracking events

Tracking events record what a person does in your website or app, such as viewing a page or starting a checkout, grouped into sessions on the customer's event history. Identity calls tie an anonymous visitor to a Kustomer customer.

The tracking endpoints require the `org.tracking` role, the one role a chat key has, so they can be called directly from a customer's browser or app. Each visitor gets a `trackingId`. If you don't send one, Kustomer creates it and, in a browser, stores it in a cookie so later calls from the same visitor reuse it. Events from a visitor who hasn't been identified are anonymous. Once you call an identity endpoint with the visitor's email, phone or `externalId`, Kustomer finds or creates the matching customer, and later events for that `trackingId` are recorded as that customer's events.

The Customers (Events) endpoints are the read side. They need a regular API key with event read access, and return `customer_event` resources from the customer's event history. That history holds tracking events, grouped into sessions, and also records of changes to the customer, such as a `kustomer.customer.update` event whose `changes` lists each attribute's `before` and `after` values.

#### Events

An event has a `name` and optional `meta`. The `name` must start with a letter and use only letters, digits, `-`, `_` and `.`, up to 255 characters; Kustomer stores it with a `tracking.` prefix, so `viewed-pricing` is read back in `trackingEvent` as `tracking.viewed-pricing`. `meta` holds up to 100 properties, typed like [custom attributes](https://developer.kustomer.com/api/core-resources#custom-attributes). Kustomer adds the suffix for you: a number named `cartTotal` is stored as `cartTotalNum`, a string as `…Str` (unless the name already ends in `Str` or `At`), and any other value is stored as JSON text in a `…Txt` property. Events also record the caller's approximate location. Each event belongs to a session (`sessionId`), which Kustomer assigns when you don't provide one.

#### Identities

An identity links a `trackingId` to a customer. Kustomer matches on the `trackingId`, `externalId`, `email` or `phone` you send, then updates the customer with the other fields in the request (`name`, `company`, `username`, `locale`, `timeZone`, `tags`, `custom` and so on); new emails and phone numbers are added to the customer's existing lists. The response is an `identity` with the matched customer in `relationships.customer`. Its `trackingId` can differ from the one you sent if the person was already known, so use the returned value for later events.

#### Which endpoint to use

| To | Call |
| --- | --- |
| Record something a visitor did | [`POST /v1/tracking/event`](https://developer.kustomer.com/api/core-resources/create-tracking-event) |
| Tell Kustomer who the visitor is | [`POST /v1/tracking/identity`](https://developer.kustomer.com/api/core-resources/create-tracking-identity) |
| Identify the visitor and record an event in one call | [`POST /v1/tracking/identityEvent`](https://developer.kustomer.com/api/core-resources/create-tracking-identity-and-track-event) |
| List a customer's tracking sessions | [`GET /v1/customers/{id}/sessions`](https://developer.kustomer.com/api/core-resources/get-all-customer-sessions) |
| Read the events in one session | [`GET /v1/customers/{customerId}/sessions/{sessionId}/events`](https://developer.kustomer.com/api/core-resources/get-all-events-by-customer-for-session) |
| Read one customer event by ID | [`GET /v1/customers/{customerId}/events/{id}`](https://developer.kustomer.com/api/core-resources/get-customer-event) |
| List all of a customer's events (deprecated) | [`GET /v1/customers/{id}/events`](https://developer.kustomer.com/api/core-resources/get-all-customer-events-deprecated) |

`POST /v1/tracking/event` returns `204 No Content`; the identity endpoints return `201` with the identity. Each session in the sessions list has `firstEventAt`, `lastEventAt` and an event `count`. The deprecated all-events endpoint now returns `404 Not Found`: read session events instead, or use [conversation events](https://developer.kustomer.com/api/core-resources/get-conversation-events) for a conversation's history.

Related: [Customers](https://developer.kustomer.com/api/core-resources#customers), [Chat](https://developer.kustomer.com/docs/chat), [API keys and roles](https://developer.kustomer.com/docs/get-started/api-keys-and-roles)

### Recipes

#### 1. Track a visitor, then identify them when they sign in

Record what an anonymous visitor does on your site, then tie those events to their Kustomer customer once you know who they are.

**Step 1.** [`POST /v1/tracking/event`](https://developer.kustomer.com/api/core-resources/create-tracking-event.md). Record each action with a `name` and optional `meta`. Use a key with the `org.tracking` role, such as a chat key, which is safe to use from a browser or app. Send the visitor's `trackingId` if you have one; in a browser Kustomer creates it and keeps it in a cookie when you don't. The response is `204 No Content`.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/tracking/event" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"trackingId\": \"$TRACKING_ID\", \"name\": \"viewed-pricing\", \"meta\": {\"plan\": \"pro\", \"seats\": 5}}"
```

```bash title="kusty"
kusty api POST /v1/tracking/event \
  --field trackingId=$TRACKING_ID --field name=viewed-pricing \
  --field meta.plan=pro --field meta.seats:=5
```

**Step 2.** [`POST /v1/tracking/identity`](https://developer.kustomer.com/api/core-resources/create-tracking-identity.md). When the visitor signs in, send the same `trackingId` with what identifies them: `email`, `phone` or your `externalId`. Kustomer finds or creates the matching customer, returned in `relationships.customer`, and attaches the visitor's earlier events to it. Use the `trackingId` from the response for later events, because it can differ from the one you sent if the person was already known.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/tracking/identity" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"trackingId\": \"$TRACKING_ID\", \"email\": \"$EMAIL\", \"externalId\": \"$USER_ID\", \"name\": \"Jane Doe\"}"
```

```bash title="kusty"
kusty api POST /v1/tracking/identity \
  --field trackingId=$TRACKING_ID --field email=$EMAIL --field externalId=$USER_ID \
  | jq -r '[.data.attributes.trackingId, .data.relationships.customer.data.id] | @tsv'
```

#### 2. Identify a customer and record a purchase in one call

Send a server-side event, such as a completed order, for a person you already know, without a separate identity call.

**Step 1.** [`POST /v1/tracking/identityEvent`](https://developer.kustomer.com/api/core-resources/create-tracking-identity-and-track-event.md). Send `identity` with how to match the customer, such as `externalId` and `email`, plus any profile fields to update, and `event` with the `name` and `meta`. Kustomer matches or creates the customer, updates it, and records the event in its history. The response is the `identity`, with the customer in `relationships.customer`.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/tracking/identityEvent" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "identity": { "externalId": "user-8812", "email": "jane.doe@example.com" },
    "event": { "name": "completed-checkout", "meta": { "orderNumber": "4417", "cartTotal": 64.67 } }
  }'
```

```bash title="kusty"
kusty api POST /v1/tracking/identityEvent --data @checkout-event.json \
  | jq -r '.data.relationships.customer.data.id'
```

> `meta` property names get a type suffix when stored, so `cartTotal` is read back as `cartTotalNum` and `orderNumber` as `orderNumberStr`.

#### 3. See what a customer did in their latest session

Show an agent or your own tool the pages and actions from a customer's most recent visit.

**Step 1.** [`GET /v1/customers/{id}/sessions`](https://developer.kustomer.com/api/core-resources/get-all-customer-sessions.md). List the customer's sessions and pick the one with the latest `lastEventAt`. Each session also has `firstEventAt` and an event `count`; its `sessionId` attribute is what the next call takes.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/customers/$CUSTOMER_ID/sessions" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
SESSION_ID=$(kusty api GET /v1/customers/$CUSTOMER_ID/sessions \
  | jq -r '.data | max_by(.attributes.lastEventAt) | .attributes.sessionId')
```

**Step 2.** [`GET /v1/customers/{customerId}/sessions/{sessionId}/events`](https://developer.kustomer.com/api/core-resources/get-all-events-by-customer-for-session.md). Read the session's events. `trackingEvent` is the name that was sent (with a `tracking.` prefix), `publishedAt` is when it happened, and `meta` holds its properties.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/customers/$CUSTOMER_ID/sessions/$SESSION_ID/events" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/customers/$CUSTOMER_ID/sessions/$SESSION_ID/events \
  | jq -r '.data[] | [.attributes.publishedAt, .attributes.trackingEvent] | @tsv'
```

> These read endpoints need a regular API key with event read access; a tracking-only key can't call them.

### Example object

A real record from [`GET /v1/customers/{customerId}/sessions/{sessionId}/events`](https://developer.kustomer.com/api/core-resources/get-all-events-by-customer-for-session.md):

```json
{
  "type": "customer_event",
  "id": "582911c191113b1900bbee4f",
  "attributes": {
    "name": "kustomer.tracking.identified.event",
    "trackingEvent": "tracking.foobar-event",
    "app": null,
    "publishedAt": "2016-11-14T01:22:09.476Z",
    "createdAt": "2016-11-14T01:31:30.187Z",
    "location": {
      "countryCode": "US",
      "countryName": "United States",
      "regionCode": "NY",
      "cityName": "Huntington",
      "zipCode": "11743",
      "latitude": 40.87190000000001,
      "longitude": -73.4347,
      "areaCode": "631",
      "regionName": "New York"
    },
    "meta": {
      "statusStr": "Silver"
    },
    "sessionId": "58290fb391113b1900bbee4c",
    "realIp": "68.132.72.101"
  },
  "relationships": {
    "org": {
      "links": {
        "self": "/v1/orgs/57bb5d2e32e83a130052e94e"
      },
      "data": {
        "type": "org",
        "id": "57bb5d2e32e83a130052e94e"
      }
    },
    "createdBy": null,
    "modifiedBy": null,
    "customer": {
      "links": {
        "self": "/v1/customers/58290b8b7c7f551a00b5b738"
      },
      "data": {
        "type": "customer",
        "id": "58290b8b7c7f551a00b5b738"
      }
    }
  },
  "links": {
    "self": "/v1/customers/58290b8b7c7f551a00b5b738/events/582911c191113b1900bbee4f"
  }
}
```

Fields:

- `type` (string): `customer_event`, the type of every entry in a customer's event history.
- `attributes.name` (string): For tracking events this is `kustomer.tracking.identified.event`, and the name you sent is in `trackingEvent`. Other entries in the history, such as `kustomer.customer.update`, record changes to the customer.
- `attributes.trackingEvent` (string): The event name you sent, stored with a `tracking.` prefix: `viewed-pricing` is read back as `tracking.viewed-pricing`.
- `attributes.publishedAt` (string): When the event happened. A session's `firstEventAt` and `lastEventAt` are the earliest and latest of these times.
- `attributes.createdAt` (string): When the event was added to the customer's history. For events sent before the visitor was identified, this can be well after `publishedAt`.
- `attributes.location` (object): The approximate location of the caller, worked out by Kustomer. You don't send it.
- `attributes.meta` (object): The `meta` you sent, with a type suffix added to each property name: a string `status` is stored as `statusStr`, a number `cartTotal` as `cartTotalNum`.
- `attributes.sessionId` (string): The session the event belongs to. Kustomer assigns one if you don't send `sessionId`. Read a session's events with `GET /v1/customers/{customerId}/sessions/{sessionId}/events`.
- `attributes.realIp` (string): The IP address the tracking call came from.
- `relationships.customer` (object): The customer the visitor was identified as. Events reach a customer's history only once the visitor is identified.

### Relationships

- Points to **Customers** via `relationships.customer`: The customer whose event history holds this event. A visitor's tracking events are attached to the customer once an identity call ties their `trackingId` to that customer.

### Permissions

Fewest roles for a read-only integration: `org.permission.event.read`. For every endpoint: `org.permission.event.read`, `org.tracking`.

## Request body

Content type: `application/json` (required)

- `remember` (boolean)
- `trackingId` (string)
- `sessionId` (string)
- `name` (string)
- `company` (string)
- `externalId` (string): (max length 256)
- `username` (string): (max length 256)
- `signedUpAt` (string<date-time>)
- `birthdayAt` (string<date-time>)
- `gender` (string): One of: `m`, `f`.
- `locale` (string): (max length 16)
- `timeZone` (string): (max length 64)
- `email` (string<email>)
- `phone` (string<phone-number>)
- `location` (object)
  - `type` (string, nullable): One of: `home`, `work`, `other`.
  - `name` (string, nullable)
  - `address` (string, nullable): (max length 256)
  - `address2` (string, nullable): (max length 256)
  - `address3` (string, nullable): (max length 256)
  - `latitude` (number, nullable)
  - `longitude` (number, nullable)
  - `countryCode` (string, nullable): (min length 2; max length 2)
  - `countryName` (string, nullable): (max length 64)
  - `regionCode` (string, nullable): (max length 2)
  - `regionName` (string, nullable): (max length 128)
  - `cityName` (string, nullable): (max length 128)
  - `zipCode` (string, nullable): (max length 30)
  - `areaCode` (string, nullable): (max length 30)
- `tags` (array<string>): (max items 20; unique items)
- `custom` (object)

Example:

```json
{
  "name": "example_name",
  "externalId": "crm-10293",
  "email": "jane.doe@example.com",
  "phone": "+15555550123",
  "tags": [
    "vip"
  ],
  "custom": {}
}
```

## Responses

### 201

Created

- `data` (object, required)
  - `type` (string, required)
  - `id` (string, required)
  - `attributes` (object, required)
    - `trackingId` (string, required)
    - `email` (string, required)
    - `status` (string, required)
    - `statusAt` (string, required)
    - `createdAt` (string, required)
    - `updatedAt` (string, required)
  - `relationships` (object, required)
    - `org` (object, required)
    - `customer` (object, required)
  - `links` (object, required)
    - `self` (string, required)

```json
{
  "data": {
    "type": "identity",
    "id": "58290b8acca9b0a5e0189626",
    "attributes": {
      "trackingId": "58290b8a91113b1900bbee48",
      "email": "johnsmith@example.com",
      "status": "updated",
      "statusAt": "2016-11-14T00:55:38.947Z",
      "createdAt": "2016-11-14T00:55:38.922Z",
      "updatedAt": "2016-11-14T00:55:38.947Z"
    },
    "relationships": {
      "org": {
        "links": {
          "self": "/v1/orgs/57bb5d2e32e83a130052e94e"
        },
        "data": {
          "type": "org",
          "id": "57bb5d2e32e83a130052e94e"
        }
      },
      "customer": {
        "links": {
          "self": "/v1/customers/58290b8b7c7f551a00b5b738"
        },
        "data": {
          "type": "customer",
          "id": "58290b8b7c7f551a00b5b738"
        }
      }
    },
    "links": {
      "self": "/v1/tracking/identity/58290b8acca9b0a5e0189626"
    }
  }
}
```

### 400

Bad Request

### 401

Unauthorized

### 403

Forbidden

## Example request

```bash
curl --request POST \
  --url 'https://api.kustomerapp.com/v1/tracking/identity' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "example_name",
  "externalId": "crm-10293",
  "email": "jane.doe@example.com",
  "phone": "+15555550123",
  "tags": [
    "vip"
  ],
  "custom": {}
}'
```
