- GET /api/v1/notifications(分页,时间倒序不分组)/unread-count /read(ids|all),
对外 camelCase(PRD 前端契约);数据为内存 mock(13 类型全覆盖,重启复位),
接真实数据只换 repositories/notification_mock.py
- vendor_push 补华为 Push Kit(OAuth+messages:send),抽通用 send_notification
(任意文案+extras+mock 模式),send_accessibility_disabled 改薄封装行为不变
- 新增 /api/v1/push/{vendors,templates,test}:凭据状态/13 类 PRD 文案模板/测试发送
(默认 mock,mock=false 真发,可联动插站内 mock 消息闭环验证已读)
- .env.example 补 HUAWEI_* 键;docs/api 新增 notifications.md + push-vendor-test.md
- alembic merge 1a924c274fce 收拢 direct_vendor_push_fields/feedback_type_reply
双 head,恢复 upgrade head 可用
- tests: test_notifications + test_push_center 共 35 例
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
傻瓜比价 App 后端 — API 接口文档(索引)
Base URL:生产
https://app-api.shaguabijia.com;本地联调http://<开发机>:8770协议:HTTP / JSON,请求与响应体均application/json,字段统一 snake_case(⚠️ 例外:消息通知中心notifications族与厂商推送push族按 PRD 前端契约用 camelCase,见各自文档) 鉴权:需鉴权的接口在请求头带Authorization: Bearer <access_token>最后更新:2026-07-14(新增 消息通知中心 3 端点(M1-M3,虚拟数据阶段)与 厂商推送测试 3 端点(P1-P3,荣耀/华为/小米/OPPO/vivo);上一次 2026-06-23 补全 device/internal/CPS 短链等整族端点) 架构:app/api/v1/只放很轻的接口层;穿山甲/微信支付/极光/短信/美团等 SDK 集成的重逻辑在app/integrations/,实现细节见 docs/integrations/。
接口总览
| # | 方法 + 路径 | 鉴权 | 详情 |
|---|---|---|---|
| 1 | GET /health |
无 | 详情 |
| 2 | POST /api/v1/auth/jverify-login |
无 | 详情 |
| 3 | POST /api/v1/auth/sms/send |
无 | 详情 |
| 4 | POST /api/v1/auth/sms/login |
无 | 详情 |
| 5 | POST /api/v1/auth/refresh |
无 | 详情 |
| 6 | GET /api/v1/auth/me |
Bearer | 详情 |
| 7 | POST /api/v1/auth/logout |
Bearer | 详情 |
| 8 | POST /api/v1/coupon/step |
无 | 详情(透传 pricebot + best-effort 写 coupon_* 三表) |
| 8a | POST /api/v1/coupon/prompt/shown |
无 | 引导窗弹出即上报(按 device+package+日记 shown,今天这个 App 不再自动弹)(无单独文档) |
| 8b | POST /api/v1/coupon/prompt/dismiss |
无 | 用户拒绝/关闭引导窗(透传链路看不到拒绝,客户端通知)(无单独文档) |
| 8c | GET /api/v1/coupon/prompt/should-show |
无 | 切到外卖 App 时是否还应弹引导窗(device_id+package)(无单独文档) |
| 8d | POST /api/v1/coupon/prompt/reset |
无 | 重置今日引导窗 engagement(开发测频控用)(无单独文档) |
| 8e | GET /api/v1/coupon/completed-today |
无 | 这台设备今天是否已跑完整轮领券(首页「去领取」卡置灰源)(无单独文档) |
| 8f | POST /api/v1/coupon/completed-today/reset |
无 | 重置今日已完成(开发用)(无单独文档) |
| 8g | GET /api/v1/coupon/stats |
Bearer | 累计领券数(「我的」页战绩卡;按 user_id 聚合,鉴权)(无单独文档) |
| 9 | POST /api/v1/meituan/coupons |
无 | 详情 |
| 10 | POST /api/v1/meituan/feed |
无 | 详情 |
| 11 | POST /api/v1/meituan/referral-link |
无 | 详情 |
| 11a | POST /api/v1/meituan/top-sales |
无 | 详情(销量榜:离线库 meituan_coupon 按销量降序 + 跨源去重,不实时打美团) |
比价透传(前缀 /api/v1,外卖 MVP;与 coupon/step 同为透传 pricebot-backend;下按 Phase 流程列,均不鉴权) |
|||
| 12 | POST /api/v1/intent/recognize |
无 | 详情(Phase 1 意图识别,单次,多数源) |
| 12a | POST /api/v1/intent/precoupon/step |
无 | Phase 0 意图识别前先用券,仅美团源(透传,无单独文档) |
| 12b | POST /api/v1/intent/step |
无 | Phase 1 多帧意图识别,仅淘宝源,循环到 done(透传,无单独文档) |
| 13 | POST /api/v1/price/step |
无 | 详情(Phase 2 步进) |
| 13a | POST /api/v1/trace/finalize |
无 | 比价 trace 收尾上云,终止/未识别拿 trace_url(透传,无单独文档) |
比价记录(前缀 /api/v1/compare;按用户落库,鉴权,区别于上面不鉴权的透传) |
|||
| 12a | POST /api/v1/compare/record |
Bearer | 详情 |
| 12b | GET /api/v1/compare/records |
Bearer | 详情 |
| 12c | GET /api/v1/compare/records/{id} |
Bearer | 详情 |
| 12e | GET /api/v1/compare/stats |
Bearer | 详情(「我的」页省钱战绩卡:完成比价数 + 累计发现可省) |
比价战绩里程碑(前缀 /api/v1/compare;福利页「记录比价战绩」,按成功比价数解锁逐档发金币) |
|||
| 12d | GET /api/v1/compare/milestones |
Bearer | 详情 |
| 12e | POST /api/v1/compare/milestones/{milestone}/claim |
Bearer | 详情 |
设备 / 无障碍存活监控(前缀 /api/v1/device;心跳超时检出 + 掉线召回,#65) |
|||
| D1 | POST /api/v1/device/register |
Bearer | 详情(注册设备/更新极光 push token) |
| D2 | POST /api/v1/device/heartbeat |
Bearer | 详情(无障碍服务存活心跳,心跳也能自注册) |
| D3 | GET /api/v1/device/liveness |
Bearer | 详情(进 App 查本机是否被判掉线过) |
| D4 | POST /api/v1/device/liveness/ack |
Bearer | 详情(确认已弹引导,清掉线告警) |
上报更低价(前缀 /api/v1/report;众包纠偏,人工审核发奖) |
|||
| R1 | POST /api/v1/report |
Bearer | 提交上报(multipart:comparison_record_id/reported_platform_id/reported_price(元) + 1~4 张截图;原最低价反查 comparison_record.best_* 校验须更低)(无单独文档) |
| R2 | GET /api/v1/report/records |
Bearer | 上报记录列表(?status= pending/approved/rejected 可选筛选)(无单独文档) |
好友邀请(前缀 /api/v1/invite;注册即生效,双方各发 1 万金币) |
|||
| I1 | GET /api/v1/invite/me |
Bearer | 我的邀请码 + 分享链接 + 已邀人数/已得金币(无单独文档) |
| I2 | GET /api/v1/invite/invitees |
Bearer | 我邀请的人列表(limit/offset 分页)(无单独文档) |
| I3 | POST /api/v1/invite/landing-track |
无 | 落地页 dl.html 访问上报指纹(剪贴板归因兜底;浏览器无 token)(无单独文档) |
| I4 | POST /api/v1/invite/bind |
Bearer | 绑定邀请人;支持 clipboard/manual 邀请码 + fingerprint 指纹反查三种归因(无单独文档) |
钱包 / 我的资产(前缀 /api/v1/wallet) |
|||
| 14 | GET /api/v1/wallet/account |
Bearer | 详情 |
| 15 | GET /api/v1/wallet/coin-transactions |
Bearer | 详情 |
| 16 | GET /api/v1/wallet/cash-transactions |
Bearer | 详情 |
| 17 | GET /api/v1/wallet/exchange-info |
无 | 详情 |
| 18 | POST /api/v1/wallet/exchange |
Bearer | 详情 |
| 19 | POST /api/v1/wallet/bind-wechat |
Bearer | 详情 |
| 20 | POST /api/v1/wallet/unbind-wechat |
Bearer | 详情 |
| 21 | GET /api/v1/wallet/withdraw-info |
Bearer | 详情 |
| 22 | POST /api/v1/wallet/withdraw |
Bearer | 详情 |
| 23 | GET /api/v1/wallet/withdraw/status |
Bearer | 详情 |
| 24 | GET /api/v1/wallet/withdraw-orders |
Bearer | 详情 |
签到(前缀 /api/v1/signin) |
|||
| 25 | GET /api/v1/signin/status |
Bearer | 详情 |
| 26 | POST /api/v1/signin |
Bearer | 详情 |
| 26a | POST /api/v1/signin/boost |
Bearer | 详情 |
任务(前缀 /api/v1/tasks) |
|||
| 27 | GET /api/v1/tasks |
Bearer | 详情 |
| 28 | POST /api/v1/tasks/{task_key}/claim |
Bearer | 详情 |
省钱(前缀 /api/v1/savings) |
|||
| 29 | GET /api/v1/savings/summary |
Bearer | 详情 |
| 30 | GET /api/v1/savings/battle |
Bearer | 详情 |
| 31 | GET /api/v1/savings/records |
Bearer | 详情 |
看广告发奖(前缀 /api/v1/ad) |
|||
| 32 | GET /api/v1/ad/pangle-callback |
验签 | 详情 |
| 33 | GET /api/v1/ad/reward-status |
Bearer | 详情 |
| 34 | POST /api/v1/ad/test-grant |
Bearer | 详情 |
| 35 | POST /api/v1/ad/ecpm-report |
Bearer | 详情 |
| 35a | POST /api/v1/ad/feed-reward |
Bearer | 详情 |
| 35b | POST /api/v1/ad/reward-noshow |
Bearer | 详情(激励视频提前关闭/未发奖留痕,只记原因不发币) |
| 35c | GET /api/v1/ad/feed-reward/units |
Bearer | 信息流广告今日已发份数/上限(配合 feed-reward 看进度)(无单独文档) |
用户资料(前缀 /api/v1/user) |
|||
| 35 | PATCH /api/v1/user/profile |
Bearer | 详情 |
| 36 | POST /api/v1/user/avatar |
Bearer | 详情 |
| 36a | POST /api/v1/user/onboarding/complete |
Bearer | 标记新手引导完成(按 账号+device_id 幂等,跨卸载重装持久)(无单独文档) |
| 36b | GET /api/v1/user/onboarding/status |
Bearer | 查该 (账号,设备) 是否走过引导(运营在 admin 删记录即触发重走)(无单独文档) |
| 37 | DELETE /api/v1/user |
Bearer | 详情 |
帮助与反馈(前缀 /api/v1/feedback) |
|||
| 38 | POST /api/v1/feedback |
Bearer | 详情 |
| 38a | GET /api/v1/feedback/config |
Bearer | 反馈页「加群二维码」卡配置(开关 + 二维码图 + 三行文案)(无单独文档) |
| 38b | GET /api/v1/feedback/records |
Bearer | 我的反馈历史(pending/adopted/rejected)(无单独文档) |
消息通知中心(前缀 /api/v1/notifications;⚠️ 本族对外 camelCase;虚拟数据阶段:内存 mock,重启复位) |
|||
| M1 | GET /api/v1/notifications |
Bearer | 详情(消息列表,分页;13 类型卡片字段 + sentAt/isRead;服务端已按时间倒序排好,不分组) |
| M2 | GET /api/v1/notifications/unread-count |
Bearer | 详情(未读总数,首页铃铛角标;>99 → "99+",0 → null 隐藏) |
| M3 | POST /api/v1/notifications/read |
Bearer | 详情(标记已读:{ids:[...]} 单条/多条 或 {all:true} 进通知中心全量清零;幂等) |
厂商推送测试(前缀 /api/v1/push;荣耀/华为/小米/OPPO/vivo 五通道联调三件套,同为 camelCase) |
|||
| P1 | GET /api/v1/push/vendors |
Bearer | 详情(5 厂商服务端凭据配置状态,缺哪些 .env 键一目了然) |
| P2 | GET /api/v1/push/templates |
Bearer | 详情(13 类通知的 push 标题/正文模板 + PRD 示例渲染效果) |
| P3 | POST /api/v1/push/test |
Bearer | 详情(测试发送:默认 mock 不真发;mock=false 真发;可联动插一条站内 mock 通知闭环验证已读) |
首页门面数据 / 客户端配置(前缀 /api/v1/platform;全平台展示数字 + 运营开关,全部不鉴权,登录前可读) |
|||
| 39 | GET /api/v1/platform/stats |
无 | 详情 |
| 40 | GET /api/v1/platform/savings-feed |
无 | 详情 |
| 40a | GET /api/v1/platform/flags |
无 | 客户端运营 feature flag(比价/领券期广告开关等),拉取后缓存(无单独文档) |
| 40b | GET /api/v1/platform/ad-config |
无 | 客户端拉广告配置(穿山甲 app_id + 各位 ID + 各场景开关;不含验签密钥)(无单独文档) |
| 40c | GET /api/v1/platform/app-version |
无 | 最新 App 版本(OTA 检查更新;与本机 versionCode 比)(无单独文档) |
微信支付回调(前缀 /api/v1/wxpay) |
|||
| W1 | POST /api/v1/wxpay/transfer-auth-notify |
无 | 免确认收款授权结果通知(一期 stub:仅应答 200 不验签不改账,授权状态靠主动查询兜底)(无单独文档) |
| CPS 群发短链落地(无前缀,挂域名根;公网不鉴权) | |||
| C1 | GET /c/{code} |
无 | 详情(短链落地:微信授权拿 openid + 记点击 + 302 跳/淘宝 H5 落地页) |
| C2 | POST /c/{code}/copy |
无 | 详情(淘宝落地页点「复制口令」记 copy) |
| C3 | GET /wx/oauth/cb |
无 | 详情(微信网页授权回调;upsert cps_wx_user + 种 cookie,include_in_schema=False) |
| C4 | GET /MP_verify_*.txt |
无 | 详情(微信「网页授权域名」归属校验文件,include_in_schema=False) |
内部回写端点(前缀 /internal;pricebot/发布流程→app-server,X-Internal-Secret 头,非客户端接口) |
|||
| N1 | POST /internal/price-observation |
内部密钥 | 详情(比价价格事实批量落 price_observation) |
| N2 | GET /internal/store-mapping/lookup |
内部密钥 | 详情(按源平台店名反查目标平台已沉淀店铺 id/deeplink) |
| N3 | POST /internal/store-mapping |
内部密钥 | 详情(跨平台店铺身份映射落 store_mapping) |
| N4 | POST /internal/store-mapping/invalidate |
内部密钥 | 详情(标记某平台 shopId 缓存 deeplink 失效) |
| N5 | POST /internal/launch-confirm-sample |
内部密钥 | 详情(启动确认窗兜底样本落 launch_confirm_sample) |
| N6 | POST /internal/app-version |
内部密钥 | 详情(发布流程写最新 App 版本,落 app_config) |
静态资源(StaticFiles 挂载,见下方 /media 静态服务) |
|||
| - | GET /media/avatars/<file> |
无 | 用户头像;返回二进制图片 |
| - | GET /media/feedback/<file> |
无 | 反馈截图;返回二进制图片 |
运营后台 Admin(独立子应用 app/admin/,前缀 /admin/api,独立进程 + 独立 admin JWT。鉴权列:admin=任意已登录管理员,operator/finance/super_admin=需对应角色(super_admin 恒通过)) |
|||
| A1 | POST /admin/api/auth/login |
无 | 详情 |
| A2 | GET /admin/api/auth/me |
admin | 详情 |
| A3 | GET /admin/api/stats/overview |
admin | 详情 |
| A4 | GET /admin/api/users |
admin | 详情 |
| A5 | GET /admin/api/users/{user_id} |
admin | 详情 |
| A6 | POST /admin/api/users/{user_id}/status |
operator | 详情 |
| A7 | POST /admin/api/users/{user_id}/coins |
finance | 详情 |
| A8 | POST /admin/api/users/{user_id}/cash |
finance | 详情 |
| A9 | GET /admin/api/wallet/coin-transactions |
admin | 详情 |
| A10 | GET /admin/api/wallet/cash-transactions |
admin | 详情 |
| A11 | GET /admin/api/withdraws |
admin | 详情 |
| A12 | POST /admin/api/withdraws/reconcile |
finance | 详情 |
| A13 | POST /admin/api/withdraws/{out_bill_no}/refresh |
finance | 详情 |
| A14 | GET /admin/api/feedbacks |
admin | 详情 |
| A15 | POST /admin/api/feedbacks/{feedback_id}/handle |
operator | 详情 |
| A16 | GET /admin/api/admins |
super_admin | 详情 |
| A17 | POST /admin/api/admins |
super_admin | 详情 |
| A18 | PATCH /admin/api/admins/{admin_id} |
super_admin | 详情 |
| A19 | GET /admin/api/audit-logs |
admin | 详情 |
| A20 | GET /admin/api/dashboard-display |
admin | 详情 |
| A21 | PATCH /admin/api/dashboard-display/{metric} |
operator | 详情 |
| A22 | GET /admin/api/marquee-seeds |
admin | 详情 |
| A23 | POST /admin/api/marquee-seeds |
operator | 详情 |
| A24 | PATCH /admin/api/marquee-seeds/{seed_id} |
operator | 详情 |
| A25 | DELETE /admin/api/marquee-seeds/{seed_id} |
operator | 详情 |
| A26 | POST /admin/api/marquee-seeds/bulk |
operator | 详情 |
| A27 | GET /admin/api/marquee-seeds/preview |
admin | 详情 |
| A28 | GET /admin/api/ad-coin-audit |
admin | 详情(看广告金币公式复算对账,只读) |
| A29 | GET /admin/api/ad-revenue-report |
admin | 详情(广告收益报表:按用户/日期/类型/应用/代码位 聚合 条数/收益/金币,只读) |
| - | GET /admin/api/health |
无 | admin 健康检查(无单独文档) |
⚠️ 美团三个接口当前无鉴权,且
referral-link的sid允许客户端传值覆盖默认渠道——见各接口"备注"。coupon/step及外卖比价的intent/recognize、intent/precoupon/step、intent/step、price/step、trace/finalize都透传到 pricebot-backend,MVP 阶段均不鉴权(device_id 透传,待补 JWT——见app/api/v1/compare.py)。 福利相关业务接口(wallet/signin/tasks/savings、ad/reward-status、ad/feed-reward)均需 Bearer;wallet/exchange-info是静态规则无鉴权;ad/pangle-callback不走 JWT、靠穿山甲验签;ad/test-grant仅本地联调(开关控制,生产 404)。 金额字段一律以分为单位(*_cents)。
通用约定
- 时间格式:ISO 8601 UTC(如
2026-05-27T12:34:56Z) - 错误响应:FastAPI 标准结构
{"detail": "<错误信息>"},配合语义化 HTTP 状态码:400业务参数错(如验证码不对)401未认证 / token 无效或过期 / 用户被禁(响应头带WWW-Authenticate: Bearer)403账号被禁用422请求体字段校验失败(FastAPI 自动校验,如手机号格式)429触发限流(短信发送过频)502上游调用失败(极光验证/解密失败、美团接口失败)
- 接口文档(交互式):
APP_ENV非 prod 时开放GET /docs(Swagger UI)、GET /redoc;生产环境关闭。
游标分页约定
钱包流水 / 提现单 / 省钱明细等列表接口统一用游标分页:
- 请求 query:
limit(每页条数,1–100,默认 20)、cursor(上一页返回的next_cursor,首页不传)。 - 响应:
{ "items": [...], "next_cursor": <int|null> }。next_cursor为末条记录的 id;为null表示已到底,无更多数据。 items按id倒序(最新在前)。
复用数据结构
TokenPair
| 字段 | 类型 | 说明 |
|---|---|---|
access_token |
string | 访问令牌,之后每个鉴权请求带 Authorization: Bearer <它> |
refresh_token |
string | 刷新令牌 |
token_type |
string | 固定 "Bearer" |
expires_in |
int | access 剩余秒数(默认 7200 = 2h) |
refresh_expires_in |
int | refresh 剩余秒数(默认 2592000 = 30d) |
TokenWithUser
继承 TokenPair 全部字段,额外多一个 user(UserOut)。登录类接口成功时返回此结构。
UserOut
| 字段 | 类型 | 说明 |
|---|---|---|
id |
int | 用户主键 |
phone |
string | 手机号(注销账号后变 deleted_<id> 占位释放唯一约束) |
nickname |
string | null | 昵称,经 PATCH /api/v1/user/profile 修改 |
avatar_url |
string | null | 头像相对 URL(/media/avatars/...),经 POST /api/v1/user/avatar 上传 |
register_channel |
string | 注册渠道:jverify / sms |
status |
string | active / disabled / deleted |
created_at |
datetime | 注册时间 |
last_login_at |
datetime | 最近登录时间 |
CouponCard(券卡片,coupons 与 feed 的 items 元素)
| 字段 | 类型 | 说明 |
|---|---|---|
product_view_sign |
string | 换链主键(传给 referral-link) |
platform |
int | 1=外卖/到家, 2=到店 |
biz_line |
int | null | 到店子类:1到餐 2到综 3酒店 4门票 |
name |
string | 商品名 |
head_image_url |
string | 头图;后端已统一拼缩放参数 @375w_375h_1e_1c.webp(美团 CDN 服务端缩到 124dp + 转 WebP,实测省 76–99%),客户端直接用 |
brand_name |
string | null | 品牌名 |
brand_logo_url |
string | null | 品牌 logo |
sell_price |
string | 现价 |
original_price |
string | 原价 |
discount_amount |
string | 优惠额 = 原价 − 现价 |
commission_rate |
string | 佣金比例,如 "1.4%" |
commission_amount |
string | null | 预估佣金(元) |
sale_volume |
string | null | 销量 |
poi_name |
string | null | 最近门店名 |
distance_text |
string | null | 格式化距离,如 "600m" / "1.5km" |
distance_meters |
float | null | 原始距离(米) |
available_poi_num |
int | null | 可用门店数 |
coupon_num |
int | null | 券张数 |
valid_days |
int | null | 券有效天数 |
price_label |
string | null | 如 "15天低价" |
rank_label |
string | null | 如 "2小时北京外卖销量榜第1名" |
rating_label |
string | null | 如 "4.6分" |
/media 静态服务
用户上传文件(头像/反馈截图)落盘到 settings.MEDIA_ROOT(默认 ./data/media/),由 FastAPI 的 StaticFiles 挂在 settings.MEDIA_URL_PREFIX(默认 /media)对外暴露:
GET /media/avatars/<file>— 用户头像(JPEG/PNG/WebP)GET /media/feedback/<file>— 反馈截图(同上)
生产建议:由 nginx 直接 serve MEDIA_ROOT 目录,绕过应用进程减少压力。
URL 格式:服务端返回相对路径(如 /media/avatars/u1_a4f2b3c8e9d2e0a1.jpg),客户端按自己的 BASE_URL 拼绝对地址——dev 下可能是 10.0.2.2/LAN IP/127.0.0.1,服务端不知道客户端怎么访问到自己。
文件名服务端随机生成 u<user_id>_<16 位 hex>.<ext>,杜绝路径穿越与覆盖。
附:鉴权与刷新机制
- 签发:登录成功后签发 access(HS256,2h) + refresh(30d),payload 含
sub(user_id)、typ(access/refresh)、iat、exp。 - 携带:客户端对需鉴权接口自动加
Authorization: Bearer <access>(登录类接口跳过)。 - 校验(
/me、/logout):验签 → 验过期 → 验typ=access→ 查库确认用户存在且status=active,任一不过 → 401。 - 续期:access 过期触发 401 → 客户端用 refresh 调
/refresh换新 token 对并重放原请求;refresh 也失效 → 清本地、跳登录。 - 无状态:token 不落库,服务端无法主动吊销(logout 为占位),靠短 access 有效期限制泄露风险。JWT 密钥
JWT_SECRET_KEY必须为高熵随机串(生产严禁用默认值)。