文档 10 / 28

API 接口规范

REST + WebSocket + gRPC · 微服务间契约 · 错误码标准

册别:第三册 · 技术与架构 版本:V1.0 日期:2026-08-15 状态:草稿待评审

📑 目录

一、通用规范 二、Auth Service 接口 三、Match Service 接口 四、Call Service 接口 五、Translate Service 接口 六、Payment Service 接口 七、Social Service 接口 八、Ad Service 接口 九、Safety Service 接口 十、WebSocket 事件总表 十一、错误码标准 十二、版本管理与兼容性

一、通用规范

1.1 基础信息

项目规范
Base URLhttps://api.vocalink.sg/v1(生产) / https://staging-api.vocalink.sg/v1(测试)
协议HTTPS only(TLS 1.2+)
数据格式JSON(UTF-8)
时区UTC(响应中统一),客户端按本地时区展示
时间戳Unix epoch milliseconds(13 位)
鉴权Bearer Token(JWT),Header: Authorization: Bearer <jwt>
幂等写操作支持 Idempotency-Key Header(UUID v4)
限流每用户 100 req/min(API Gateway 层)

1.2 统一响应格式

// 成功响应 { "code": 0, "message": "ok", "data": { ... }, "request_id": "req_abc123def456", "server_time_ms": 1715324800000 } // 错误响应 { "code": 4001, "message": "Invalid phone number format", "data": null, "request_id": "req_abc123def456", "server_time_ms": 1715324800000 }

1.3 通用 Header

