Alliance Chat · OPERATIONS
全部会话
跨项目查看服务进展,回溯每一次沟通。
第三方平台注册 · 指定客服绑定
由第三方服务端调用。先在“客服人员”创建客服,注册时提交平台用户 ID
和该项目的客服编号。
每个项目使用独立密钥,仅展示一次;重置后旧密钥立即失效。请保存到第三方服务端,勿放入浏览器。
POST /api/integration/register-member
Authorization: Bearer 项目接入密钥
Content-Type: application/json
{"project_id":"1","user_id":"third-party-user-123","staff_id":"1001"}
user_id 为第三方平台原始用户 ID,必须转为字符串(1–128字符);staff_id
为“客服人员”列表中的项目客服编号,须以正整数字符串提交。
首次成功返回 201;同一项目和用户重复请求返回同一
member_id(200),不能改绑其他客服(409)。客服跨项目或已停用返回 404;密钥无效返回
401,项目授权失效返回 403/404。上游失败可使用相同参数重试。
返回:{"project_id":"1","user_id":"third-party-user-123","staff_id":"1001","member_id":"@p1_member_a7k2m9:服务域名","created":true}
注册自动创建客户与客服的专属会话,返回
room_id。客服使用列表中的聊天账号及相同密码登录聊天前端;客户通过嵌入组件免密打开自己的聊天。
客户转移与前端嵌入
转移保留原专属会话及历史,新客服接管、旧客服移出;客户退出原项目群聊,不自动加入新群。原群历史留存供运营审计。失败后使用原请求编号和原参数重试。
POST /api/integration/transfer-member
Authorization: Bearer 项目接入密钥
Idempotency-Key: 唯一且重试时保持不变的请求编号
{"project_id":"1","user_id":"third-party-user-123","staff_id":"1002"}
POST /api/integration/chat-ticket
Authorization: Bearer 项目接入密钥
{"project_id":"1","user_id":"third-party-user-123","origin":"https://www.partner.example"}
凭证有效期 60 秒,只能使用一次。合作方 ticket 接口必须从自身登录会话取得
user_id,不能接受浏览器传入的客户身份。聊天登录有效期 1 小时;退出合作方账号时调用
destroy()。
<script src="合作项目后台地址/embed.js"></script>
<script>
const chat = AllianceChat.mount({
projectId: '1',
ticketUrl: '/chat-ticket.php'
});
// 指定 container: '#customer-chat' 可嵌入页面容器,容器需设置高度。
// 客户退出登录或切换账号时:chat.destroy();
</script>
PHP 服务端调用示例(PHP 8.1+ / ext-curl)
<?php
require 'AllianceChat.php'; // 完整封装见 examples/php
$chat = new AllianceChat(
getenv('ALLIANCE_CHAT_URL'),
getenv('ALLIANCE_PROJECT_ID'),
getenv('ALLIANCE_API_KEY')
);
// 注册处理器:客服编号由合作方服务端决定
$chat->register((string)$customerId, '1001');
// 转移任务:编号先保存到数据库,所有重试复用同一个值
$chat->transfer((string)$customerId, '1002', $savedRequestId);
// 查询交接状态
$status = $chat->transferStatus((string)$customerId, $savedRequestId);
chat-ticket.php:接入合作方已有登录认证
<?php
require 'bootstrap.php'; // 在服务端初始化 $chat
session_start();
header('Content-Type: application/json');
header('Cache-Control: no-store');
$origin = getenv('PARTNER_PUBLIC_ORIGIN');
if ($_SERVER['REQUEST_METHOD'] !== 'POST' ||
($_SERVER['HTTP_ORIGIN'] ?? '') !== $origin ||
!isset($_SESSION['user_id'])) {
http_response_code(403); exit;
}
// $chat 使用上方服务端配置;不能读取浏览器提交的 user_id
try {
echo json_encode($chat->ticket((string)$_SESSION['user_id'], $origin));
} catch (Throwable $e) {
http_response_code(503);
echo '{"error":"Chat temporarily unavailable"}';
}
完整 PHP 案例见仓库 examples/php;接口契约见
docs/对接接口文档.md。客服管理和客服聊天使用现有后台及聊天前端。
01 · 先确认你要接入什么
当前开放的是运营管理接口:合作项目管理员登录后管理自己的项目会话。会员注册绑定请使用上方的服务端专用接口;管理会话凭据和项目密钥均不可下发给会员浏览器。
| 功能 |
当前状态 |
| 管理员/客服登录、客服管理、注册绑定、会员封禁、创建会话、历史与审计 |
已开放,可按本文联调 |
| 客户一次性凭证登录、客服转移 |
已开放,见上方服务端业务接口 |
| 客户文本消息发送、历史分页 |
已通过客户聊天组件提供;群发言权限在会话管理中配置 |
合作网站的“联系客服”使用上方嵌入组件;下列步骤用于管理员单独联调管理接口。
开通顺序
- Alliance 在总运营后台登记项目,确定不可变项目 ID。
- Alliance 开通合作方管理员并授权项目;合作方使用独立后台入口登录。
- 查询授权项目,创建一个不邀请成员的测试房间,验证会话查询与历史读取。
-
客服由合作管理员开通,客户由合作方后端注册接口开通。项目管理员账号不等于 Matrix
聊天账号。
当前环境
你的授权项目
项目 ID 必须以字符串传递。示例房间 ID 和会员 ID
是占位值;请替换为真实返回值。生产域名需要由 Alliance 部署后确认。
02 · 登录与鉴权
下面是 Bash 终端中的手动联调示例,需要 curl 和 jq(macOS 默认 zsh 请先执行
bash)。只填写你自己的管理员账号。BASE 必须是后台入口的完整
Origin(协议、域名、端口),不要带路径或末尾斜杠。
登录返回 {"user": {...}, "csrf": "..."},同时通过 Set-Cookie 建立 8
小时会话。合作方 Cookie 为 partner_session,总运营为
ops_session;二者不能互换。浏览器中的 Cookie 为 HttpOnly,应由浏览器自动携带。
- 读取接口:携带登录 Cookie。
-
写入接口:Cookie +
Origin: $BASE + X-CSRF-Token: $CSRF +
JSON 请求体。登录本身需要 Origin,不需要 CSRF。
- 重新登录后重新获取 CSRF。修改密码、调整授权或停用账号会使旧登录失效。
-
这些示例供管理员手动联调,不是会员网站跨域接入方案。会员前端不能持有管理员密码、Cookie
或 Matrix 服务令牌。
curl -fsS -b "$COOKIE" "$BASE/api/me"
# 退出;之后 Cookie 和 CSRF 不再可用
curl -fsS -b "$COOKIE" -H "Origin: $BASE" \
-H "X-CSRF-Token: $CSRF" -X POST "$BASE/api/logout"
rm -f "$COOKIE"
03 · 创建第一条测试会话
先查询授权项目,将其中一个项目 ID 填到
PROJECT。新房间只包含服务账号,因此历史中可能只有系统事件,没有聊天文本。
curl -fsS -b "$COOKIE" "$BASE/api/projects" | jq .
PROJECT="替换为授权项目ID"
REQUEST_ID="$(uuidgen)"
BODY="$(jq -nc --arg p "$PROJECT" '{project_id:$p,name:"接入联调测试",invite:[]}')"
CREATED="$(curl -fsS -b "$COOKIE" -H "Origin: $BASE" \
-H "X-CSRF-Token: $CSRF" -H "Content-Type: application/json" \
-H "Idempotency-Key: $REQUEST_ID" -d "$BODY" "$BASE/api/rooms")"
printf '%s\n' "$CREATED" | jq .
ROOM_ID="$(printf '%s' "$CREATED" | jq -er .room_id)"
ROOM_PATH="$(jq -rn --arg id "$ROOM_ID" '$id|@uri')"
curl -fsS -b "$COOKIE" "$BASE/api/rooms?project=$PROJECT&page=0" | jq .
curl -fsS -b "$COOKIE" "$BASE/api/rooms/$ROOM_PATH/messages" | jq .
创建成功首次返回 HTTP
201:{"room_id":"!实际ID:服务域名"}。同账号、相同参数、相同幂等键重试成功请求返回
HTTP 200 和同一个房间。
创建超时不要换新幂等键再次创建。先查会话列表;如果返回“未确认完成”,联系 Alliance
总运营同步并核查。合作方同步只刷新已经登记的会话,不能找回所有未登记房间。示例会产生真实测试房间,当前无删除接口。
04 · 接口参数与返回值
| 方法 / 路径 |
参数与响应 |
| GET /api/projects |
无参数;{items:[{id,name,active,created_at,room_count}]}。active 为 0/1。
|
| POST /api/rooms |
project_id:正整数字符串;name:去除首尾空白后 1–120 字符;invite:Matrix ID
数组,最多 50 个,管理员可留空;客服至少选择一名绑定会员。admins 为 invite
中的群管理员 ID 数组,speaking 为 all(所有人)或
admins(仅管理员)。Idempotency-Key:16–80 位字母、数字或连字符,建议
UUID。返回 {room_id}。
|
| GET /api/rooms |
project:项目 ID;q:名称/房间 ID 搜索,最多 120 字符;page:从 0
开始的整数。每页 30 条,返回 {items,total,page}。房间字段包含
id、project_id、name、created_at、synced_at、project_name、project_active。
|
| GET /api/rooms/{roomId}/messages |
cursor:可选,上次响应的 cursor。每次最多 40 个事件,从新到旧;返回
{items,cursor}。cursor 为 null 时停止。
|
| GET /api/rooms/{roomId}/media/{eventId} |
使用消息的 id 作为 eventId,且 attachment=true。两个路径参数分别 URL
编码;返回下载二进制,不是 JSON;最大 20 MB。
|
| POST /api/sync |
JSON {} 开始;后续 {cursor:"上次返回值"},直到 cursor=null。返回
{imported,skipped,processed,total,cursor}。合作方仅刷新已登记且授权的会话;总运营可扫描服务账号已加入的合规房间。
|
| GET /api/audit |
page 从 0 开始,每页最多 50 条;返回 {items,page},少于 50
条可停止。合作方只能查看授权范围内审计。
|
| GET /api/me |
返回 {user,csrf},检查当前会话。 |
| POST /api/password |
JSON {current,password};新密码至少 12 字符,成功后重新登录。 |
| POST /api/logout |
撤销当前登录会话。 |
合作方不能调用项目创建/修改和合作方账号管理接口。所有房间读取都会再次校验项目权限;知道房间
ID 不代表有权访问。
邀请成员
这些账号必须已由平台开通。后台自动把受控成员加入会话;客户通过嵌入组件发送消息,客服使用自己的聊天身份登录前端。
05 · 历史分页与附件
{
"items": [{
"id": "$事件ID", "type": "m.room.message",
"sender": "@p项目ID_member_会员ID:服务域名",
"time": 1760000000000, "body": "您好", "msgtype": "m.text",
"redacted": false, "attachment": false
}],
"cursor": "服务端返回的不透明分页凭据,或 null"
}
上面是响应结构示意。time 为 Unix 毫秒时间戳;items 包含系统事件,显示聊天文本时筛选
type=m.room.message。游标绑定当前登录会话和房间,1
小时有效;不能跨房间、跨账号复用或自行解析。
CURSOR="替换为上一页返回的cursor"
curl -fsS -b "$COOKIE" --get \
--data-urlencode "cursor=$CURSOR" \
"$BASE/api/rooms/$ROOM_PATH/messages" | jq .
EVENT_ID="替换为attachment为true的消息id"
EVENT_PATH="$(jq -rn --arg id "$EVENT_ID" '$id|@uri')"
curl -fS -b "$COOKIE" \
"$BASE/api/rooms/$ROOM_PATH/media/$EVENT_PATH" -o attachment.bin
不支持用任意 mxc
地址下载。历史和附件读取会记录审计;后台可查看的是服务端仍保留且服务账号有权读取的数据。会话不启用端到端加密,接入方应向用户说明运营质检范围。
06 · 错误处理与验收
错误通常为 JSON:{"error":"具体原因"}。排错时去掉 curl 的 -f 并加
-i,可以查看状态码和错误正文。
| 状态 |
排查与处理 |
| 400 |
核对字段类型、邀请账号格式、幂等键;分页凭据过期则从第一页重新读取。 |
| 401 |
登录失效或账号密码不正确。重新登录后更新 Cookie 和 CSRF。 |
| 403 |
核对 Origin、CSRF、账号角色及项目授权;不要尝试通过换项目 ID 绕过。 |
| 404 |
接口、房间或附件不存在,或不在授权范围。检查路径编码并联系总运营核对归属。
|
| 409 |
项目停用、幂等冲突、创建结果不确定或同步正在运行。先核查会话,避免重复创建。
|
| 413 |
请求体过大或附件超过后台下载限制。JSON 请求体上限 32 KB,附件上限 20 MB。
|
| 429 |
登录过于频繁或同时登录请求过多;降低频率,稍后重试。 |
| 500 / 502 / 503 / 504 |
记录时间和操作,联系 Alliance 排查服务状态。创建请求不要自动换幂等键重试。
|
联调完成标准
- 登录后项目列表仅包含获授权项目。
- 测试房间可以创建、查询和读取历史;空房无聊天消息属于正常情况。
- 相同幂等键与相同参数重试已成功创建的请求,不增加房间。
- 真实客户注册绑定后,可直接聊天;管理后台能查看其测试消息及附件。
- 退出后再查接口返回 401;合作方无法访问未授权项目。
反馈问题请提供操作时间、接口、HTTP 状态和错误文本。不要在工单中粘贴密码、Cookie
或服务令牌。