## Messages (`messages`)

In-app messages and announcements; admins publish announcements and tenants read and mark them as read.

Authentication: User · Docs: https://www-demo.kuxitong.com/en/docs/api/messages

### GET `/api/v2/messages`

List messages · Authentication: User (some parameters admin only)

Query parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `page` | integer |  | Page number, starting from 1 Default: 1 |
| `page_size` | integer |  | Items per page Default: 20 |
| `sort` | string |  | Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id` |
| `tenant_id` | integer |  | Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data |
| `type` | string |  | Message type, such as announcement or cert-expire. |
| `site_id` | integer |  | Site ID |

```sh
curl "https://panel.example.com/api/v2/messages" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/messages`

Publish announcement · Authentication: Admin only

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string |  | Message body. |
| `is_bold` | boolean |  | Whether to show the title in bold. |
| `is_external` | boolean |  | When true, clicking jumps to url and url is required; otherwise content is required. |
| `is_popup` | boolean |  | Whether to show it as a pop-up. |
| `is_red` | boolean |  | Whether to show the title in red. |
| `is_show` | boolean |  | Whether the message is visible. |
| `sort` | integer |  | Display order (smaller first). |
| `title` | string | Yes | Message title. |
| `url` | string |  | Link opened on click when is_external is true. |

```sh
curl -X POST "https://panel.example.com/api/v2/messages" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"今晚 23 点维护。","title":"维护通知"}'
```

### POST `/api/v2/messages/read`

Mark messages as read · Authentication: User

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `ids` | integer[] |  | Empty means all messages sent to you. |

```sh
curl -X POST "https://panel.example.com/api/v2/messages/read" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/messages/recent`

Recent unread messages · Authentication: User

Query parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `days` | integer |  | Only messages from the last this many days. Default: 30 |
| `limit` | integer |  | Maximum number of messages to return. Default: 8 |

```sh
curl "https://panel.example.com/api/v2/messages/recent" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/messages/unread-count`

Unread message count · Authentication: User

```sh
curl "https://panel.example.com/api/v2/messages/unread-count" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/messages/{id}`

Get message · Authentication: User (some parameters admin only)

```sh
curl "https://panel.example.com/api/v2/messages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/messages/{id}`

Update message · Authentication: Admin only

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string |  | Message body. |
| `is_bold` | boolean |  | Whether to show the title in bold. |
| `is_external` | boolean |  | When true, clicking jumps to url and url is required; otherwise content is required. |
| `is_popup` | boolean |  | Whether to show it as a pop-up. |
| `is_red` | boolean |  | Whether to show the title in red. |
| `is_show` | boolean |  | Whether the message is visible. |
| `sort` | integer |  | Display order (smaller first). |
| `title` | string |  | Message title. |
| `url` | string |  | Link opened on click when is_external is true. |

```sh
curl -X PUT "https://panel.example.com/api/v2/messages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/messages/{id}`

Delete message · Authentication: Admin only

```sh
curl -X DELETE "https://panel.example.com/api/v2/messages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

Messages object:

| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string |  | Message body. |
| `count` | integer |  | Number of unread messages. |
| `created_at` | string |  | Created at (read-only) |
| `id` | integer |  | Record ID (read-only) |
| `ids` | integer[] |  | Empty means all messages sent to you. |
| `is_bold` | boolean |  | Whether to show the title in bold. |
| `is_external` | boolean |  | When true, clicking jumps to url and url is required; otherwise content is required. |
| `is_popup` | boolean |  | Whether to show it as a pop-up. |
| `is_red` | boolean |  | Whether to show the title in red. |
| `is_show` | boolean |  | Whether the message is visible. |
| `items` | Message[] |  | Items on this page |
| `read` | boolean |  | Whether the message has been read. (read-only) |
| `site_id` | integer |  | Site ID (read-only) |
| `sort` | integer |  | Display order (smaller first). |
| `tenant_id` | integer |  | Recipient tenant; empty for announcements. (read-only) |
| `title` | string |  | Message title. |
| `title_args` | object |  | Arguments of the title key: name → string, number, or a clause {key, args} (a clause is looked up in the dictionary and filled the same way, and may nest). (read-only) |
| `title_key` | string |  | Title key (the Chinese sentence with {name} placeholders). When set, the panel looks it up in the UI-language dictionary and fills the placeholders from title_args; when null (old messages, announcements, edited titles) the panel shows title as is. (read-only) |
| `type` | string |  | announcement = announcement; others are notification types (such as cert-expire, package-expire). (read-only) |
| `updated_at` | string |  | Updated at (read-only) |
| `url` | string |  | Link opened on click when is_external is true. |
