# Get notes

> GET /v1/notes · Core resources API

Source: https://developer.kustomer.com/api/core-resources/get-notes

```http
GET https://{orgname}.api.kustomerapp.com/v1/notes
Authorization: Bearer <API key>
```

## Authorization

Requires any one of these roles: `org.permission.note.read`; or legacy `org.user.note.read`. The API key or user must hold at least one of them. Legacy roles predate permission sets and still work.

Retrieves all [notes](https://help.kustomer.com/using-notes-HJvDjNP58) for a Kustomer organization.

## About Notes

A note is an internal comment that your team leaves on a conversation. Customers never see notes; agents use them to hand off context, record what they checked, and @mention teammates.

In the agent desktop, notes appear in a conversation's thread next to its [messages](https://developer.kustomer.com/api/core-resources#messages) but are styled as internal and are never sent to the customer. Every note belongs to one [conversation](https://developer.kustomer.com/api/core-resources#conversations), and through it to that conversation's customer, so you can read notes per conversation or across everything you know about a customer. Agents write notes by hand; integrations and workflows use them to drop in context such as an order lookup result or a fraud check, without the customer seeing it.

Notes attach to conversations. Internal comments on custom objects, such as a task or an order, are a separate resource called [comments](https://developer.kustomer.com/api/core-resources#comments).

#### Key fields

| Field | Meaning |
| --- | --- |
| `body` | The note text, 1 to 10,240 characters. Required. |
| `conversation` | The conversation the note belongs to. Required when you create a note with `POST /v1/notes` or in bulk; the customer comes from the conversation. |
| `userMentions` | Up to 20 `{ user }` or `{ team }` entries. Mentioned users are notified, the same as an @mention typed in the agent desktop. |
| `attachments` | Files uploaded beforehand with [`POST /v1/attachments`](https://developer.kustomer.com/api/core-resources/create-attachment), passed as `{ _id, name, contentType, contentLength }`. |
| `externalId` | Your own ID for the note, up to 256 characters. |

The conversation's `noteCount` tracks how many notes it has. An unsent note is a different object: a [draft](https://developer.kustomer.com/api/core-resources#drafts) with `channel: "note"`, limited to one per conversation.

#### Which endpoint to use

| To | Call |
| --- | --- |
| Add a note to a conversation | [`POST /v1/conversations/{id}/notes`](https://developer.kustomer.com/api/core-resources/create-note-within-conversation), or [`POST /v1/notes`](https://developer.kustomer.com/api/core-resources/create-note) with `conversation` in the body |
| Read, edit or delete a note | [`GET`](https://developer.kustomer.com/api/core-resources/get-note-by-id), [`PUT`](https://developer.kustomer.com/api/core-resources/update-note-by-id), [`PATCH`](https://developer.kustomer.com/api/core-resources/update-note-attributes-by-id) or [`DELETE /v1/notes/{id}`](https://developer.kustomer.com/api/core-resources/delete-note-by-id) |
| List a conversation's notes | [`GET /v1/conversations/{id}/notes`](https://developer.kustomer.com/api/core-resources/get-notes-by-conversation) |
| List every note about a customer | [`GET /v1/customers/{id}/notes`](https://developer.kustomer.com/api/core-resources/get-notes-by-customer-id) |
| Page through all notes | [`GET /v1/notes`](https://developer.kustomer.com/api/core-resources/get-notes) |
| Import or update up to 100 notes per request | [`POST`](https://developer.kustomer.com/api/core-resources/bulk-create-notes) or [`PUT /v1/notes/bulk`](https://developer.kustomer.com/api/core-resources/bulk-batch-update-notes) |

A client can create 120 notes per customer per minute. Only tokens with the `org.admin` role can set `createdAt`, `createdBy`, `modifiedAt` and `modifiedBy`, which you need when importing history so notes keep their original author and time. `PUT` merges your changes unless you add `replace=true`, in which case `conversation` and `body` are both required. Bulk jobs run asynchronously; see [Bulk operations](https://developer.kustomer.com/docs/guides/bulk-operations).

Related: [Conversations](https://developer.kustomer.com/api/core-resources#conversations), [Messages](https://developer.kustomer.com/api/core-resources#messages), [Comments on custom objects](https://developer.kustomer.com/api/core-resources#comments), [Conversations and messages](https://developer.kustomer.com/docs/concepts/conversations-and-messages)

### Recipes

#### 1. Add an internal note and @mention a teammate

Hand off context on a conversation, such as a fraud check result or an escalation reason, and notify the person who needs to act on it.

**Step 1.** [`GET /v1/users`](https://developer.kustomer.com/api/access-management/get-users.md). Mentions take user or team IDs, not names. Find the user by email and keep their `id`.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/users?email=$TEAMMATE_EMAIL" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/users --query email=$TEAMMATE_EMAIL | jq -r '.data[0].id'
```

**Step 2.** [`POST /v1/conversations/{id}/notes`](https://developer.kustomer.com/api/core-resources/create-note-within-conversation.md). Post the note on the conversation. `body` is required and up to 10,240 characters. `userMentions` takes up to 20 entries, each `{ "user": … }` or `{ "team": … }`, and mentioned users are notified just as if an agent had typed the @mention. The customer never sees the note.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/conversations/$CONVERSATION_ID/notes" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"body\": \"Fraud check flagged this order (score 0.91). Please verify the shipping address before refunding.\", \"userMentions\": [{\"user\": \"$USER_ID\"}]}"
```

```bash title="kusty"
kusty api POST /v1/conversations/$CONVERSATION_ID/notes \
  --field body="Fraud check flagged this order (score 0.91). Please verify the shipping address before refunding." \
  --field userMentions.0.user=$USER_ID
```

> To mention a whole team, look it up with [`GET /v1/teams`](https://developer.kustomer.com/api/access-management/get-teams) and send `{ "team": "<team id>" }`. To attach a file, upload it first and pass it in `attachments`; see [Attachments](https://developer.kustomer.com/api/core-resources#attachments).

#### 2. Post an integration note once per event

Drop the result of a lookup, such as an order status or a CRM summary, into a conversation without repeating it when your webhook handler is retried.

**Step 1.** [`GET /v1/conversations/{id}/notes`](https://developer.kustomer.com/api/core-resources/get-notes-by-conversation.md). There's no lookup by a note's `externalId`, so list the conversation's notes and check whether one already carries your event ID.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/conversations/$CONVERSATION_ID/notes?pageSize=100" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/conversations/$CONVERSATION_ID/notes --all \
  | jq -r --arg ref "$EVENT_ID" 'select(.data.attributes.externalId == $ref) | .data.id'
```

**Step 2.** [`POST /v1/conversations/{id}/notes`](https://developer.kustomer.com/api/core-resources/create-note-within-conversation.md). If nothing matched, create the note with your event ID as `externalId` (up to 256 characters), so the next retry finds it.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/conversations/$CONVERSATION_ID/notes" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"externalId\": \"$EVENT_ID\", \"body\": \"Order 4417: shipped 2 days ago via UPS, tracking 1Z999AA10123456784.\"}"
```

```bash title="kusty"
kusty api POST /v1/conversations/$CONVERSATION_ID/notes \
  --field externalId=$EVENT_ID \
  --field body="Order 4417: shipped 2 days ago via UPS, tracking 1Z999AA10123456784."
```

> A client can create 120 notes per customer per minute. If your integration can fire many times for one customer, batch the results into a single note.

#### 3. Export every note about a customer

Pull all internal notes across a customer's conversations, for an account review, a handover to another team or a data request.

**Step 1.** [`GET /v1/customers/{id}/notes`](https://developer.kustomer.com/api/core-resources/get-notes-by-customer-id.md). Page through the customer's notes. Each one has `relationships.conversation` and `relationships.createdBy`, so you can group by conversation and show the author.

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

```bash title="kusty"
kusty api GET /v1/customers/$CUSTOMER_ID/notes --all > notes.jsonl
```

**Step 2.** Write one CSV row per note. Authors are user IDs; resolve them with [`GET /v1/users/{id}`](https://developer.kustomer.com/api/access-management/get-user-by-id) and cache the names.

```bash title="kusty"
jq -r '[.data.attributes.createdAt, .data.relationships.conversation.data.id,
        .data.relationships.createdBy.data.id, .data.attributes.body] | @csv' notes.jsonl > notes.csv
```

> Notes can be deleted with [`DELETE /v1/notes/{id}`](https://developer.kustomer.com/api/core-resources/delete-note-by-id). Messages can't, so for a full data request also list the customer's [messages](https://developer.kustomer.com/api/core-resources/get-messages-by-customer-id).

### Example object

A real record from [`GET /v1/notes/{id}`](https://developer.kustomer.com/api/core-resources/get-note-by-id.md):

```json
{
  "type": "note",
  "id": "57cf1d65079e780006e34f79",
  "attributes": {
    "body": "Hey",
    "createdAt": "2016-09-06T19:47:49.235Z",
    "updatedAt": "2016-09-06T19:47:49.236Z"
  },
  "relationships": {
    "org": {
      "links": {
        "self": "/v1/orgs/57bb5d2e32e83a130052e94e"
      },
      "data": {
        "type": "org",
        "id": "57bb5d2e32e83a130052e94e"
      }
    },
    "customer": {
      "links": {
        "self": "/v1/customers/57c08ccde595371400462df2"
      },
      "data": {
        "type": "customer",
        "id": "57c08ccde595371400462df2"
      }
    },
    "createdBy": {
      "links": {
        "self": "/v1/users/57bb5d2e32e83a130052e94f"
      },
      "data": {
        "type": "user",
        "id": "57bb5d2e32e83a130052e94f"
      }
    },
    "conversation": {
      "links": {
        "self": "/v1/conversations/57ce17d2369f251400fc8e89"
      },
      "data": {
        "type": "conversation",
        "id": "57ce17d2369f251400fc8e89"
      }
    }
  },
  "links": {
    "self": "/v1/notes/57cf1d65079e780006e34f79"
  }
}
```

Fields:

- `attributes.body` (string): The note text, 1 to 10,240 characters. Required. Agents see it in the conversation thread, styled as internal; the customer never does.
- `attributes.createdAt` (string): When the note was written. Only tokens with the `org.admin` role can set it, which you need when importing old notes so they keep their original time.
- `relationships.customer` (object): The customer the note is about. Kustomer copies it from the conversation, so you never set it yourself.
- `relationships.createdBy` (object): The note's author. It's the user or API key that created it, unless an `org.admin` token set `createdBy` during an import.
- `relationships.conversation` (object): The conversation the note belongs to. Required when you create a note with `POST /v1/notes` or in bulk.

### Relationships

- Points to **Customers** via `relationships.customer`: The customer a note is about, taken from its conversation. List every note about a customer with `GET /v1/customers/{id}/notes`.
- Points to **Conversations** via `relationships.conversation`: The conversation a note is left on. Every note belongs to one conversation, which counts its notes in `noteCount`.

### Permissions

Fewest roles for a read-only integration: `org.permission.note.read`. For every endpoint: `org.permission.note.read`, `org.permission.note.create`, `org.permission.note.update`, `org.permission.note.delete`.

### Events

Workflow triggers:

- `kustomer.note.create` (Note Created): An agent or workflow adds a note
- `kustomer.note.update` (Note Updated): A note is edited

Workflow actions:

- `kustomer.note.create` (Note: Create): required inputs `conversation`, `body`
- `kustomer.note.update` (Note: Update): required inputs `id`
- `kustomer.note.find-by-id` (Note: Lookup (By ID)): required inputs `id`
- `kustomer.note.find-by-external` (Note: Lookup (By External ID)): required inputs `identifier`

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `page` | integer | no | Page number of results to return. |
| `pageSize` | integer | no | Number of results to return per page. |
| `sort` | string | no | Sort direction for results. |

## Responses

### 200

OK

- `meta` (object, required)
  - `pageSize` (integer, required)
  - `page` (integer, required)
- `data` (array<object>, required)
  - `type` (string, required)
  - `id` (string, required)
  - `attributes` (object, required)
    - `body` (string, required)
    - `createdAt` (string, required)
    - `updatedAt` (string, required)
  - `relationships` (object, required)
    - `org` (object, required)
    - `customer` (object, required)
    - `createdBy` (object, required)
    - `conversation` (object, required)
  - `links` (object, required)
    - `self` (string, required)
- `links` (object, required)
  - `self` (string, required)
  - `first` (string, required)
  - `prev` (string, required, nullable)
  - `next` (string, required, nullable)

```json
{
  "meta": {
    "pageSize": 100,
    "page": 1
  },
  "data": [
    {
      "type": "note",
      "id": "57cf1d65079e780006e34f79",
      "attributes": {
        "body": "Hey",
        "createdAt": "2016-09-06T19:47:49.235Z",
        "updatedAt": "2016-09-06T19:47:49.236Z"
      },
      "relationships": {
        "org": {
          "links": {
            "self": "/v1/orgs/57bb5d2e32e83a130052e94e"
          },
          "data": {
            "type": "org",
            "id": "57bb5d2e32e83a130052e94e"
          }
        },
        "customer": {
          "links": {
            "self": "/v1/customers/57c08ccde595371400462df2"
          },
          "data": {
            "type": "customer",
            "id": "57c08ccde595371400462df2"
          }
        },
        "createdBy": {
          "links": {
            "self": "/v1/users/57bb5d2e32e83a130052e94f"
          },
          "data": {
            "type": "user",
            "id": "57bb5d2e32e83a130052e94f"
          }
        },
        "conversation": {
          "links": {
            "self": "/v1/conversations/57ce17d2369f251400fc8e89"
          },
          "data": {
            "type": "conversation",
            "id": "57ce17d2369f251400fc8e89"
          }
        }
      },
      "links": {
        "self": "/v1/notes/57cf1d65079e780006e34f79"
      }
    }
  ],
  "links": {
    "self": "/v1/notes?sort=asc&page=1&pageSize=100",
    "first": "/v1/notes?sort=asc&page=1&pageSize=100",
    "prev": null,
    "next": null
  }
}
```

### 401

Unauthorized

### 403

Forbidden

## Example request

```bash
curl --request GET \
  --url 'https://api.kustomerapp.com/v1/notes' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```