Header必填说明
Authorization是(除 /auth/*)Bearer <jwt_token>
Content-Type是(POST/PUT)application/json
X-Request-ID推荐UUID,用于链路追踪
Idempotency-Key写操作推荐UUID v4,防重复提交
X-Client-VersionApp 版本号(如 1.0.0)
X-Platformios / android / web
X-Localezh-CN / en-SG

1.4 分页规范

// 请求参数 ?page=1&page_size=20&sort=created_at&order=desc // 响应 { "code": 0, "data": { "items": [...], "pagination": { "page": 1, "page_size": 20, "total": 356, "has_more": true, "next_cursor": "eyJwYWdlIjoyfQ==" } } }

二、Auth Service 接口

POST /auth/otp/send 发送 OTP 验证码
{ "phone": "+6591234567", "country_code": "SG" }
响应字段说明
data.session_idOTP 会话 ID(60s 有效)
data.expires_in剩余秒数(60)
POST /auth/otp/verify 验证 OTP 并登录/注册
{ "session_id": "sess_xxx", "otp_code": "4287", "device_id": "device_uuid_xxx" }
响应字段说明
data.access_tokenJWT(有效期 7 天)
data.refresh_token刷新令牌(有效期 30 天)
data.is_new_user是否新注册用户
data.user用户基本信息
POST /auth/refresh 刷新 Token
{ "refresh_token": "refresh_xxx" }
GET /auth/me 获取当前用户信息
{ "code": 0, "data": { "user_id": "usr_xxx", "nickname": "Alex", "avatar": "https://...", "mother_tongue": "en-US", "target_language": "zh-CN", "vip_status": "active", "vip_expire_at": 1718000000000, "free_calls_left": 7, "coins": 1200 } }
PUT /auth/profile 更新个人资料
{ "nickname": "Alex Tan", "avatar": "https://...", "mother_tongue": "en-US", "target_language": "zh-CN", "bio": "Learning Mandarin!" }
POST /auth/logout 退出登录(Token 加入黑名单)
{ "device_id": "device_uuid_xxx" }
DELETE /auth/account 注销账号(30 天冷却)
{ "reason": "no_longer_needed", "confirm_password": "..." }

三、Match Service 接口

POST /match/start 开始匹配
{ "preferred_language": "zh-CN", "max_wait_seconds": 30, "filters": { "min_rating": 3, "same_gender": false } }
响应字段说明
data.match_id匹配会话 ID
data.statussearching / matched / timeout
data.estimated_wait_ms预估等待时间
WebSocket wss://api.vocalink.sg/v1/match/events 匹配事件推送
// 匹配成功 { "type": "matched", "match_id": "m_xxx", "partner": { "user_id": "usr_yyy", "nickname": "小李", "avatar": "...", "language": "zh-CN", "rating": 4.5 }, "call_token": "call_token_xxx", "signaling_server": "wss://rtc.vocalink.sg" } // 匹配超时 { "type": "timeout", "match_id": "m_xxx", "message": "No partner found", "suggestion": "expand_search" }
POST /match/cancel 取消匹配
{ "match_id": "m_xxx" }
GET /match/pool/stats 匹配池实时统计
{ "code": 0, "data": { "online_users": 12480, "searching_users": 320, "avg_wait_ms": 2800, "peak_hour": "21:00-22:00 SGT" } }

四、Call Service 接口

POST /call/start 发起通话(匹配成功后调用)
{ "match_id": "m_xxx", "call_token": "call_token_xxx", "audio_config": { "codec": "opus", "sample_rate": 16000 } }
WebSocket wss://rtc.vocalink.sg/v1/call/signaling WebRTC 信令通道
// Client → Server: Offer { "type": "webrtc_offer", "call_id": "c_xxx", "sdp": "..." } // Server → Client: Answer { "type": "webrtc_answer", "call_id": "c_xxx", "sdp": "..." } // Server → Client: ICE Candidate { "type": "ice_candidate", "call_id": "c_xxx", "candidate": "..." }
POST /call/end 结束通话
{ "call_id": "c_xxx", "reason": "normal_hangup", "rating": 5, "feedback": "Great conversation!" }
响应字段说明
data.duration_seconds通话时长
data.coins_spent本次消耗金币
data.coins_earned本次获得金币(被叫)
data.can_add_buddy是否可加为语伴
POST /call/report 举报通话中的违规行为
{ "call_id": "c_xxx", "reason": "harassment", "description": "Used inappropriate language", "severity": "high" }
GET /call/history 通话记录
{ "code": 0, "data": { "items": [ { "call_id": "c_xxx", "partner": "小李", "start_time": 1715324800000, "duration": 342, "direction": "outbound", "cost_coins": 0 } ], "pagination": { "page": 1, "total": 56, "has_more": true } } }

五、Translate Service 接口

WebSocket wss://api.vocalink.sg/v1/translate/stream 翻译流(通话中实时推送字幕)
// Server → Client: 字幕推送 { "type": "subtitle", "call_id": "c_xxx", "seq": 42, "is_final": true, "source_lang": "zh-CN", "target_lang": "en-US", "source_text": "我今天想去吃火锅", "translated_text": "I want to eat hotpot today", "tts_audio_url": "https://cdn.vocalink.sg/tts/xxx.mp3", "latency_ms": 342, "confidence": 0.92 } // Server → Client: 中间结果 { "type": "subtitle_partial", "call_id": "c_xxx", "seq": 43, "source_text": "明天天气", "is_final": false }
POST /translate/feedback 翻译质量反馈
{ "call_id": "c_xxx", "seq": 42, "rating": 4, "issue": "wrong_terminology", "expected": "I want to eat steamboat today", "comment": "hotpot ≠ steamboat in SG" }
GET /translate/quality 翻译质量指标(内部监控)
{ "code": 0, "data": { "bleu_score": 42.3, "avg_latency_ms": 387, "p95_latency_ms": 498, "cache_hit_rate": 0.37, "error_rate": 0.002, "sample_size": 50000 } }

六、Payment Service 接口

GET /payment/packages 获取充值套餐列表
{ "code": 0, "data": { "coin_packages": [ { "id": "pkg_500", "coins": 500, "price_sgd": 4.99, "bonus_coins": 50, "popular": false }, { "id": "pkg_1200", "coins": 1200, "price_sgd": 9.99, "bonus_coins": 200, "popular": true }, { "id": "pkg_3000", "coins": 3000, "price_sgd": 19.99, "bonus_coins": 600, "popular": false }, { "id": "pkg_6000", "coins": 6000, "price_sgd": 34.99, "bonus_coins": 1500, "popular": false } ], "vip_plans": [ { "id": "vip_week", "duration_days": 7, "price_sgd": 3.99, "features": ["unlimited_calls","no_ads","priority_match"] }, { "id": "vip_month", "duration_days": 30, "price_sgd": 12.99, "features": ["unlimited_calls","no_ads","priority_match","tts_voice"], "recommended": true }, { "id": "vip_year", "duration_days": 365, "price_sgd": 99.99, "features": ["unlimited_calls","no_ads","priority_match","tts_voice","exclusive_badge"], "best_value": true } ] } }
POST /payment/charge 创建充值订单
{ "package_id": "pkg_1200", "channel": "paynow", "return_url": "vocalink://payment/callback" }
响应字段说明
data.order_id订单号
data.pay_url支付跳转 URL(PayNow/Stripe)
data.qr_codePayNow QR 数据(Base64)
data.expires_at订单过期时间
POST /payment/subscription 订阅 VIP
{ "plan_id": "vip_month", "channel": "apple_iap", "receipt_data": "base64_receipt..." }
GET /payment/orders 订单历史
{ "code": 0, "data": { "items": [ { "order_id": "ord_xxx", "type": "coins", "amount_sgd": 9.99, "coins": 1400, "channel": "paynow", "status": "completed", "created_at": 1715324800000 } ] } }
POST /payment/gift/send 发送礼物
{ "call_id": "c_xxx", "target_user_id": "usr_yyy", "gift_type": "crown", "quantity": 1 }
GET /payment/balance 查询余额
{ "code": 0, "data": { "coins": 1200, "vip_status": "active", "vip_expire_at": 1718000000000, "free_calls_left": 10, "free_calls_reset_at": 1715366400000 } }

七、Social Service 接口

GET /social/buddies 语伴列表
{ "code": 0, "data": { "items": [ { "user_id": "usr_yyy", "nickname": "小李", "avatar": "...", "language": "zh-CN", "last_call_at": 1715324800000, "total_calls": 12, "is_favorite": true, "is_online": true } ] } }
POST /social/buddies/add 添加语伴
{ "target_user_id": "usr_yyy", "call_id": "c_xxx" }
DELETE /social/buddies/:user_id 删除/拉黑语伴
{ "action": "block", "reason": "harassment" }
GET /social/messages/:user_id 私聊消息列表
{ "code": 0, "data": { "items": [ { "msg_id": "msg_xxx", "from_user": "usr_yyy", "type": "text", "content": "Hello! 你好吗?", "translated_content": "Hello! How are you?", "created_at": 1715324800000, "is_read": true } ], "pagination": { "page": 1, "has_more": true } } }
POST /social/messages/send 发送私聊消息(带翻译)
{ "target_user_id": "usr_yyy", "type": "text", "content": "See you tomorrow!", "auto_translate": true }
GET /social/leaderboard 排行榜
{ "code": 0, "data": { "type": "most_active", "period": "weekly", "items": [ { "rank": 1, "user_id": "usr_zzz", "nickname": "Wang", "avatar": "...", "score": 3420, "badge": "🌟" } ] } }

八、Ad Service 接口

GET /ads/config 获取广告位配置
{ "code": 0, "data": { "rewarded_video": { "enabled": true, "provider": "admob", "ad_unit_id": "ca-app-pub-xxx/yyy", "reward_coins": 2, "daily_limit": 5, "remaining_today": 3 }, "banner": { "enabled": true, "provider": "admob", "ad_unit_id": "ca-app-pub-xxx/zzz", "position": "bottom_home" } } }
POST /ads/reward/claim 领取广告奖励
{ "ad_id": "admob_reward_xxx", "ad_type": "rewarded_video", "watch_duration_ms": 28000, "verification_token": "admobsig_xxx" }
响应字段说明
data.reward_granted是否发放奖励
data.coins_added获得金币数
data.remaining_today今日剩余次数
POST /ads/event 广告事件上报
{ "event_type": "impression|click|dismiss|error", "ad_type": "banner|rewarded", "provider": "admob", "ad_unit_id": "ca-app-pub-xxx/yyy", "error_code": null }

九、Safety Service 接口

POST /safety/report 提交举报
{ "target_user_id": "usr_yyy", "call_id": "c_xxx", "reason": "harassment", "description": "Repeated unwanted advances", "severity": "high", "evidence": { "type": "text_excerpt", "content": "..." } }
举报原因枚举说明
harassment骚扰/纠缠
nsfw色情/不当内容
scam诈骗/钓鱼
hate_speech仇恨言论
spam垃圾信息
underage疑似未成年人
other其他(需描述)
GET /safety/report/:id 查询举报处理状态
{ "code": 0, "data": { "report_id": "rpt_xxx", "status": "resolved", "resolution": "user_warned", "handled_at": 1715325000000, "handler": "moderator_001" } }
POST /safety/moderate/text 实时文本审核(内部调用)
{ "text": "check this message", "context": { "user_id": "usr_xxx", "call_id": "c_xxx" } }
响应字段说明
data.is_safe是否安全
data.categories命中的违规类别
data.actionallow / warn / block / escalate
data.confidence置信度 0-1
GET /safety/status 查询用户安全状态
{ "code": 0, "data": { "user_id": "usr_xxx", "trust_score": 85, "warnings": 0, "is_restricted": false, "restriction_reason": null } }

十、WebSocket 事件总表

10.1 连接管理

连接 URL用途心跳重连
wss://api.vocalink.sg/v1/ws/global全局事件(通知/系统消息)30s ping/pong指数退避 1-30s
wss://api.vocalink.sg/v1/match/events匹配事件推送10s即时
wss://rtc.vocalink.sg/v1/call/signalingWebRTC 信令5s3s 内
wss://api.vocalink.sg/v1/translate/stream翻译字幕流15s1s 内
wss://api.vocalink.sg/v1/social/messages私聊实时消息30s5s

10.2 事件类型枚举

事件类型 (type)方向说明
match.foundS→C匹配成功
match.timeoutS→C匹配超时
call.startedS→C通话开始
call.endedS→C通话结束
call.qualityS→C通话质量更新
subtitleS→C翻译字幕(final)
subtitle_partialS→C翻译字幕(中间结果)
gift.receivedS→C收到礼物
buddy.onlineS→C语伴上线
message.newS→C新私聊消息
system.noticeS→C系统通知
webrtc_offerC↔SWebRTC Offer
webrtc_answerC↔SWebRTC Answer
ice_candidateC↔SICE Candidate

十一、错误码标准

错误码段类别示例
0成功
1000-1999通用错误1001 参数错误 / 1002 未授权 / 1003 频率限制
2000-2999Auth 错误2001 OTP 无效 / 2002 Token 过期 / 2003 账号被封
3000-3999Match 错误3001 匹配池为空 / 3002 匹配超时 / 3003 被拒绝
4000-4999Call 错误4001 通话已满 / 4002 对方忙 / 4003 网络差
5000-5999Translate 错误5001 ASR 失败 / 5002 MT 失败 / 5003 TTS 失败
6000-6999Payment 错误6001 余额不足 / 6002 支付超时 / 6003 退款失败
7000-7999Social 错误7001 已被拉黑 / 7002 添加频繁
8000-8999Safety 错误8001 内容违规 / 8002 账号受限
9000-9999Ad 错误9001 填充失败 / 9002 频次超限 / 9003 验证失败

11.1 常用错误码详解

CodeMessage客户端处理
1002Unauthorized跳转登录页 / 自动刷新 Token
1003Rate limited显示"操作太频繁,请稍后再试"
2002Token expired用 refresh_token 静默刷新
3002Match timeout弹窗"扩大范围"或"稍后再来"
4001Translation unavailable降级为纯语音模式
6001Insufficient coins跳转充值页
8001Content violation通话中断 + 提示"违反社区规则"
9002Ad daily limit reached隐藏广告入口

十二、版本管理与兼容性

12.1 版本策略

规则说明
URL 版本/v1/ /v2/ 大版本变更(不兼容时升级)
Header 版本X-API-Version: 1.2(小版本,兼容)
向后兼容每个版本至少维护 12 个月
废弃流程标记 deprecated → 通知 3 个月 → 下线
客户端强制更新API 返回 426 → 客户端弹"请更新到最新版"

12.2 变更日志

版本日期变更
v1.02026-08-15Phase 1 初始 API 集合
v1.12026-09-30新增翻译反馈接口 / 优化匹配算法参数
v1.22026-11-15广告位接口 / TTS 语音合成接口

⚠️ API 变更原则:

  • 不删除已有字段(标记 deprecated 但保留)
  • 新增字段客户端必须忽略未知字段
  • 枚举值扩展时,客户端需处理未知值(默认 fallback)
  • 所有变更在 #api-changelog Slack 频道同步

附录

附录 A:Postman Collection

所有 API 已导出为 Postman Collection v2.1,包含环境变量(dev/staging/prod)。

下载:https://github.com/vocalink/api-specs/vocalink-api-v1.postman_collection.json

附录 B:OpenAPI Schema

OpenAPI 3.0 YAML 文件同步维护,用于自动生成 SDK 和文档。

路径:https://api.vocalink.sg/v1/openapi.yaml

附录 C:相关文档

文档关联内容
08 系统架构 HLDAPI 在微服务架构中的位置
09 实时翻译子系统 LLD翻译相关接口的内部实现
13 支付中台接入方案支付通道详细对接

附录 D:修订记录

版本日期修改内容作者
V1.02026-08-15初始版本后端团队