> ## Documentation Index
> Fetch the complete documentation index at: https://docs.insforge.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 即時API參考

> 管理即時通道、檢查訊息歷程記錄，並使用原始Socket.IO發佈/訂閱。

## 概述

即時有兩個接口：

* **REST API**用於通道管理、訊息歷程記錄、交付統計、權限和保留設定。
* **Socket.IO**用於即時訂閱、發佈、呈現和交付事件。

<Note>
  REST API不會串流訊息。使用Socket.IO連線或[TypeScript SDK](/sdks/typescript/realtime)取得即時事件。
</Note>

## 驗証

管理員REST端點需要專案管理員權杖或API金鑰。

```bash theme={null}
Authorization: Bearer <project-admin-jwt-or-ik_api_key>
Content-Type: application/json
```

您也可以使用以下方式傳遞API金鑰：

```bash theme={null}
X-API-Key: <ik_api_key>
```

Socket.IO連線透過Socket.IO`auth`物件進行驗証：

```javascript theme={null}
const socket = io('https://your-app.insforge.app', {
  auth: {
    token: '<user-jwt-or-anon-token>'
  }
});
```

伺服器/管理員用戶端可以傳遞API金鑰：

```javascript theme={null}
const socket = io('https://your-app.insforge.app', {
  auth: {
    apiKey: '<ik_api_key>'
  }
});
```

## Socket.IO發佈/訂閱

在不使用InsForge SDK時安裝Socket.IO用戶端：

```bash theme={null}
npm install socket.io-client
```

### 連線和訂閱

```javascript theme={null}
import { io } from 'socket.io-client';

const socket = io('https://your-app.insforge.app', {
  auth: {
    token: '<user-jwt-or-anon-token>'
  }
});

socket.emit('realtime:subscribe', { channel: 'order:123' }, (response) => {
  if (response.ok) {
    console.log('Subscribed:', response.channel);
    console.log('Presence:', response.presence.members);
  } else {
    console.error(response.error.code, response.error.message);
  }
});
```

### 聆聽事件

```javascript theme={null}
socket.on('status_changed', (message) => {
  console.log(message.status);
  console.log(message.meta.messageId);
  console.log(message.meta.senderType);
});

socket.on('presence:join', (message) => {
  console.log('Joined:', message.member);
});

socket.on('presence:leave', (message) => {
  console.log('Left:', message.member);
});

socket.on('realtime:error', (error) => {
  console.error(error.channel, error.code, error.message);
});
```

### 發佈

```javascript theme={null}
socket.emit('realtime:publish', {
  channel: 'order:123',
  event: 'customer_viewed',
  payload: {
    viewedAt: new Date().toISOString()
  }
});
```

<Warning>
  通訊端必須成功訂閱通道，才能發佈至該通道。
</Warning>

### 取消訂閱

```javascript theme={null}
socket.emit('realtime:unsubscribe', { channel: 'order:123' });
socket.disconnect();
```

### 通訊端事件

| 事件                     | 方向      | 說明                        |
| ---------------------- | ------- | ------------------------- |
| `realtime:subscribe`   | 用戶端至伺服器 | 訂閱通道。確認傳回成功/錯誤和呈現快照。      |
| `realtime:unsubscribe` | 用戶端至伺服器 | 離開通道。                     |
| `realtime:publish`     | 用戶端至伺服器 | 將使用者訊息插入即時管道。             |
| Custom event name      | 伺服器至用戶端 | 已交付的訊息，在訊息`eventName`下發出。 |
| `presence:join`        | 伺服器至用戶端 | 邏輯成員在通道中出現。               |
| `presence:leave`       | 伺服器至用戶端 | 邏輯成員不再在通道中。               |
| `realtime:error`       | 伺服器至用戶端 | 訂閱或發佈失敗。                  |

## 通道模式

在用戶端訂閱之前建立通道定義。

| 模式                | 相符                       |
| ----------------- | ------------------------ |
| `orders`          | `orders`                 |
| `order:%`         | `order:123`, `order:456` |
| `chat:%:messages` | `chat:room-1:messages`   |

模式相符使用SQL`LIKE`，因此`%`是萬用字元。`_`在通道模式中不被接受，因為它也是SQL萬用字元。

## 通道

### 列出通道

```http theme={null}
GET /api/realtime/channels
```

```bash theme={null}
curl "https://your-app.insforge.app/api/realtime/channels" \
  -H "Authorization: Bearer <project-admin-jwt-or-ik_api_key>"
```

回應：

```json theme={null}
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "pattern": "order:%",
    "description": "Order updates",
    "webhookUrls": ["https://example.com/webhook"],
    "enabled": true,
    "createdAt": "2026-04-25T17:00:00.000Z",
    "updatedAt": "2026-04-25T17:00:00.000Z"
  }
]
```

### 建立通道

```http theme={null}
POST /api/realtime/channels
```

請求本文：

