# Quickstart

> Create an API key, verify it, create a customer, open a conversation and add a message, in about five minutes.

Source: https://developer.kustomer.com/docs/get-started/quickstart

This quickstart walks through the calls nearly every integration makes: check who you are, create a customer, open a conversation for them, and add a message. You need admin access to a Kustomer org. Use a sandbox org if you have one.

## 1. Create an API key

#### Open API keys

In Kustomer, go to **Settings › Security › API Keys** and select **Add API Key**.

#### Name the key and pick roles

Give it a name like `quickstart`. For this tutorial, add these roles:
`org.permission.customer.create`, `org.permission.customer.read`, `org.permission.conversation.create` and `org.permission.message.create`.
Roles can't be changed after creation, so pick what your integration needs. See [API keys and roles](https://developer.kustomer.com/docs/get-started/api-keys-and-roles).

#### Copy the token

Set an expiry (or none) and, optionally, a CIDR IP restriction. Then create the key and copy the token. **Kustomer only shows it once.**

Store the token and your org name in environment variables. Your org name is the subdomain you use to sign in: for `acme.kustomerapp.com`, it's `acme`.

```bash title="Shell"
export KUSTOMER_API_KEY="eyJhbGciOi..."
export KUSTOMER_ORG="acme"
```

> **Treat API keys like passwords:** A key acts as a machine user with the roles you gave it. Keep keys in a secrets manager, never in client-side code or source control. Keys can't be edited, so rotate them by creating a new key and deleting the old one.

## 2. Verify the key

Ask the API which token you're using. This works with any valid key, whatever its roles.

`GET /v1/auth/tokens/current` ([reference](https://developer.kustomer.com/api/access-management/get-current-auth-token))

```bash title="cURL"
curl "https://$KUSTOMER_ORG.api.kustomerapp.com/v1/auth/tokens/current" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY"
```

```ts title="Node.js"
const base = `https://${process.env.KUSTOMER_ORG}.api.kustomerapp.com`
const headers = { Authorization: `Bearer ${process.env.KUSTOMER_API_KEY}`, 'Content-Type': 'application/json' }

const res = await fetch(`${base}/v1/auth/tokens/current`, { headers })
console.log(res.status, await res.json())
```

```python title="Python"
import os, requests

base = f"https://{os.environ['KUSTOMER_ORG']}.api.kustomerapp.com"
headers = {"Authorization": f"Bearer {os.environ['KUSTOMER_API_KEY']}"}

res = requests.get(f"{base}/v1/auth/tokens/current", headers=headers)
print(res.status_code, res.json())
```

```bash title="kusty"
kusty api GET /v1/auth/tokens/current
```

A `200` response describes the token, including its roles and the machine user behind it:

```json title="200 OK"
{
  "data": {
    "type": "auth_token",
    "id": "5822276811e88a1000787abe",
    "attributes": {
      "name": "quickstart",
      "lastTokenChars": "xyz123",
      "roles": ["org.permission.customer.create", "org.permission.customer.read", "..."]
    },
    "relationships": {
      "org": { "data": { "type": "org", "id": "57f29863a1dbf61100e6aa92" } },
      "user": { "data": { "type": "user", "id": "58190b991f2932100010d683" } }
    }
  }
}
```

If you get `401`, check that the header reads `Bearer`, a space, then the token, and that you're using your org's host. See [Errors](https://developer.kustomer.com/docs/concepts/errors).

## 3. Create a customer

Customers are the center of the data model. Give each one an `externalId` that matches the ID in your own system so you can find them again without storing Kustomer IDs.

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

```bash title="cURL"
curl -X POST "https://$KUSTOMER_ORG.api.kustomerapp.com/v1/customers" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Doe",
    "externalId": "crm-10293",
    "emails": [{ "type": "home", "email": "jane.doe@example.com" }],
    "tags": ["quickstart"]
  }'
```

```ts title="Node.js"
const customer = await fetch(`${base}/v1/customers`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    name: 'Jane Doe',
    externalId: 'crm-10293',
    emails: [{ type: 'home', email: 'jane.doe@example.com' }],
    tags: ['quickstart'],
  }),
}).then((r) => r.json())

const customerId = customer.data.id
```

```python title="Python"
customer = requests.post(f"{base}/v1/customers", headers=headers, json={
    "name": "Jane Doe",
    "externalId": "crm-10293",
    "emails": [{"type": "home", "email": "jane.doe@example.com"}],
    "tags": ["quickstart"],
}).json()

customer_id = customer["data"]["id"]
```

```bash title="kusty"
kusty api POST /v1/customers --data '{
  "name": "Jane Doe",
  "externalId": "crm-10293",
  "emails": [{ "type": "home", "email": "jane.doe@example.com" }],
  "tags": ["quickstart"]
}'
```

Requests send plain JSON attributes. Responses come back wrapped in a `data` envelope with `type`, `id`, `attributes` and `relationships`. [Request and response format](https://developer.kustomer.com/docs/concepts/json-api-format) explains the envelope.

```json title="201 Created"
{
  "data": {
    "type": "customer",
    "id": "5822a4a5aa5f92110005d69a",
    "attributes": {
      "name": "Jane Doe",
      "displayName": "Jane Doe",
      "externalId": "crm-10293",
      "emails": [{ "email": "jane.doe@example.com", "verified": false, "type": "home" }],
      "tags": ["quickstart"],
      "createdAt": "2026-10-21T14:02:11.925Z"
    },
    "links": { "self": "/v1/customers/5822a4a5aa5f92110005d69a" }
  }
}
```

## 4. Open a conversation

`POST /v1/customers/{id}/conversations` ([reference](https://developer.kustomer.com/api/core-resources/create-conversation-for-customer))

```bash title="cURL"
curl -X POST "https://$KUSTOMER_ORG.api.kustomerapp.com/v1/customers/$CUSTOMER_ID/conversations" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Where is my order?", "status": "open", "priority": 3, "tags": ["quickstart"] }'
```

`priority` runs from 1 to 5 and `status` is `open` or `done` on create. Copy `data.id` from the response.

## 5. Add a message

Messages carry the actual communication. `channel` and `app` are required: `channel` is the medium, and `app` identifies the integration that produced the message. The text goes in `preview`.

`POST /v1/conversations/{id}/messages` ([reference](https://developer.kustomer.com/api/core-resources/create-message-from-conversation))

```bash title="cURL"
curl -X POST "https://$KUSTOMER_ORG.api.kustomerapp.com/v1/conversations/$CONVERSATION_ID/messages" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "chat",
    "app": "quickstart",
    "direction": "in",
    "preview": "Hi! My order #4417 has not arrived yet."
  }'
```

Open the customer in Kustomer: the conversation and message are on their timeline.

_Figure: Kustomer agent workspace showing Jane Doe's timeline with the new conversation and inbound chat message. The customer timeline after the quickstart calls._

## Next steps

- [Making requests](https://developer.kustomer.com/docs/get-started/making-requests): Headers, methods, update semantics and idempotency.
- [Data model](https://developer.kustomer.com/docs/concepts/data-model): How every object relates, with an interactive map.
- [Sync from a CRM](https://developer.kustomer.com/docs/guides/sync-customers-from-crm): Turn these calls into a production sync.
