# Update note attributes by ID

> PATCH /v1/notes/{id} · Core resources API

Source: https://developer.kustomer.com/api/core-resources/update-note-attributes-by-id

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

## Authorization

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

Updates one or more note attributes based on the unique note ID.

### Note
> This endpoint is subject to Object Rate Limiting, which limits how many updates single user can make to a single note. To learn more, see [Rate limiting](https://developer.kustomer.com/docs/concepts/rate-limits).

### Authorization
> The `org.admin` role is required for setting `createdAt`, `createdBy`, `modifiedAt`, and `modifiedBy`.  Otherwise, these attributes are automatically set by the token.

## 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`

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Unique note ID. |

## Request body

Content type: `application/json` (required)

- `conversation` (string)
- `externalId` (string, nullable): (max length 256)
- `body` (string): (min length 1; max length 10240)
- `userMentions` (array<object>)
  - `user` (string)
  - `team` (string)
- `deleted` (boolean, nullable)
- `attachments` (array<attachment>): (unique items)
  - `_id` (string<object-id>, required)
  - `name` (string, required)
  - `contentType` (string, required)
  - `contentLength` (number, required)
  - `sourceId` (string<object-id>)
- `createdAt` (string<date-time>)
- `modifiedAt` (string<date-time>)
- `updatedAt` (string<date-time>)
- `createdBy` (string<object-id>)
- `modifiedBy` (string<object-id>, nullable)
- `lang` (string, nullable): (max length 100)

Example:

```json
{
  "conversation": "string",
  "externalId": "crm-10293",
  "body": "Example text",
  "userMentions": [
    {
      "user": "65f2c0a1b4e3d2001234abcd",
      "team": "string"
    }
  ],
  "deleted": true,
  "attachments": [
    {
      "_id": "65f2c0a1b4e3d2001234abcd",
      "name": "example_name",
      "contentType": "application/pdf",
      "contentLength": 0
    }
  ]
}
```

## Responses

### 200

OK

- `data` (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)
    - `userMentions` (object, required)
  - `links` (object, required)
    - `self` (string, required)

```json
{
  "data": {
    "type": "note",
    "id": "57cf1d65079e780006e34f79",
    "attributes": {
      "body": "Hey Agent Smith, do you know the answer to this problem?",
      "createdAt": "2016-09-06T19:47:49.235Z",
      "updatedAt": "2016-11-13T17:50:09.477Z"
    },
    "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"
        }
      },
      "userMentions": {
        "data": [
          {
            "type": "user",
            "id": "570690cb8f17df14005fc527"
          }
        ]
      }
    },
    "links": {
      "self": "/v1/notes/57cf1d65079e780006e34f79"
    }
  }
}
```

### 400

Bad Request

### 401

Unauthorized

### 403

Forbidden

### 404

Not Found

## Example request

```bash
curl --request PATCH \
  --url 'https://api.kustomerapp.com/v1/notes/57cf1d65079e780006e34f79' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "conversation": "string",
  "externalId": "crm-10293",
  "body": "Example text",
  "userMentions": [
    {
      "user": "65f2c0a1b4e3d2001234abcd",
      "team": "string"
    }
  ],
  "deleted": true,
  "attachments": [
    {
      "_id": "65f2c0a1b4e3d2001234abcd",
      "name": "example_name",
      "contentType": "application/pdf",
      "contentLength": 0
    }
  ]
}'
```
