> For the complete documentation index, see [llms.txt](https://docs.api.intratool.de/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.api.intratool.de/api-reference/chat/chat-messages.md).

# ChatMessages

## Introduction

`ChatMessages` are the content of a [ChatConversation](/api-reference/chat/chat-conversations.md). A message has a concrete [type](#types), can contain rich text, require a reading confirmation, or relate to another intratool resource selected from the supported [relatable types](#relatable-types).

The `text` field uses the shared [Rich Text](/introduction/rich-text.md) HTML format.

## Model Definition

**Alias**

`chatMessage`

**Relations**

| Key                | Relation                                                               | Type       | Relation Field(s)                                                         |
| ------------------ | ---------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------- |
| `user`             | [User](/api-reference/users.md)                                        | Belongs to | `user_id`                                                                 |
| `chatConversation` | [ChatConversation](/api-reference/chat/chat-conversations.md)          | Belongs to | `chat_conversation_id`                                                    |
| `language`         | [Language](/api-reference/languages.md)                                | Belongs to | `lang_id`                                                                 |
| `relatable`        | [Relatable](#relatable-types)                                          | Morph to   | `relatable_type`, `relatable_id`                                          |
| `seenUsers`        | [ChatMessageSeenUsers](/api-reference/chat/chat-message-seen-users.md) | Has many   | `chat_message_seen_users.chat_message_id`                                 |
| `reactions`        | [Reactions](/api-reference/reactions.md)                               | Morph many | `reactions.reactable_type`, `reactions.reactable_id`                      |
| `currentReaction`  | [CurrentReaction](/api-reference/reactions.md)                         | Morph one  | `reactions.reactable_type`, `reactions.reactable_id`, `reactions.user_id` |
| `translations`     | [Translations](/api-reference/translations.md)                         | Morph many | `translations.translatable_type`, `translations.translatable_id`          |

**Types**

* `default` - A standard message.
* `voiceMessage` - A voice message.

**Relatable types**

* `chatFile` - Relate a `ChatFile`.
* `chatMessage` - Relate another `ChatMessage`.
* `filemanagerDirectory` - Relate a [FilemanagerDirectory](/api-reference/filemanager/filemanager-directories.md).
* `filemanagerFile` - Relate a [FilemanagerFile](/api-reference/filemanager/filemanager-files.md).
* `form` - Relate a [Form](/api-reference/forms/forms.md).
* `formMessage` - Relate a [FormMessage](/api-reference/forms/form-messages.md).
* `infoboardComment` - Relate an [InfoboardComment](/api-reference/infoboard/infoboard-comments.md).
* `infoboardPost` - Relate an [InfoboardPost](/api-reference/infoboard/infoboard-posts.md).
* `manualChapter` - Relate a [ManualChapter](/api-reference/manual/manual-chapters.md).
* `manualEntry` - Relate a [ManualEntry](/api-reference/manual/manual-entries.md).
* `report` - Relate a `Report`.
* `survey` - Relate a [Survey](/api-reference/surveys/surveys.md).
* `taskAssignment` - Relate a [TaskAssignment](/api-reference/tasks-2/task-assignments.md).
* `taskExecution` - Relate a [TaskExecution](/api-reference/tasks-2/task-executions.md).
* `taskTemplate` - Relate a [TaskTemplate](/api-reference/tasks-2/task-templates.md).
* `taskTemplateComposition` - Relate a `TaskTemplateComposition`.

**Computed Properties**

* `hash` - The hashed `id` of the `ChatMessage`.

**Capabilities**

* [Targetables](/introduction/resource-capabilities/targetables.md) - Message visibility and eligible recipients follow the parent [ChatConversation](/api-reference/chat/chat-conversations.md); messages do not have independent Entity Permissions.
* [URL context](/introduction/resource-capabilities/url-context.md) - Message URLs resolve to access-checked context information.
* [Translations](/introduction/resource-capabilities/translations.md) - The `text` field is translatable.
* [Notifications](/introduction/resource-capabilities/notifications.md) - Creating a message can notify eligible participants who have not muted or archived the conversation; messages requiring confirmation use a dedicated notification type.
* [Reactions](/introduction/resource-capabilities/reactions.md) - Users can add one current emoji reaction and retrieve individual or summarized reactions.
* [Seen and read tracking](/introduction/resource-capabilities/seen-and-read-tracking.md) - The API tracks message visibility and explicit reading confirmations per user.

## List

List `ChatMessages` from conversations available to the current authenticated [User](/api-reference/users.md).

**Definition**

<mark style="color:green;">`GET`</mark> `/api/chat/messages`

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('GET', '/api/chat/messages', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
[
  {
    "id": 1,
    "user_id": 3,
    "chat_conversation_id": 1,
    "forwarded_id": null,
    "lang_id": "en-US",
    "type": "default",
    "relatable_type": null,
    "relatable_id": null,
    "text": "<p>Welcome to the project chat.</p>",
    "reading_confirmation": false,
    "created_at": "2026-08-06 09:35:00",
    "updated_at": "2026-08-06 09:35:00",
    "deleted_at": null,
    "hash": "vkn978r25g37681dqwzem4px"
  },
  {
    "id": 2,
    "user_id": 4,
    "chat_conversation_id": 2,
    "forwarded_id": null,
    "lang_id": "en-US",
    "type": "default",
    "relatable_type": "infoboardPost",
    "relatable_id": 1,
    "text": "<p>Please review the linked announcement.</p>",
    "reading_confirmation": true,
    "created_at": "2026-08-06 09:40:00",
    "updated_at": "2026-08-06 09:40:00",
    "deleted_at": null,
    "hash": "q6n1vx8m4p2kr9dw5e7z0yla"
  }
]
```

## Count

Count `ChatMessages` from conversations available to the current authenticated [User](/api-reference/users.md).

**Definition**

<mark style="color:green;">`GET`</mark> `/api/chat/messages/count`

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('GET', '/api/chat/messages/count', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
1
```

## List by conversation

List `ChatMessages` for a [ChatConversation](/api-reference/chat/chat-conversations.md).

**Definition**

<mark style="color:green;">`GET`</mark> `/api/chat/conversations/{chatConversation}/messages`

**Route Parameters**

| Parameter          | Type                  | Description                  |
| ------------------ | --------------------- | ---------------------------- |
| `chatConversation` | `integer` \| `string` | ChatConversation ID or hash. |

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('GET', '/api/chat/conversations/1/messages', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
[
  {
    "id": 1,
    "user_id": 3,
    "chat_conversation_id": 1,
    "forwarded_id": null,
    "lang_id": "en-US",
    "type": "default",
    "relatable_type": null,
    "relatable_id": null,
    "text": "<p>Welcome to the project chat.</p>",
    "reading_confirmation": false,
    "created_at": "2026-08-06 09:35:00",
    "updated_at": "2026-08-06 09:35:00",
    "deleted_at": null,
    "hash": "vkn978r25g37681dqwzem4px"
  },
  {
    "id": 2,
    "user_id": 4,
    "chat_conversation_id": 1,
    "forwarded_id": null,
    "lang_id": "en-US",
    "type": "default",
    "relatable_type": "infoboardPost",
    "relatable_id": 1,
    "text": "<p>Please review the linked announcement.</p>",
    "reading_confirmation": true,
    "created_at": "2026-08-06 09:40:00",
    "updated_at": "2026-08-06 09:40:00",
    "deleted_at": null,
    "hash": "q6n1vx8m4p2kr9dw5e7z0yla"
  }
]
```

## Count by conversation

Count `ChatMessages` for a [ChatConversation](/api-reference/chat/chat-conversations.md).

**Definition**

<mark style="color:green;">`GET`</mark> `/api/chat/conversations/{chatConversation}/messages/count`

**Route Parameters**

| Parameter          | Type                  | Description                  |
| ------------------ | --------------------- | ---------------------------- |
| `chatConversation` | `integer` \| `string` | ChatConversation ID or hash. |

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('GET', '/api/chat/conversations/1/messages/count', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
1
```

## Show

Show one `ChatMessage` by ID or hash.

**Definition**

<mark style="color:green;">`GET`</mark> `/api/chat/messages/{chatMessage}`

**Route Parameters**

| Parameter     | Type                  | Description             |
| ------------- | --------------------- | ----------------------- |
| `chatMessage` | `integer` \| `string` | ChatMessage ID or hash. |

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('GET', '/api/chat/messages/1', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "id": 1,
  "user_id": 3,
  "chat_conversation_id": 1,
  "forwarded_id": null,
  "lang_id": "en-US",
  "type": "default",
  "relatable_type": null,
  "relatable_id": null,
  "text": "<p>Welcome to the project chat.</p>",
  "reading_confirmation": false,
  "created_at": "2026-08-06 09:35:00",
  "updated_at": "2026-08-06 09:35:00",
  "deleted_at": null,
  "hash": "vkn978r25g37681dqwzem4px"
}
```

## Create

Create a new `ChatMessage`.

**Definition**

<mark style="color:yellow;">`POST`</mark> `/api/chat/messages`

**Request Keys**

| Key                      | Type                | Default         | Description                                                                             |
| ------------------------ | ------------------- | --------------- | --------------------------------------------------------------------------------------- |
| `chat_conversation_id`\* | `integer`           | -               | ID of the related [ChatConversation](/api-reference/chat/chat-conversations.md).        |
| `lang_id`                | `string`            | system language | Language key for the translatable text.                                                 |
| `type`\*                 | `string`            | -               | [Type](#types) of the `ChatMessage`.                                                    |
| `relatable_type`         | `string` \| `null`  | `null`          | [Relatable type](#relatable-types) of the related entity. Required with `relatable_id`. |
| `relatable_id`           | `integer` \| `null` | `null`          | ID of the related entity. Required with `relatable_type`.                               |
| `text`                   | `string` \| `null`  | `null`          | Message content. Required when no related entity is supplied.                           |
| `reading_confirmation`   | `boolean`           | `false`         | Whether users must explicitly confirm that they read the message.                       |

Keys with `*` are required.

**Behavior**

The authenticated user becomes the message author; a client-provided `user_id` is ignored. Messages cannot be created in a locked conversation.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('POST', '/api/chat/messages', [
    'headers' => ['Authorization' => "Bearer {accessToken}"],
    'json' => [
        'chat_conversation_id' => 1,
        'type' => 'default',
        'text' => '<p>Welcome to the project chat.</p>'
    ]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": {
    "id": 1,
    "user_id": 3,
    "chat_conversation_id": 1,
    "forwarded_id": null,
    "lang_id": "en-US",
    "type": "default",
    "relatable_type": null,
    "relatable_id": null,
    "text": "<p>Welcome to the project chat.</p>",
    "reading_confirmation": false,
    "created_at": "2026-08-06 09:35:00",
    "updated_at": "2026-08-06 09:35:00",
    "deleted_at": null,
    "hash": "vkn978r25g37681dqwzem4px"
  }
}
```

## Forward

Forward a `ChatMessage` to another [ChatConversation](/api-reference/chat/chat-conversations.md).

**Definition**

<mark style="color:yellow;">`POST`</mark> `/api/chat/messages/{chatMessage}/forward`

**Route Parameters**

| Parameter     | Type                  | Description                    |
| ------------- | --------------------- | ------------------------------ |
| `chatMessage` | `integer` \| `string` | Source ChatMessage ID or hash. |

**Request Keys**

| Key                      | Type      | Default | Description                                                                     |
| ------------------------ | --------- | ------- | ------------------------------------------------------------------------------- |
| `chat_conversation_id`\* | `integer` | -       | ID of the target [ChatConversation](/api-reference/chat/chat-conversations.md). |

Keys with `*` are required.

**Behavior**

The new message retains the content of the source message, stores the source ID in `forwarded_id`, and uses the authenticated user as its author. Related chat files are copied to the target conversation. The target conversation must be unlocked.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('POST', '/api/chat/messages/1/forward', [
    'headers' => ['Authorization' => "Bearer {accessToken}"],
    'json' => [
        'chat_conversation_id' => 2
    ]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": {
    "id": 2,
    "user_id": 3,
    "chat_conversation_id": 2,
    "forwarded_id": 1,
    "lang_id": "en-US",
    "type": "default",
    "relatable_type": null,
    "relatable_id": null,
    "text": "<p>Welcome to the project chat.</p>",
    "reading_confirmation": false,
    "created_at": "2026-08-06 10:05:00",
    "updated_at": "2026-08-06 10:05:00",
    "deleted_at": null,
    "hash": "yd6er2o0pz12v6lgnw54qmv7"
  }
}
```

## Mark notifications unread

Mark matching [Notifications](/api-reference/notifications.md) for a `ChatMessage` unread for the current authenticated [User](/api-reference/users.md).

**Definition**

<mark style="color:yellow;">`POST`</mark> `/api/chat/messages/{chatMessage}/notifications/unread`

**Route Parameters**

| Parameter     | Type                  | Description             |
| ------------- | --------------------- | ----------------------- |
| `chatMessage` | `integer` \| `string` | ChatMessage ID or hash. |

**Behavior**

* The user must be allowed to view the non-deleted message.
* Every currently read chat notification that targets the message has its `read_at` value cleared. Existing `seen_at` values are preserved, and other notification types are unchanged.
* Repeating the request is idempotent. Response data is the number of notifications changed.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('POST', '/api/chat/messages/1/notifications/unread', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": 1
}
```

## Reset

Reset supported relations of a `ChatMessage`.

**Definition**

<mark style="color:yellow;">`POST`</mark> `/api/chat/messages/{chatMessage}/reset`

**Route Parameters**

| Parameter     | Type                  | Description             |
| ------------- | --------------------- | ----------------------- |
| `chatMessage` | `integer` \| `string` | ChatMessage ID or hash. |

**Request Keys**

| Key         | Type      | Default | Description                                    |
| ----------- | --------- | ------- | ---------------------------------------------- |
| `reactions` | `boolean` | `false` | Set to `true` to remove all message reactions. |

**Behavior**

At least one resettable relation must be set to `true`. Only the conversation owner can reset message relations.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('POST', '/api/chat/messages/1/reset', [
    'headers' => ['Authorization' => "Bearer {accessToken}"],
    'json' => [
        'reactions' => true
    ]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": {
    "id": 1,
    "user_id": 3,
    "chat_conversation_id": 1,
    "forwarded_id": null,
    "lang_id": "en-US",
    "type": "default",
    "relatable_type": null,
    "relatable_id": null,
    "text": "<p>Welcome to the project chat.</p>",
    "reading_confirmation": false,
    "created_at": "2026-08-06 09:35:00",
    "updated_at": "2026-08-06 09:35:00",
    "deleted_at": null,
    "hash": "vkn978r25g37681dqwzem4px"
  }
}
```

## Update

Update an existing `ChatMessage`.

**Definition**

<mark style="color:blue;">`PUT`</mark> `/api/chat/messages/{chatMessage}`

**Route Parameters**

| Parameter     | Type                  | Description             |
| ------------- | --------------------- | ----------------------- |
| `chatMessage` | `integer` \| `string` | ChatMessage ID or hash. |

**Request Keys**

| Key                    | Type                | Description                                                           |
| ---------------------- | ------------------- | --------------------------------------------------------------------- |
| `lang_id`              | `string`            | New language key for the translatable text.                           |
| `type`                 | `string`            | New [type](#types) of the `ChatMessage`.                              |
| `relatable_type`       | `string` \| `null`  | New [relatable type](#relatable-types). Required with `relatable_id`. |
| `relatable_id`         | `integer` \| `null` | New related entity ID. Required with `relatable_type`.                |
| `text`                 | `string` \| `null`  | New message content. Required when no related entity is supplied.     |
| `reading_confirmation` | `boolean`           | Whether users must explicitly confirm that they read the message.     |

**Behavior**

Only the message author can update it, and only within 15 minutes of creation while the conversation is unlocked. `user_id` and `chat_conversation_id` cannot be changed by this endpoint.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('PUT', '/api/chat/messages/1', [
    'headers' => ['Authorization' => "Bearer {accessToken}"],
    'json' => [
        'text' => '<p>Welcome to the project launch chat.</p>'
    ]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": {
    "id": 1,
    "user_id": 3,
    "chat_conversation_id": 1,
    "forwarded_id": null,
    "lang_id": "en-US",
    "type": "default",
    "relatable_type": null,
    "relatable_id": null,
    "text": "<p>Welcome to the project launch chat.</p>",
    "reading_confirmation": false,
    "created_at": "2026-08-06 09:35:00",
    "updated_at": "2026-08-06 09:45:00",
    "deleted_at": null,
    "hash": "vkn978r25g37681dqwzem4px"
  }
}
```

## Delete

Delete an existing `ChatMessage`.

**Definition**

<mark style="color:red;">`DELETE`</mark> `/api/chat/messages/{chatMessage}`

**Route Parameters**

| Parameter     | Type                  | Description             |
| ------------- | --------------------- | ----------------------- |
| `chatMessage` | `integer` \| `string` | ChatMessage ID or hash. |

**Behavior**

Only the message author can delete it while the conversation is unlocked. Deleting a message clears its `text` before soft deletion.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('DELETE', '/api/chat/messages/1', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": null
}
```
