Aile 平臺整合(Integration)外部對接手冊

版本: v2.2\ 最後更新: 2026-06-26\ 適用對象: 第三方系統整合開發者\ 服務模組: aile-service-integration\ 程式碼分支: release

v2.2 保留 AIFF 寫入規格、pictureUrl 主資料與 setting 級圖片、訊息傳送、服務廣播與 Simulator 聯調說明。

v2.2+ 變更摘要(2026-06-25 release):

  • Breaking: OpenAPI 路徑重構 — 從 /integration/openapi/v1/<資源> 改為 /<資源>/v1/<動作>
  • Breaking: 所有 OpenAPI 端點統一為 POST,不再支援 GET。
  • Breaking: HMAC 簽名公式修正 — integrationId + nonce + body(不含 method/path)。
  • Breaking: Authorization 頭字首從 HMAC-SHA256 改為 AILE
  • 新增: AIFF 寫入介面(create/update/delete)。
  • 新增: 訊息傳送介面(POST /messages/v1/send)。
  • 新增: 群發廣播介面(POST /messages/v1/broadcast/create)。
  • 修正: 事件資源域和事件型別列表(基於原始碼)。

目錄

  1. 1. 概述
  2. 2. 核心概念與模型
  3. 3. 整合接入流程
  4. 4. OpenAPI 安全機制(HMAC 簽名)
  5. 5. 控制面 API(平臺管理端)
  6. 6. OpenAPI(第三方呼叫 Aile)
  7. 7. Webhook 事件推送(Aile → 第三方)
  8. 8. 事件資源域與事件型別參考
  9. 9. 接入實戰指南(第三方開發步驟)
  10. 10. 參考實現:Simulator 模擬服務
  11. 11. 常見問題與錯誤碼

1. 概述

Aile 平臺整合(Platform Integration)是一套標準化的第三方系統接入框架,允許外部 SaaS 平臺以租戶級別安裝 Aile 服務,並交換業務事件與資料。

1.1 架構全景


    
    
    
  ┌─────────────────────────────────────────────────┐
