# Flutter 心跳接口对接

## 1. APP 心跳

### 接口地址

```http
POST /api/v1/app/heartbeat
Authorization: Bearer <access_token>
```

### 参数

Body 不需要传参数。

Header：

| 字段 | 必填 | 说明 |
| --- | --- | --- |
| `Authorization` | 是 | 登录 token。 |
| `X-Device-ID` | 否 | 设备 ID；有就传，服务端只做会话审计。 |

### 返回值

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_xxx",
  "data": {
    "accepted": true,
    "heartbeat_at_ms": 1778000005000,
    "server_time_ms": 1778000005000
  }
}
```

| 字段 | 说明 |
| --- | --- |
| `data.accepted` | 是否接受本次 APP 心跳。 |
| `data.heartbeat_at_ms` | 本次 APP 心跳写入时间，UTC epoch milliseconds。 |
| `data.server_time_ms` | 服务端时间，UTC epoch milliseconds。 |

相关 IM：无。

## 2. 房间心跳

### 接口地址

```http
POST /api/v1/rooms/heartbeat
Authorization: Bearer <access_token>
Content-Type: application/json
```

### 参数

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `room_id` | string | 是 | 房间 ID。 |
| `command_id` | string | 是 | 本次心跳命令 ID。同一次请求重试复用同一个值，下一次心跳换新的值。 |

请求示例：

```json
{
  "room_id": "lalu_xxx",
  "command_id": "cmd_room_heartbeat_lalu_xxx_123_001"
}
```

### 返回值

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_xxx",
  "data": {
    "result": {
      "applied": true,
      "room_version": 18,
      "server_time_ms": 1778000005000
    },
    "user": {
      "user_id": 123,
      "role": "audience",
      "joined_at_ms": 1778000000000,
      "last_seen_at_ms": 1778000005000
    },
    "room": {
      "room_id": "lalu_xxx",
      "version": 18,
      "online_users": []
    }
  }
}
```

| 字段 | 说明 |
| --- | --- |
| `data.result.applied` | 本次心跳是否写入成功。 |
| `data.result.room_version` | 房间版本。 |
| `data.user.last_seen_at_ms` | 当前用户房间 presence 最近刷新时间。 |
| `data.room` | 刷新后的房间快照。 |

相关 IM：无。房间心跳只刷新 room-service presence，不会广播独立 IM。

## 3. 麦位心跳

### 接口地址

```http
POST /api/v1/rooms/mic/heartbeat
Authorization: Bearer <access_token>
Content-Type: application/json
```

### 参数

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `room_id` | string | 是 | 房间 ID。 |
| `command_id` | string | 是 | 本次麦位心跳命令 ID。同一次请求重试复用同一个值，下一次心跳换新的值。 |
| `mic_session_id` | string | 是 | 当前麦位会话 ID，必须使用上麦返回的 `mic_session_id`。 |
| `target_user_id` | int64 | 否 | 传 `0` 或不传表示当前登录用户自己。 |

请求示例：

```json
{
  "room_id": "lalu_xxx",
  "command_id": "cmd_mic_heartbeat_lalu_xxx_123_001",
  "mic_session_id": "mic_xxx",
  "target_user_id": 0
}
```

### 返回值

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_xxx",
  "data": {
    "result": {
      "applied": true,
      "room_version": 18,
      "server_time_ms": 1778000005000
    },
    "seat_no": 1,
    "mic_heartbeat_at_ms": 1778000005000,
    "room": {
      "room_id": "lalu_xxx",
      "version": 18,
      "mic_seats": [
        {
          "seat_no": 1,
          "user_id": 123,
          "publish_state": "publishing",
          "mic_session_id": "mic_xxx",
          "mic_heartbeat_at_ms": 1778000005000
        }
      ]
    }
  }
}
```

| 字段 | 说明 |
| --- | --- |
| `data.seat_no` | 当前用户所在麦位。 |
| `data.mic_heartbeat_at_ms` | 服务端接受本次麦位心跳的时间，UTC epoch milliseconds。 |
| `data.room` | 刷新后的房间快照。 |
| `data.room.mic_seats[].mic_heartbeat_at_ms` | 麦位最近一次服务端接受心跳的时间。 |
| `data.room.mic_seats[].publish_state` | `publishing` 表示当前会话已确认发流，可以继续麦位心跳。 |

相关 IM：无独立心跳 IM。收到 `room_mic_down` 后停止麦位心跳。