| 欄位            | 類型         | 必需 | 說明                        |
| ------------- | ---------- | -- | ------------------------- |
| `pattern`     | `string`   | 是  | 通道模式。                     |
| `description` | `string`   | 否  | 人類可讀的說明。                  |
| `webhookUrls` | `string[]` | 否  | 每筆已交付訊息的Webhook URL。      |
| `enabled`     | `boolean`  | 否  | 預設為`true`。已停用的通道無法加入或交付至。 |

```bash theme={null}
curl -X POST "https://your-app.insforge.app/api/realtime/channels" \
  -H "Authorization: Bearer <project-admin-jwt-or-ik_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "pattern": "chat:%",
    "description": "Chat rooms",
    "webhookUrls": ["https://example.com/realtime-webhook"],
    "enabled": true
  }'
```

### 取得通道

```http theme={null}
GET /api/realtime/channels/{id}
```

### 更新通道

```http theme={null}
PUT /api/realtime/channels/{id}
```

```bash theme={null}
curl -X PUT "https://your-app.insforge.app/api/realtime/channels/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer <project-admin-jwt-or-ik_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Active order updates",
    "enabled": true
  }'
```

### 刪除通道

```http theme={null}
DELETE /api/realtime/channels/{id}
```

```json theme={null}
{
  "message": "Channel deleted"
}
```

訊息歷程記錄會保留。已刪除的通道會將現有訊息`channelId`值設定為`null`。

## 訊息

### 列出訊息

```http theme={null}
GET /api/realtime/messages
```

查詢參數：

| 參數          | 類型        | 說明             |
| ----------- | --------- | -------------- |
| `channelId` | `uuid`    | 按通道ID篩選。       |
| `eventName` | `string`  | 按事件名稱篩選。       |
| `limit`     | `integer` | 1至1000。預設為100。 |
| `offset`    | `integer` | 預設為0。          |

```bash theme={null}
curl "https://your-app.insforge.app/api/realtime/messages?eventName=status_changed&limit=50" \
  -H "Authorization: Bearer <project-admin-jwt-or-ik_api_key>"
```

回應：

```json theme={null}
[
  {
    "id": "660e8400-e29b-41d4-a716-446655440000",
    "eventName": "status_changed",
    "channelId": "550e8400-e29b-41d4-a716-446655440000",
    "channelName": "order:123",
    "payload": {
      "id": "123",
      "status": "shipped"
    },
    "senderType": "system",
    "senderId": null,
    "wsAudienceCount": 5,
    "whAudienceCount": 1,
    "whDeliveredCount": 1,
    "createdAt": "2026-04-25T17:00:00.000Z"
  }
]
```

### 訊息統計

```http theme={null}
GET /api/realtime/messages/stats
```

查詢參數：

| 參數          | 類型          | 說明               |
| ----------- | ----------- | ---------------- |
| `channelId` | `uuid`      | 按通道ID篩選統計資料。     |
| `since`     | `date-time` | 僅包含在此時間戳之後建立的訊息。 |

```json theme={null}
{
  "totalMessages": 1250,
  "whDeliveryRate": 0.98,
  "topEvents": [
    {
      "eventName": "status_changed",
      "count": 450
    }
  ],
  "retentionDays": null
}
```

`retentionDays: null`表示訊息會無限期保留。

## 權限

```http theme={null}
GET /api/realtime/permissions
```

傳回使用者定義的RLS原則，用於：

* `realtime.channels`上的訂閱檢查。
* `realtime.messages`上的發佈檢查。

```json theme={null}
{
  "subscribe": {
    "policies": [
      {
        "policyName": "users_subscribe_own_orders",
        "tableName": "channels",
        "command": "SELECT",
        "roles": ["authenticated"],
        "using": "pattern = 'order:%'",
        "withCheck": null
      }
    ]
  },
  "publish": {
    "policies": []
  }
}
```

## 設定

### 取得即時設定

```http theme={null}
GET /api/realtime/config
```

```json theme={null}
{
  "retentionDays": null
}
```

### 更新即時設定

```http theme={null}
PATCH /api/realtime/config
```

```bash theme={null}
curl -X PATCH "https://your-app.insforge.app/api/realtime/config" \
  -H "Authorization: Bearer <project-admin-jwt-or-ik_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "retentionDays": 90
  }'
```

使用`null`以無限期保留訊息。正整數表示保留訊息指定的天數。

## Webhooks

當通道有`webhookUrls`時，透過該通道交付的每筆訊息都會發佈至各個URL。

請求本文是原始訊息承載。標頭識別交付：

| 標頭                      | 值        |
| ----------------------- | -------- |
| `X-InsForge-Event`      | 事件名稱     |
| `X-InsForge-Channel`    | 已解決的通道名稱 |
| `X-InsForge-Message-Id` | 訊息UUID   |

交付嘗試反映在訊息歷程記錄中的`whAudienceCount`和`whDeliveredCount`中。