│                 Aile 平臺                         │
│                                                    │
│  aile-service-integration                         │
│  ├── /integration/app/*        應用定義管理        │
│  ├── /integration/tenant/*     安裝生命週期管理    │
│  ├── /messages/*               訊息傳送 / 廣播     │
│  ├── /openapi/*                第三方 API(HMAC簽名)│
│  └── InternalEvent → Webhook → 第三方回撥          │
│                                                    │
│  aile-service-tenant (事件釋出)                    │
│  └── InternalEventTrigger → 業務事件發布           │
└─────────────────────────────────────────────────┘
         │ 控制面 (HTTP)          │ OpenAPI (HMAC)    │ Webhook (HMAC)
         ▼                        ▼                   ▼
┌─────────────────────────────────────────────────┐
│              第三方整合平臺(你)                   │
│  ├── 安裝介面 (接收 Aile 安裝請求)                 │
│  ├── OpenAPI 呼叫 (查詢/傳送訊息/群發廣播)         │
│  └── Webhook 接收 (接收 Aile 業務事件)             │
└─────────────────────────────────────────────────┘

1.2 與舊版 TenantAppModel 的關係

注意: aile-service-job 模組中有一個舊的 TenantAppModel / TenantAppController 體系,以 /tenantapp/webhook 為路徑字首。本手冊描述的是新的 Integration Platform 體系(基於 IntegrationAppModel / TenantIntegrationModel),路徑字首為 /integration/。新體系相較舊體繫有以下增強:

特性舊 TenantAppModel新 Integration Platform
應用定義無全域性應用定義IntegrationApp(獨立於租戶)
安裝生命週期簡單 CRUD完整狀態機 Pending→Active→Suspended→Deleted
金鑰管理固定 secretKeyHMAC appSecret + rotate-secret
事件訂閱webHookTypessubscribedEvents(事件資源域粒度)
第三方回撥install/update/rotateSecret/uninstall
OpenAPI 目錄catalog 端點自動發現
安全隔離簽名+租戶繫結integrationId + body 一致性校驗 + nonce

2. 核心概念與模型

2.1 IntegrationApp(平臺應用定義)

這是由 Aile 管理員建立的全域性應用註冊,描述一個第三方平臺的身份和能力。


    
    
    
  {
  "appId"
: "your-app-id",           // 全域性唯一應用 ID
  "appName"
: "Your Platform Name",  // 應用名稱
  "provider"
: "your-company",       // 提供方
  "supportedEvents"
: [              // 支援的事件資源域(*. 為通配)
    "contact.*"
,
    "service_number.*"

  ]
,
  "authType"
: "HMAC_SHA256",        // 鑑權型別
  "secret"
: "platform-secret",      // 平臺級金鑰(Aile 呼叫第三方時使用)
  "installUrl"
: "https://your-platform.com/api/aile/install",     // 第三方安裝 URL
  "updateUrl"
: "https://your-platform.com/api/aile/update",       // 第三方更新 URL
  "rotateSecretUrl"
: "https://your-platform.com/api/aile/rotate", // 第三方輪換金鑰 URL
  "uninstallUrl"
: "https://your-platform.com/api/aile/uninstall", // 第三方解除安裝 URL
  "installAckMode"
: "Sync",         // Sync(同步完成)或 Async(非同步受理)
  "status"
: "Active"                // Draft → Active → Suspended → Deleted
}

──→ 狀態機:Draft → Active → Suspended → Active → Deleted

2.2 TenantIntegration(租戶安裝例項)

當一個 Aile 租戶安裝你的平臺應用時,會在 Aile 端建立一個安裝例項:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",       // 安裝例項唯一 ID(Aile 生成)
  "appId"
: "your-app-id",            // 關聯的應用 ID
  "tenantId"
: "T001",                // Aile 租戶 ID
  "tenantType"
: "enterprise",        // 租戶型別
  "externalTenantId"
: "EXT-12345",   // 第三方系統對應租戶 ID(由你指定)
  "appSecret"
: "generated-secret",   // 安裝級金鑰(用於 HMAC 簽名,由 Aile 生成)
  "webhookUrl"
: "https://your-platform.com/webhook/events", // 事件接收地址
  "subscribedEvents"
: [              // 實際訂閱的事件資源域
    "contact.*"
,
    "service_number.*"

  ]
,
  "installAckMode"
: "Sync",          // 受理模式
  "status"
: "Active"                 // 安裝狀態
}

──→ 安裝狀態機:Pending → Active → Suspended/Disabled → Active → Deleted
InstallFailed 狀態表示安裝失敗。

2.3 租戶隔離模型


3. 整合接入流程

3.1 整體流程圖


    
    
    
  Step 0: Aile 管理員註冊 IntegrationApp(後臺操作)
  │
Step 1: Aile 租戶發起安裝
  POST /integration/tenant/system/v1/install
  { appId, tenantId, tenantType }
  │
  ├── Aile 建立 TenantIntegration(狀態=Pending)
  ├── Aile 呼叫第三方 installUrl(傳遞 integrationId、appSecret 等)
  │
Step 2: 第三方處理安裝
  ├── 驗證請求合法性
  ├── 建立外部租戶關聯
  ├── 確認 webhookUrl 和 subscribedEvents
  │
  ├── Sync 模式:直接返回 { status: "Active", externalTenantId, webhookUrl, subscribedEvents }
  │      → Aile 更新狀態為 Active
  │
  └── Async 模式:先返回 { accepted: true, status: "Pending" }
         → 後續回撥 Aile
         POST /integration/tenant/open/v1/install/callback
         { integrationId, status: "Active", externalTenantId, webhookUrl, subscribedEvents }
         → Aile 更新狀態為 Active

Step 3: 日常執行
  ├── 第三方呼叫 Aile OpenAPI(HMAC 簽名,查詢/同步資料)
  └── Aile 推送業務事件到第三方 webhookUrl(HMAC 簽名)

Step 4: 解除安裝
  POST /integration/tenant/system/v1/uninstall?integrationId=xxx
  ├── Aile 呼叫第三方 uninstallUrl
  └── TenantIntegration 狀態 = Deleted

3.2 Aile 傳送給第三方的安裝請求

當租戶發起安裝後,Aile 會呼叫 IntegrationApp.installUrl,傳送的請求體:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "appId"
: "your-app-id",
  "tenantId"
: "T001",
  "tenantType"
: "enterprise",
  "operatorId"
: "emp_001",
  "appSecret"
: "generated-secret-for-this-instance",
  "installationCallbackUrl"
: "https://aile-api.com/integration/tenant/open/v1/install/callback",
  "installAckMode"
: "Sync",
  "subscribedEvents"
: ["contact.*", "service_number.*"]
}

3.3 第三方應返回的安裝響應

Sync 模式(installAckMode=Sync):


    
    
    
  {
  "status"
: "Active",
  "externalTenantId"
: "EXT-12345",
  "webhookUrl"
: "https://your-platform.com/webhook/events",
  "subscribedEvents"
: ["contact.*", "service_number.*"]
}

Async 模式(installAckMode=Async):


    
    
    
  {
  "accepted"
: true,
  "status"
: "Pending"
}

之後非同步回撥 Aile:


    
    
    
  curl -X POST https://aile-api.com/integration/tenant/open/v1/install/callback \
  -H "Content-Type: application/json" \
  -d '{
    "integrationId": "ti_xxxxx",
    "status": "Active",
    "externalTenantId": "EXT-12345",
    "webhookUrl": "https://your-platform.com/webhook/events",
    "subscribedEvents": ["contact.*", "service_number.*"]
  }'

3.4 第三方更新 / 輪換金鑰 / 解除安裝介面

Aile 在以下場景會呼叫第三方對應 URL(定義在 IntegrationApp 中):

操作Aile 呼叫傳遞引數
更新配置updateUrl{ integrationId, webhookUrl, subscribedEvents }
輪換金鑰rotateSecretUrl{ integrationId, operatorId }
解除安裝uninstallUrl{ integrationId }

4. OpenAPI 安全機制(HMAC 簽名)

所有第三方呼叫 Aile OpenAPI 的請求都必須攜帶 HMAC 簽名。Aile 推送的 Webhook 事件也會使用相同簽名機制。

4.1 簽名演算法


    
    
    
  演演算法:  HMAC-SHA256
金鑰:    appSecret(來自 TenantIntegration 安裝例項)
簽名內容: integrationId + nonce + requestBody
簽名結果: Base64( HMAC-SHA256(appSecret, 簽名內容) )

4.2 請求頭規範

Header說明
AuthorizationAILE {integrationId}:{signature}簽名身份與結果
X-Aile-Noncenonce_1718256000123每次請求唯一的隨機字串
Content-Typeapplication/json請求體格式

4.3 簽名示例(Python)


    
    
    
  import hmac
import
 hashlib
import
 base64
import
 time
import
 requests

def
 build_signature(integration_id: str, app_secret: str, nonce: str, body: str) -> str:
    """
    計算 HMAC-SHA256 簽名。
    簽名內容 = integrationId + nonce + body
    """

    raw = integration_id + nonce + body
    mac = hmac.new(
        app_secret.encode('utf-8'),
        raw.encode('utf-8'),
        hashlib.sha256
    )
    return
 base64.b64encode(mac.digest()).decode('utf-8')

def
 build_auth_header(integration_id: str, signature: str) -> str:
    return
 f"AILE {integration_id}:{signature}"

def
 call_aile_openapi(integration_id: str, app_secret: str
                       method: str, path: str, body: dict = None
) -> dict:
    """
    呼叫 Aile OpenAPI。
    path 格式: /tenants/v1/me
    """

    base_url = "https://aile-api.com"  # 替換為實際環境地址
    body_str = json.dumps(body) if body else ""
    nonce = f"nonce_{int(time.time() * 1000)}"
    
    signature = build_signature(integration_id, app_secret, nonce, body_str)
    authorization = build_auth_header(integration_id, signature)
    
    response = requests.request(
        method=method,
        url=f"{base_url}{path}",
        headers={
            "Authorization"
: authorization,
            "X-Aile-Nonce"
: nonce,
            "Content-Type"
: "application/json"
        },
        data=body_str if body_str else None
    )
    return
 response.json()

4.4 簽名示例(JavaScript / Node.js)


    
    
    
  import crypto from "crypto";

function
 buildSignature(integrationId, appSecret, nonce, bodyString) {
  const
 raw = integrationId + nonce + (bodyString ?? "");
  return
 crypto.createHmac("sha256", appSecret).update(raw).digest("base64");
}

function
 buildAuthHeader(integrationId, signature) {
  return
 `AILE ${integrationId}:${signature}`;
}

async
 function callAileOpenApi(integrationId, appSecret, method, path, body) {
  const
 bodyStr = body ? JSON.stringify(body) : "";
  const
 nonce = `nonce_${Date.now()}`;
  const
 signature = buildSignature(integrationId, appSecret, nonce, bodyStr);
  
  const
 response = await fetch(`https://aile-api.com${path}`, {
    method,
    headers
: {
      "Authorization"
: buildAuthHeader(integrationId, signature),
      "X-Aile-Nonce"
: nonce,
      "Content-Type"
: "application/json"
    },
    body
: bodyStr || undefined
  });
  return
 response.json();
}

4.5 簽名示例(Java)


    
    
    
  import javax.crypto.Mac;
import
 javax.crypto.spec.SecretKeySpec;
import
 java.nio.charset.StandardCharsets;
import
 java.util.Base64;

public
 class AileHmacSigner {
    public
 static String buildSignature(String integrationId, String appSecret, 
                                         String nonce, String body)
 {
        String
 raw = integrationId + nonce + (body != null ? body : "");
        try
 {
            Mac
 mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            return
 Base64.getEncoder().encodeToString(mac.doFinal(raw.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            throw
 new RuntimeException("HMAC signing failed", e);
        }
    }
    
    public
 static String buildAuthHeader(String integrationId, String signature) {
        return
 "AILE " + integrationId + ":" + signature;
    }
}

4.6 簽名驗證流程(服務端)

Aile 服務端驗證流程:

  1. 1. 過濾器攔截所有 OpenAPI 資源路徑(例如 /tenants/v1/me/contacts/v1/list/aiffs/v1/create
  2. 2. 從 Authorization 頭解析 integrationIdrequestSignature
  3. 3. 從請求體中解析 integrationId 欄位,與簽名中的身份一致性校驗(防止冒用)
  4. 4. 根據 integrationId 查詢 TenantIntegrationModel,取得 appSecret
  5. 5. 使用 appSecretintegrationId + nonce + body 計算 HMAC-SHA256
  6. 6. 使用 MessageDigest.isEqual() 時間恆定比對簽名
  7. 7. 校驗安裝例項狀態為 Active、所屬應用狀態為 Active

5. 控制面 API(平臺管理端)

以下 API 供 Aile 內部管理面使用,第三方不需要呼叫這些介面。列於此處供理解完整流程。

5.1 IntegrationApp(應用定義)

方法路徑說明
POST/integration/app/system/v1/create建立應用定義
POST/integration/app/system/v1/update更新應用定義
GET/integration/app/system/v1/detail?appId=查詢應用詳情
POST/integration/app/system/v1/items分頁查詢應用列表
POST/integration/app/system/v1/enable上架應用
POST/integration/app/system/v1/disable下架應用
POST/integration/app/system/v1/delete刪除應用
GET/integration/app/system/v1/statistics/usage?appId=使用統計

5.2 TenantIntegration(安裝管理)

方法路徑說明
POST/integration/tenant/system/v1/install發起安裝
POST/integration/tenant/system/v1/update更新安裝配置
POST/integration/tenant/system/v1/suspend?integrationId=暫停安裝
POST/integration/tenant/system/v1/resume?integrationId=恢復安裝
POST/integration/tenant/system/v1/uninstall?integrationId=解除安裝
POST/integration/tenant/system/v1/rotate-secret?integrationId=輪換金鑰
GET/integration/tenant/system/v1/detail?integrationId=查詢安裝詳情
GET/integration/tenant/system/v1/items?tenantId=依租戶查詢列表
GET/integration/tenant/system/v1/items/by-app?appId=依應用查詢列表
POST/integration/tenant/open/v1/install/callback第三方安裝回撥(公開介面)

5.3 安裝請求引數詳情

發起安裝:


    
    
    
  {
  "appId"
: "your-app-id",       // 必填
  "tenantId"
: "T001",           // 必填
  "tenantType"
: "enterprise"    // 必填
}

安裝回撥(第三方 → Aile):


    
    
    
  {
  "integrationId"
: "ti_xxxxx",        // 必填
  "status"
: "Active",                 // 必填(Active 或 InstallFailed)
  "externalTenantId"
: "EXT-12345",    // 可選但不建議為空
  "webhookUrl"
: "https://...",        // 可選
  "subscribedEvents"
: ["contact.*"],   // 可選
  "message"
: "安裝完成"                // 可選
}

更新配置:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "webhookUrl"
: "https://new-url.com/webhook",
  "subscribedEvents"
: ["tenant.*", "contact.*"]
}

6. OpenAPI(第三方呼叫 Aile)

所有 OpenAPI 端點採用 /<資源>/v1/<動作> 路徑結構(例如 /contacts/v1/list),所有請求均為 POST 方法(含查詢請求),且必須攜帶 HMAC 簽名。舊版 /integration/openapi/v1/<資源> 路徑不再作為對外穩定契約。

6.1 通用請求格式

所有 OpenAPI 請求體都必須包含 integrationId


    
    
    
  {
  "integrationId"
: "ti_xxxxx"
}

其餘欄位因 API 而異。詳見各端點說明。

6.2 通用響應格式


    
    
    
  {
  "code"
: 200,
  "message"
: "success",
  "data"
: { ... }
}

6.3 API 端點一覽

6.3.1 租戶資訊

方法路徑說明
POST/tenants/v1/me查詢當前安裝例項的租戶資訊

請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx"
}

響應 data


    
    
    
  {
  "tenantId"
: "T001",
  "tenantName"
: "某某公司",
  "tenantType"
: "enterprise",
  "status"
: "Active"
}

6.3.2 服務號

方法路徑說明
POST/service-numbers/v1/list查詢服務號列表
POST/service-numbers/v1/detail查詢服務號詳情
POST/service-numbers/v1/sync查詢服務號差異同步列表

列表請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "current"
: 1,
  "size"
: 20
}

詳情請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "serviceNumberId"
: "SN001"
}

同步請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx"
}

6.3.3 員工

方法路徑說明
POST/employees/v1/list查詢租戶員工列表

    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "current"
: 1,
  "size"
: 20
}

6.3.4 聯絡人(客戶)

方法路徑說明
POST/contacts/v1/list查詢聯絡人列表
POST/contacts/v1/detail查詢聯絡人詳情
POST/contacts/v1/interactions查詢近期互動記錄

列表請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "serviceNumberId"
: "SN001",
  "current"
: 1,
  "size"
: 20
}

詳情請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "contactId"
: "C001",
  "serviceNumberId"
: "SN001"
}

互動記錄請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "serviceNumberId"
: "SN001",
  "days"
: 30,
  "current"
: 1,
  "size"
: 20
}

6.3.5 群組(LineGroup)

方法路徑說明
POST/groups/v1/list查詢群組列表

    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "current"
: 1,
  "size"
: 20
}

6.3.6 會話統計

方法路徑說明
POST/sessions/v1/statistics查詢會話月統計
POST/sessions/v1/statistics/detail查詢會話月統計詳情

    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "serviceNumberId"
: "SN001",
  "month"
: "2026-06"
}

6.3.7 AIFF 配置(應用內浮動框架)

v2.2 更新。 新增 create / update / delete 寫介面,支援主資料圖片 (pictureUrl) 和 setting 級別配置。

方法路徑說明
POST/aiffs/v1/list查詢 AIFF 列表(分頁)
POST/aiffs/v1/detail查詢 AIFF 詳情(含 settings)
POST/aiffs/v1/create建立 AIFF 主資料與設定
POST/aiffs/v1/update更新 AIFF 主資料與設定
POST/aiffs/v1/delete刪除 AIFF 主資料與全部設定

列表請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx"
}

詳情請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "extraId"
: "your-app-id"
}

建立請求 OpenApiAiffCreateRequestDto

欄位型別必填說明
integrationIdString租戶安裝例項 ID
extraIdString外部應用唯一識別(外部系統中的 AIFF ID)
nameStringAIFF 應用名稱
descriptionStringAIFF 應用描述
pictureUrlStringAIFF 主資料圖片地址,直接儲存外部傳入的 URL(不下載、不上傳)
settingsObject[]建立時同步寫入的 AIFF 設定列表(可選)

更新請求 OpenApiAiffUpdateRequestDto

欄位型別必填說明
integrationIdString租戶安裝例項 ID
extraIdString外部應用唯一識別
nameStringAIFF 應用名稱
descriptionStringAIFF 應用描述
pictureUrlStringAIFF 主資料圖片地址
settingsObject[]更新時同步維護的 AIFF 設定列表(可選)

刪除請求:


    
    
    
  {
  "integrationId"
: "ti_xxxxx",
  "extraId"
: "your-app-id"
}

刪除主資料時會連帶刪除該 AIFF 下的所有設定。

Setting 子結構 OpenApiAiffSettingRequestDto

每個 setting 對應一組前端展示配置,可在建立/更新 AIFF 時一併提交。

欄位型別必填說明
idString既有設定 ID(更新既有設定時使用)
extraKeyString外部設定唯一識別
displayNameString前端展示名稱
pictureUrlString設定級別圖片地址。未傳時查詢返回回退外層主資料 pictureUrl
serviceNumberIdsString[]設定生效的服務號 ID 列表
displayTypeString顯示型別,見下表
roomTypeString[]聊天室型別列表(僅 displayType=Room 時生效),見下表
displayLocationString嵌入位置(僅 displayType=Room 時生效),見下表
endPointUrlStringAIFF 跳轉目標地址
supportDeviceString支援裝置型別,見下表
popupSizeString彈窗尺寸,見下表

displayType 列舉值:

說明
Frame主框架
AppList應用列表
Room聊天室內嵌(此時需設定 roomType + displayLocation
ContactIndex客戶主頁

roomType 列舉值(可多選):

說明
One單人聊天室
Person個人聊天室
Friend好友聊天室
System系統聊天室
Discuss多人聊天室
Group社團聊天室
GroupOwner社團聊天室(擁有者)
BusinessCustomer商務號聊天室(客戶角度)
BusinessEmployee商務號聊天室(員工角度)
BusinessSecretary商務號秘書群聊天室
ServiceNumberCustomer服務號聊天室(客戶角度)
ServiceNumberEmployee服務號聊天室(員工角度)
ServiceNumberAgent服務號聊天室(服務人員角度)
ServiceNumberGroup服務號群內聊天室
Object物件聊天室

displayLocation 列舉值:

說明
Toolbar工具列
Extend擴充套件欄位
Embed下沉式(內嵌)
MessageMenu訊息選單

supportDevice 列舉值:

說明
Desktop桌面端
Mobile手機端

popupSize 列舉值:

說明
Full全螢幕
Half半螢幕

詳情響應 data 結構 OpenApiAiffVO


    
    
    
  {
  "id"
: "aiff-xxx",
  "extraId"
: "your-app-id",
  "tenantId"
: "T001",
  "name"
: "外部應用名稱",
  "description"
: "應用描述",
  "pictureUrl"
: "https://example.com/image.png",
  "settings"
: [
    {

      "id"
: "setting-001",
      "extraId"
: "your-app-id",
      "extraKey"
: "setting-key-1",
      "displayName"
: "設定顯示名稱",
      "pictureUrl"
: "https://example.com/setting-icon.png",
      "endPointUrl"
: "https://example.com/aiff",
      "serviceNumberIds"
: ["SN001", "SN002"],
      "aiffId"
: "aiff-xxx"
    }

  ]

}

重要說明:

  1. 1. 圖片處理pictureUrl 僅做字串透傳與儲存,不下載圖片、不上傳附件。setting 未傳 pictureUrl 時,寫入階段不自動補外層值,僅查詢返回時回退外層主資料圖片
  2. 2. icon 檔案上傳:OpenAPI 僅承接結構化資料,不承接 icon 檔案上傳(內部 job 服務的 multipart/form-data icon 欄位在 OpenAPI 鏈路中固定為空)
  3. 3. setting 定位:更新時依 extraKey 定位既有 setting;若未傳可識別的標識,更新行為依賴既有業務約束
  4. 4. 刪除級聯:刪除 AIFF 主資料時會一併刪除該 extraId 下所有 setting

6.3.8 API 目錄(自動發現)

方法路徑說明
POST/catalog/v1/business-objects查詢業務物件清單
POST/catalog/v1/sync-resources查詢支援同步的資源清單
POST/catalog/v1/event-types查詢支援的事件型別清單
POST/catalog/v1/event-scopes查詢支援的事件資源域清單

所有目錄端點請求格式相同:


    
    
    
  {
  "integrationId"
: "ti_xxxxx"
}

6.3.9 傳送訊息

v2.1 新增功能。 供外部整合應用向指定聊天室傳送訊息。

方法路徑說明
POST/messages/v1/send傳送訊息到指定聊天室

功能範圍:

請求 DTO 結構:

頂層請求 OpenApiMessageSendRequestDto

欄位型別必填說明
integrationIdString租戶安裝例項 ID
senderObject傳送者資料,見下表
toObject接收者資料,見下表
messagesObject[]訊息列表(至少 1 條),見下表

傳送者 OpenApiMessageSenderDto

欄位型別必填說明
typeString傳送者型別:System / User / ServiceNumber
userTypeString使用者型別:Employee / Contact(type=User 時使用,預設為 Employee)
codeStringopenId 或服務號代號(type 非 System 時必填)
incomingString進線標記(可選)

接收者 OpenApiMessageReceiverDto

欄位型別必填說明
typeString接收目標型別:Room / System / User / ServiceNumber / ServiceMember
userTypeString使用者型別:Employee / Contact / Visitor(type=User 時使用)
codeString接收者代號(openId 或 roomId)
serviceNumberIdString服務號 ID(type=ServiceNumber/ServiceMember 時使用)
channelTypeString指定渠道:Line / Facebook / Webchat / Aiwow

單條訊息 OpenApiMessageItemDto

欄位型別必填說明
typeString訊息型別:Text / Template
altTextString替代文字(渠道不支援時的降級顯示)
sourceTypeString訊息來源型別:User / System / Assistant / Broadcast。未傳時按 sender.type 推導:System→System,其餘→User
contentObject訊息內容,見下表

訊息內容 OpenApiMessageContentDto

欄位型別必填說明
typeString模板型別(訊息為 Template 時使用):Buttons / Confirm / Process / Carousel
titleString標題
textString文字內容(Text 訊息的主體;Template 訊息的內文)
imageUrlString圖片網址(Template 訊息使用)
orientationString內容方向:Vertical(垂直)/ Horizontal(水平)
defaultActionObject預設動作(點選整張卡片的行為),結構:{ type, label, url }
actionsObject[]互動動作列表(按鈕等),每項結構同上

動作型別(defaultAction / actions[].type):

說明
Action前端本地行為
Postback提交到後端的回傳行為
Url前端開啟外部連結
Aiff前端開啟 Aiff 容器

響應格式:


    
    
    
  {
  "code"
: 200,
  "message"
: "success",
  "data"
: [
    {

      "id"
: "message-xxx",
      "roomId"
: "room-001",
      "tenantId"
: "T001",
      "type"
: "Text",
      "content"
: { "text": "Hello" },
      "senderId"
: "U001",
      "createdAt"
: "2026-06-23T10:30:00Z"
    }

  ]

}

訊息路由規則說明:

傳送訊息時,系統根據 to.typesender.type 的組合決定最終的目標聊天室:

to.typesender.type路由邏輯
Room任意直接使用 to.code 作為 roomId
System任意透過 to.code(員工 openId)定位員工的系統聊天室
UserSystem以接收者 openId 定位其系統聊天室(系統通知場景)
UserUser(同一個 openId)查詢該使用者的個人聊天室
UserUser(不同 openId)查詢傳送者的好友聊天室(非好友則報錯)
UserServiceNumber查詢服務號擁有者與目標使用者的好友聊天室
ServiceNumber任意查詢指定服務號與指定客戶的服務號聊天室
ServiceMember任意查詢指定服務號的服務成員聊天室

6.3.10 建立並傳送服務廣播

v2.1 新增功能。 供外部整合應用建立並傳送服務號廣播(群發),內部走 tenant 服務既有廣播建立流程。

方法路徑說明
POST/messages/v1/broadcast/create建立並傳送服務廣播

請求 DTO 結構 OpenApiBroadcastCreateRequestDto

欄位型別必填說明
integrationIdString租戶安裝例項 ID
openIdString本次建立廣播的員工 OpenID(用以解析建立者身份)
serviceNumberIdString目標服務號 ID
nameString廣播任務標題
remarkString廣播備註
channelString廣播頻道:Line / Facebook / Webchat / Aiwow
contentObject[]廣播內容列表,每個元素為 BroadcastBody
broadcastTimeLong預約廣播時間(Unix 毫秒時間戳),不填則立即傳送
labelIdsString[]標籤匹配範圍(以標籤篩選目標客戶)
customerIdsString[]指定廣播目標客戶 ID 列表
matchLogicString標籤匹配邏輯:OR(滿足任一)/ AND(全部滿足)

廣播內容 BroadcastBody

欄位型別必填說明
indexInteger順序編號
typeString訊息型別(廣播支援:Text / Image / File / Template
contentString訊息內容(與既有服務號廣播格式一致)

響應格式:


    
    
    
  {
  "code"
: 200,
  "message"
: "success",
  "data"
: {
    "id"
: "broadcast-xxx",
    "serviceNumberId"
: "SN001",
    "name"
: "節日推廣",
    "status"
: "Doing",
    "createdAt"
: "2026-06-23T10:30:00Z"
  }

}

重要說明:

  1. 1. 建立者身份校驗openId 必須對應一個存在於當前安裝例項租戶中的員工,否則請求失敗
  2. 2. 標籤與客戶篩選labelIdscustomerIds 都可選;若均不填,廣播目標將為空
  3. 3. 立即 vs 預約:不填 broadcastTime 則立即嘗試傳送;填寫未來時間則排程傳送
  4. 4. 廣播狀態:建立成功後狀態為 Doing,由 tenant 既有流程觸發下游廣播傳送;傳送完成後狀態變更為 Done
  5. 5. 許可權控制integration 服務會臨時建立 AileContext(含 tenantId + accountId + employeeId),完成後恢復原上下文,保證執行緒池安全

7. Webhook 事件推送(Aile → 第三方)

7.1 推送機制

7.2 事件信封格式 (EventEnvelope)


    
    
    
  {
  "eventId"
: "evt_abc123",
  "eventType"
: "contact.created",
  "eventVersion"
: "v1",
  "occurredAt"
: "2026-06-16T10:30:00Z",
  "source"
: "aile-tenant",
  "integration"
: {
    "appId"
: "your-app-id",
    "integrationId"
: "ti_xxxxx"
  }
,
  "tenant"
: {
    "tenantId"
: "T001",
    "externalTenantId"
: "EXT-12345",
    "tenantType"
: "enterprise"
  }
,
  "scope"
: {
    "serviceNumberId"
: "SN001",
    "entrySourceId"
: "line_channel_123"
  }
,
  "data"
: {
    "contactId"
: "C001",
    "name"
: "張三",
    "channel"
: "Line",
    "scopeId"
: "Uxxx_line_id"
  }
,
  "metadata"
: {
    "traceId"
: "trace_001",
    "retryCount"
: 0
  }

}

7.3 事件分發規則

  1. 1. 狀態過濾: 僅向 status=Active 的安裝例項推送
  2. 2. 事件過濾: 僅推送安裝例項 subscribedEvents 中訂閱的事件資源域
  3. 3. 安裝隔離: 一個安裝例項推送失敗不影響其他安裝例項
  4. 4. 重試機制: 推送失敗時進行重試,透過 metadata.retryCount 記錄

8. 事件資源域與事件型別參考

8.1 事件資源域(subscription scope codes)

用於 supportedEventssubscribedEvents 的訂閱值:

資源域程式碼說明
tenant.*租戶事件
user.*使用者事件
service_number.*服務號事件
contact.*聯絡人(客戶)事件
visitor.*訪客事件
group.*群組事件
addressbook.*通訊錄事件
notice.*通知事件
session.*會話事件

8.2 目前已實現的事件型別

以下事件型別在 aile-service-tenant 中已實作並自動釋出:

事件型別資源域說明
service_number.createdservice_number.*服務號建立
service_number.updatedservice_number.*服務號更新
service_number.deletedservice_number.*服務號刪除
contact.createdcontact.*聯絡人建立
contact.updatedcontact.*聯絡人更新
contact.deletedcontact.*聯絡人刪除
contact.service_number_unfollowedcontact.*聯絡人取消追蹤服務號
visitor.mergedvisitor.*匿名訪客合併為實名
employee.disabledemployee.disabled員工停用
tenant.disabledtenant.*租戶停用

注意: 當前事件推送機制(InternalEvent → Pub/Sub → Webhook HTTP)中,Pub/Sub 釋出已實現,但 Webhook HTTP 投遞層目前正在規劃中。具體可用性請與 Aile 團隊確認。


9. 接入實戰指南(第三方開發步驟)

9.1 前置準備

  1. 1. 聯絡 Aile 管理員,取得:
    • appId(你的應用識別碼)
    • • Aile API Base URL(例如 https://api.aile.com
  2. 2. 準備你的伺服器端點:
    • • 安裝介面:POST /your-platform/api/aile/install
    • • 更新介面:POST /your-platform/api/aile/update
    • • 輪換金鑰介面:POST /your-platform/api/aile/rotate
    • • 解除安裝介面:POST /your-platform/api/aile/uninstall
    • • Webhook 接收介面:POST /your-platform/webhook/events

9.2 第一步:實現安裝介面

Aile 呼叫 installUrl 時,你的介面需要:

  1. 1. 接收引數並儲存關鍵資訊(特別是 appSecretintegrationId
  2. 2. 為這個安裝建立 externalTenantId(你的系統中對應的租戶 ID)
  3. 3. 確定你的 Webhook 接收地址
  4. 4. 決定訂閱哪些事件資源域

示例(Node.js / Express):


    
    
    
  app.post('/api/aile/install', (req, res) => {
  const
 { integrationId, appId, tenantId, tenantType, appSecret, 
          installationCallbackUrl, subscribedEvents } = req.body;
  
  // 儲存安裝資訊到你的資料庫

  db.installations.save({
    integrationId,
    appId,
    tenantId,
    tenantType,
    appSecret,          // 重要:後續所有 OpenAPI 呼叫都需要
    installationCallbackUrl,
    subscribedEvents,
    externalTenantId
: `ext_${tenantId}`,
    webhookUrl
: 'https://your-platform.com/webhook/events',
    status
: 'Active'
  });
  
  // 同步模式直接返回成功

  res.json({
    status
: 'Active',
    externalTenantId
: `ext_${tenantId}`,
    webhookUrl
: 'https://your-platform.com/webhook/events',
    subscribedEvents
: ['contact.*', 'service_number.*']
  });
});

9.3 第二步:實現 OpenAPI 呼叫

使用儲存的 appSecretintegrationId,透過 HMAC 簽名呼叫 Aile API。


    
    
    
  // 查詢租戶資訊
const
 result = await callAileOpenApi(
  integrationId, appSecret,
  'POST'
,
  '/tenants/v1/me'
,
  { integrationId }
);

// 查詢服務號列表

const
 services = await callAileOpenApi(
  integrationId, appSecret,
  'POST'
,
  '/service-numbers/v1/list'
,
  { integrationId, current: 1, size: 20 }
);

// 查詢聯絡人列表

const
 contacts = await callAileOpenApi(
  integrationId, appSecret,
  'POST'
,
  '/contacts/v1/list'
,
  { integrationId, serviceNumberId: 'SN001', current: 1, size: 20 }
);

9.4 第三步:實現 Webhook 接收

接收 Aile 推送的業務事件:


    
    
    
  app.post('/webhook/events', (req, res) => {
  const
 event = req.body;
  
  // 冪等檢查:避免重複處理同一事件

  if
 (alreadyProcessed(event.eventId)) {
    return
 res.json({ success: true, duplicated: true });
  }
  
  // 根據事件型別進行業務處理

  switch
 (event.eventType) {
    case
 'contact.created':
      handleContactCreated
(event.data);
      break
;
    case
 'contact.updated':
      handleContactUpdated
(event.data);
      break
;
    case
 'service_number.created':
      handleServiceNumberCreated
(event.data);
      break
;
    // ... 更多事件型別

  }
  
  markAsProcessed
(event.eventId);
  res.json({ success: true, duplicated: false });
});

9.5 第四步:實現更新 / 輪換 / 解除安裝


    
    
    
  app.post('/api/aile/update', (req, res) => {
  const
 { integrationId, webhookUrl, subscribedEvents } = req.body;
  db.installations.update(integrationId, { webhookUrl, subscribedEvents });
  res.json({ status: 'Active' });
});

app.post('/api/aile/rotate', (req, res) => {
  const
 { integrationId, operatorId } = req.body;
  // 更新 appSecret(Aile 端會生成新金鑰,這裡接收通知)

  res.json({ status: 'Active' });
});

app.post('/api/aile/uninstall', (req, res) => {
  const
 { integrationId } = req.body;
  db.installations.update(integrationId, { status: 'Deleted' });
  res.json({ status: 'Deleted' });
});

9.6 重要注意事項

  1. 1. 所有 OpenAPI 請求都是 POST: 包括查詢請求也使用 POST 方法
  2. 2. 請求體必須包含 integrationId: 且必須與簽名中的 integrationId 一致
  3. 3. Nonce 必須唯一: 建議使用 nonce_{timestamp} 格式
  4. 4. empty body 處理: 無請求體時,bodyString 為空字串 "",簽名使用 integrationId + nonce + ""
  5. 5. 響應格式: Aile 統一返回 { code: 200, message: "success", data: {...} }
  6. 6. HTTPS 強制: 所有 API 通訊必須使用 HTTPS

10. 參考實現:Simulator 模擬服務

integration-third-party-simulator 是一個完整的第三方模擬服務,可用於本地開發聯調。

10.1 啟動方式


    
    
    
  cd integration-third-party-simulator
cp
 .env.example .env
npm install
npm start

預設埠:3301

10.2 關鍵配置(.env)


    
    
    
  PORT=3301
INSTALL_MODE=sync                  # sync 或 async
ASYNC_CALLBACK_DELAY_MS=200        # 非同步回撥延遲
ASYNC_FINAL_STATUS=Active          # 非同步最終狀態
DEFAULT_WEBHOOK_BASE_URL=http://localhost:3301
AILE_OPENAPI_BASE_URL=http://localhost:8080   # Aile 服務地址

10.3 模擬服務介面

控制面(第三方平臺端,接收 Aile 請求):


    
    
    
  # 安裝
curl -X POST http://localhost:3301/control-plane/install \
  -H "Content-Type: application/json" \
  -d '{
    "integrationId": "ti_001",
    "appId": "aipower",
    "tenantId": "tenant_001",
    "tenantType": "PERSONAL",
    "appSecret": "secret_001",
    "installationCallbackUrl": "http://localhost:8080/integration/tenant/open/v1/install/callback",
    "subscribedEvents": ["contact.*"]
  }'


# 更新

curl -X POST http://localhost:3301/control-plane/update \
  -H "Content-Type: application/json" \
  -d '{"integrationId": "ti_001", "webhookUrl": "https://new.example.com/webhook"}'

# 解除安裝

curl -X POST http://localhost:3301/control-plane/uninstall \
  -H "Content-Type: application/json" \
  -d '{"integrationId": "ti_001"}'

除錯介面:


    
    
    
  # 檢視所有安裝
curl http://localhost:3301/debug/installations

# 檢視所有 Webhook 事件

curl http://localhost:3301/debug/webhooks

# 以安裝例項身份觸發 OpenAPI 呼叫

curl -X POST http://localhost:3301/debug/installations/ti_001/openapi/invoke \
  -H "Content-Type: application/json" \
  -d '{"method": "POST", "path": "/tenants/v1/me"}'

10.4 聯調建議

  1. 1. 將 IntegrationApp.installUrl 指向 http://localhost:3301/control-plane/install
  2. 2. 先用 INSTALL_MODE=sync 打通主鏈路
  3. 3. 再切 async 驗證回撥分支
  4. 4. 確保 AILE_OPENAPI_BASE_URL 指向可訪問的 Aile 環境

11. 常見問題與錯誤碼

11.1 常見錯誤碼

錯誤碼說明解決建議
FAIL_OPENAPI_AUTH_HEADER_REQUIRED缺少 Authorization 或 X-Aile-Nonce 頭檢查請求頭是否正確傳遞
FAIL_OPENAPI_SIGNATURE_INVALID簽名驗證失敗檢查簽名演算法(integrationId+nonce+body),確認 appSecret 正確
FAIL_OPENAPI_INTEGRATION_NOT_FOUND安裝例項不存在或未啟用檢查 integrationId 是否正確,安裝狀態是否為 Active
FAIL_OPENAPI_INTEGRATION_DISABLED安裝例項已停用聯絡 Aile 管理員確認安裝狀態
FAIL_TENANT_INTEGRATION_NOT_FOUND資料許可權校驗失敗確認查詢的服務號或聯絡人是否屬於當前租戶
FAIL_INTEGRATION_APP_NOT_FOUND應用定義不存在或已下架聯絡 Aile 管理員確認應用狀態

11.2 FAQ

Q: 簽名驗證一直失敗?

A: 請確認簽名內容為 integrationId + nonce + bodyString注意不是 method + path + nonce + body)。bodyString 為原始 JSON 字串,無 body 時為空字串。

Q: Authorization 頭格式?

A: 格式為 AILE {integrationId}:{signature},例如 AILE ti_001:abc123...

Q: 查詢請求使用 GET 還是 POST?

A: 所有 OpenAPI 端點均使用 POST 方法(含查詢請求),請求體為 JSON。

Q: 如何判斷安裝是否為 Async 模式?

A: 檢視請求中的 installAckMode 欄位。Sync 表示同步完成(直接返回狀態),Async 表示先受理再回撥。

Q: 第三方需要實現哪些介面?

A: 至少需要實現 installUrl(安裝),建議也實現 updateUrluninstallUrl;Webhook 接收介面用於接收事件。


附錄 A:關鍵檔案索引

層級檔案路徑說明
應用定義模型aile-api/aile-integration-api/.../model/IntegrationAppModel.javaIntegrationApp 持久化模型
安裝例項模型aile-api/aile-integration-api/.../model/TenantIntegrationModel.javaTenantIntegration 持久化模型
事件信封 DTOaile-api/aile-integration-api/.../dto/event/EventEnvelopeDto.java對外事件格式
安裝請求 DTOaile-api/aile-integration-api/.../dto/control/InstallationRequestDto.java安裝請求引數
安裝響應 DTOaile-api/aile-integration-api/.../dto/control/InstallationResponse.java第三方安裝響應
回撥請求 DTOaile-api/aile-integration-api/.../dto/control/InstallationCallbackRequestDto.java非同步回撥引數
事件資源域列舉aile-api/aile-integration-api/.../enums/IntegrationEventScopeType.java9 個事件資源域定義
安裝狀態列舉aile-api/aile-integration-api/.../enums/TenantIntegrationStatus.java6 種安裝狀態
HMAC 簽名校驗器aile-service/aile-service-integration/.../service/impl/IntegrationOpenApiSignatureVerifier.java入站簽名校驗實現
OpenAPI 過濾器aile-service/aile-service-integration/.../config/IntegrationOpenApiSignatureFilter.java請求攔截過濾器
訪問驗證器aile-service/aile-service-integration/.../service/impl/IntegrationOpenApiAccessValidator.java安裝狀態與資料許可權校驗
OpenAPI 服務aile-service/aile-service-integration/.../service/impl/IntegrationOpenApiServiceImpl.javaOpenAPI 業務邏輯
安裝控制器aile-service/aile-service-integration/.../controller/TenantIntegrationController.java安裝 API 端點
應用控制器aile-service/aile-service-integration/.../controller/IntegrationAppController.java應用管理 API 端點
事件型別常量aile-service/aile-service-tenant/.../constants/TenantIntegrationEventTypes.java已實現的業務事件型別
Simulator 簽名integration-third-party-simulator/src/utils/signature.js簽名實現參考
Simulator 安裝integration-third-party-simulator/src/services/installationService.js安裝流程參考
訊息傳送 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiMessageSendRequestDto.java訊息傳送請求
訊息接收者 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiMessageReceiverDto.java接收目標定義
訊息傳送者 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiMessageSenderDto.java傳送者身份定義
訊息內容 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiMessageContentDto.java訊息內容結構
訊息條目 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiMessageItemDto.java單條訊息結構
廣播請求 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiBroadcastCreateRequestDto.java廣播建立請求
廣播內容 DTOaile-api/aile-tenant-api/.../model/servicenumber/BroadcastBody.java廣播訊息體
訊息控制器aile-service/aile-service-integration/.../controller/IntegrationOpenApiMessageController.java訊息與廣播 API 端點
訊息服務實現aile-service/aile-service-integration/.../service/impl/IntegrationOpenApiMessageServiceImpl.java訊息傳送與廣播業務邏輯
AIFF 建立 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiAiffCreateRequestDto.javaAIFF 建立請求
AIFF 更新 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiAiffUpdateRequestDto.javaAIFF 更新請求
AIFF 刪除 DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiAiffDeleteRequestDto.javaAIFF 刪除請求
AIFF Setting DTOaile-api/aile-integration-api/.../dto/openapi/OpenApiAiffSettingRequestDto.javaAIFF 設定請求
AIFF 控制器aile-service/aile-service-integration/.../controller/IntegrationOpenApiAiffController.javaAIFF CRUD API 端點
RoomTypeEnumaile-api/aile-job-api/.../aiff/enums/RoomTypeEnum.java15 種聊天室型別
DisplayTypeEnumaile-api/aile-job-api/.../aiff/enums/DisplayTypeEnum.java4 種顯示型別
AiffModelaile-api/aile-job-api/.../aiff/model/AiffModel.javaAIFF 主資料模型(含 pictureUrl)

附錄 B:版本變更記錄

版本日期變更
v2.2+2026-06-25在 v2.2 AIFF 規格基礎上補充 release 變更:OpenAPI 路徑由 /integration/openapi/v1/<資源> 重構為 /<資源>/v1/<動作>;所有端點統一 POST;HMAC 簽名公式確認為 integrationId + nonce + body;Authorization 字首改為 AILE;同步更新 AIFF 寫入、訊息傳送、群發廣播與事件資源域/事件型別說明。
v2.22026-06-24AIFF 章節全面重寫:新增 create / update / delete 寫介面完整規格;補充 pictureUrl 圖片支援說明(主資料級 + setting 級);補齊 5 組列舉表(displayType / roomType 15 種 / displayLocation / supportDevice / popupSize);新增 setting 子結構 DTO 與詳情響應;更新附錄 A
v2.12026-06-23新增 6.3.9 傳送訊息 API 完整規格 + 6.3.10 廣播 API 完整規格;更新架構全景圖;更新附錄 A 檔案索引
v2.02026-06-16基於 release 分支最新程式碼重寫;修正 HMAC 簽名演算法文件;補充 10 個 OpenAPI 控制器細節;增加目錄章節
v1.02026-06-13初版