面向白名单运营商与持有方商家:自助完成创建、调价、户型维护、逐晚房态、上下架,并接住客户订单(查单 / 确认 / 拒单);C 端目录只展示 online 房源。鉴权复用平台商家开放接口同一套 HMAC-SHA256 机制(与家政开放接口同签名算法、同密钥体系)。
房源开放接口是平台商家开放接口的房源分支:路径前缀 /api/juzhu/housing/vendor/*,全部为 POST,请求/响应均为 JSON。鉴权、密钥、错误码风格与家政开放接口(/api/juzhu/jiazheng/vendor/*)完全一致,一套密钥两个业务共用。
status ∈ draft(草稿,默认)/ online(上架)/ offline(下架);C 端目录只出 status=online 且 rating_status=passed(双闸)。目录有 ≤ 15 秒缓存,上下架最迟 15 秒生效。online 创建会被拒);上架前须通过平台评级审核(rating_status:draft → pending → passed / rejected),提审与查进度走开放接口 projects/rating/submit / projects/rating/status(见 4.11)。已上架房源的内容更新免审即时生效。vendor_id + hmac_key。regions/list + projects/list(只读)。projects/create 建草稿(默认不入 C 端),补户型、图片与价格。projects/rating/submit 提交自评分进入平台复核,projects/rating/status 查进度与驳回原因。projects/status 上架;日常用房态接口做关房/夜价,随用随调。| 环境 | Base | 说明 |
|---|---|---|
| 联调/演示 | https://sytest.meizu.life(本页同源,调试台直接可用) | 演示库,数据可随时清理重建 |
| 生产 | 以平台接入单下发的域名为准 | 同一套接口与签名,仅换 Base |
/api/juzhu/housing/vendor/* 即可;跨域接入方按上表 Base 拼全路径。
每个商家一个 vendor_id + 一把 hmac_key,由平台统一配置并线下下发。hmac_key 等同密码:只放服务端或自己的联调机,不要写进前端代码、不要提交仓库。
body,加上 vendor_id;剔除 sign 字段。父键.子键 点号展平;null、''(空串)的键不参与签名。true→'True'、false→'False');数组 → ['a', 'b'](单引号、逗号空格分隔)。k1=v1&k2=v2&…(& 连接,无转义)。timestamp(毫秒时间戳)参与上述串;用 hmac_key 做 HMAC-SHA256,取 hex 小写 为 sign。vendor_id + timestamp + sign,POST JSON 发送。时间戳与服务器偏差 ±5 分钟 内有效。price_night: 188,不要 188.0):Python 侧 str(188.0)='188.0' 而平台序列化为 '188',两边签名串不一致会直接 401 验签失败。价格单位为元、取整数。
// Node 签名示例
const crypto = require('crypto');
function pyStr(v) {
if (v === true) return 'True';
if (v === false) return 'False';
if (Array.isArray(v)) return '[' + v.map(x => (typeof x === 'string' ? "'" + x + "'" : pyStr(x))).join(', ') + ']';
return String(v);
}
function flatten(data, prefix) {
const flat = {};
for (const [k, v] of Object.entries(data || {})) {
if (v == null || v === '') continue; // 空值不参与签名
const key = prefix ? prefix + '.' + k : k;
if (v && typeof v === 'object' && !Array.isArray(v)) Object.assign(flat, flatten(v, key));
else flat[key] = pyStr(v);
}
return flat;
}
function sign(secretKey, body) {
const payload = { ...body };
delete payload.sign;
const timestamp = Date.now();
const flat = flatten(payload);
flat.timestamp = String(timestamp);
const stringToSign = Object.keys(flat).sort().map(k => k + '=' + flat[k]).join('&');
payload.timestamp = timestamp;
payload.sign = crypto.createHmac('sha256', secretKey).update(stringToSign, 'utf8').digest('hex');
return payload; // 直接作为 POST body
}
const body = sign(HMAC_KEY, { vendor_id: VENDOR_ID });
await fetch(BASE + '/api/juzhu/housing/vendor/projects/list', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
tags=['演示', '回归']),与 JSON 序列化不同;② 嵌套对象(如 units 数组里的对象)会被点号展平进签名,直接把最终 body 交给 sign 函数即可,不要手工拼;③ 重试时须重新签名(timestamp 会过期)。
响应统一为 JSON:成功 { "code": 0, "message": "success", … };失败 HTTP 状态码 + { "code": 4xx, "message": "原因" }(见 错误码)。
字段与平台房源模型一致、即接口契约本身;带 ★ 为商家写入接口接受的字段,标 只读出参 的字段由平台计算下发、传入无效。
price_from 改为选填,上架闸改为逐户型校验「能算出默认夜价」;
② 户型 price_night 在 rental 频道同样生效(不再只认月租 ÷ 30);
③ 最短连住下放户型(户型 > 房源 > 频道默认),与取消政策同一层;
④ 新增只读出参 default_night_price(户型)与 price_from_display / price_unit / price_note(房源卡片价,见 3.4)。
三项改动均向后兼容:按原样传 price_from + rent_monthly 的房源行为逐字不变。
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 平台生成,创建后返回;后续接口用 id 定位房源 |
name | string | ★必填 | 房源/项目名
channel | string | ★ 业务频道:rental 租赁住宿(长租+旅居,监管同口径)/ minsu 惠居民宿 / newhouse 新房 / resale 二手 / trade 卖旧买新;缺省 rental,创建后不可改。「保租房」不是频道,用 tags 表达(["保租房"],平台侧专题) |
city_id | int | ★必填 | 城市 id(
district_id | int | ★ 行政区 id(districts.id),须属于 city_id;可不传 |
address | string | ★ 详细地址;缺省自动拼「城市 · 名称」。暂无经纬度字段(如需 POI 打点请向平台提需求) |
slug | string | URL 标识(C 端深链词),同 channel 内唯一。建议直接传贵方房源编号;不传则按名称自动生成。注意:传入已存在的 slug 不报错,会静默加 -2/-3 后缀——创建前请先 projects/list 核对防重;改 name 会同步重生成 slug |
cover_image | string | ★ 封面图 URL;室内图集走 photos/add(4.11),上架须 ≥ 7 张照片 |
tags | string[] | ★ 标签数组(如 ["保租房","近地铁"]) |
price_from | int | 选填(2026-09 起)。起价,单位元:rental 为「元/月」,minsu 为「元/晚」;作为默认夜价的最后兜底(rental 折算 价/30)。不传也可以——此时由每个户型自己的价(price_night 或 rent_monthly)承担,上架闸按户型逐个校验(见 4.6)。平日/周末/节假日分档不走它,走房态日历逐晚覆盖(见 5.1) |
price_from_display / price_unit / price_note | — | 只读出参(2026-09):C 端卡片展示价三件套,页面直接渲染、不要自行折算。price_unit ∈ night(按晚起)/ month(按月起)/ null(该频道不适用,走 price_total);price_from_display 为数值,为空时取 price_note(暂无可订 / 价格面议)。单位口径:minsu 与带「旅居」tag 的 rental 按晚(取最低可售单夜价,见 3.4),其余 rental 按月(起价语义不变) |
sort_order / is_featured / featured_rank / old_house_hint | — | ★ 排序权重 / 平台精选开关 / 精选排序位(越小越靠前,与 is_featured 配合)/ 卖旧买新提示。is_featured、featured_rank 一般由平台运营设置,商家传了也会被接受 |
unit_count / managed_unit_count | int | ★ 户型数 / 在管套数(C 端「在管房源 N 套」的展示口径,与户型条数不是一回事)。unit_count 由平台在增删户型时自动维护,商家传了会被覆盖 |
contact_phone | string | ★ 真实联系电话,11 位手机号(1 开头;400 号码不接受)。仅入库用于 C 端拨号的虚拟号实时绑定,任何查询接口不回显;可经 projects/update 更新 |
owner_vendor_id | int | 数据归属商家(签名商家自动写入,不可改)。所有接口按它做行级隔离;订单佣金快照按它取商家档费率 |
status | string | ★ draft 草稿(默认,新建强制)/ online 上架 / offline 下架 |
ext | object | ★ 房源能力与差异属性:online_booking(在线预订)+ online_payment(在线支付,两项至少开启一项,见 5.3)+ insurance(保险标识数组,见 7)+ min_stay_nights(最短连住,2026-09 起降级为「房源默认值」,户型级优先,见 5.2) |
rating_status / rating | — | 审核/评级位:draft → pending → passed / rejected。passed 是上架前置;提审走 projects/rating/submit、进度与驳回原因走 projects/rating/status(4.12),列表/详情出参也随行返回 |
户型 = 房源下的实体售卖库存单元:预订、逐晚房态、免费取消政策都挂在户型维度;整栋 / 不限房型走项目级(unit_id=0)。同规格房型多间库存用 total_qty 表达(多间口径 2026-09-10:房型 × N 间,按晚扣减、售满即关,不区分具体房间号)。projects/create 可带 units[] 一次建全,后续 units/create 追加。
| 字段 | 类型 | 说明 |
|---|---|---|
project_id | int | ★必填 | 所属房源 id
name | string | ★必填 | 户型名(如「两居 68㎡」「整栋 · 6 室」)。可传
area_sqm | number | ★ 面积(㎡) |
layout_label | string | ★ 户型标签(2室1厅) |
rent_monthly | int | ★ 月租(元/月),照实传贵方月租即可;月租→夜价的 /30 折算发生在平台侧(C 端按晚售卖口径)。2026-09 起为可选:与 price_night 至少给一个(短租房源可直接给夜价,见下) |
price_total | int | ★ 总价(元),newhouse/resale 频道用 |
promo_price | int | ★ 优惠价(元)。当前为展示位:C 端据此打「首月特惠」标签,不参与订单计价(营销价真实成交需另行排期) |
total_qty | int | ★ 总间数(1-999,缺省 1)。该房型同规格可订单元数:每晚可订量 = total_qty − 当晚已订(可用 stay-calendar/set 的 qty 按晚覆盖放出间数,见 5.1);下单可选多间(rooms),订单金额按 逐晚价 × 间数 计。调低不得低于未来晚已订间数,否则 400 |
price_night | int | ★ 夜价(元/晚),写入 units.ext.price_night。2026-09 起两个频道都生效:默认夜价取值顺序 = price_night > rent_monthly/30 > price_from/30(rental)/ price_from(minsu)。房态日历的逐晚覆盖价仍优先于以上全部(见 5.1) |
min_stay_nights | int | ★ 最短连住(晚),写入 units.ext.min_stay_nights。2026-09 起下放到户型:生效顺序 = 户型 > 房源 > 频道默认(rental/minsu 默认均 15 晚;下限 rental 1 / minsu 15,上限 365)。传 null 清除(回落房源级)。整栋单(不指定户型)按排序最前的户型执行,与取消政策同一套回退 |
default_night_price | — | 只读出参(2026-09):该户型的默认单夜价(按上面的顺序算好)。C 端详情页/下单页直接读它,不要再用 rent_monthly/30 自行折算——否则会与成交价脱节 |
default_closed | bool | ★ 默认关房(2026-09,写 units.ext.default_closed):开启后只有你们推送过放出量的晚才可订,没推过的晚一律不可订——多渠道商家防超售(见 3.6)。缺省关闭;null 清除 |
room_profile | object | ★ 房间档案(2026-09 开放,写 units.ext.room_profile):房源简介 / 面积口径 / 窗户 / 入住人数 / 床位 / 厨房 / 吸烟 等 21 个字段,C 端「房间档案」卡直接渲染(见 3.7)。传 null 清除 |
min_stay_nights_source | — | 只读出参:最短连住这个生效值的来源,unit(户型级显式配置)/ project(房源级)/ default(频道默认)。后台表单靠它区分「显式配的」与「继承来的」,避免保存时把继承值固化 |
cancel_policy | object | ★ 免费取消政策(房型级),写入 units.ext.cancel_policy:{enabled, days_before, cutoff_time};免费取消窗口 = 入住日往前推 days_before(0-30,0=入住当天)天的 cutoff_time(HH:mm)时刻,窗口外 / 未开通一律不可取消不可退 |
tags / unit_spec / cover_image / sort_order | — | ★ 标签 / 房型说明 / 封面 / 排序(sort_order 升序展示,缺省 99,用于主推房型排前) |
amenities | string[] | ★ 配套标识数组,按下表 10 个 id 传(C 端按 id 渲染图标) |
ac 空调 · washer 洗衣机 · fridge 冰箱 · heater 热水器 · lock 智能锁 ·
wifi 宽带 · tv 电视 · hood 油烟机 · microwave 微波炉 · induction 电磁炉。
不传 = C 端回落展示全部 10 项;传未知 id 不渲染。枚举字典化(随接口下发)在平台排期内。
| 字段 | 说明 |
|---|---|
project_id + unit_id | 库存归属;unit_id=0 或缺省表示项目级(整栋 / 不限房型,容量恒 1)。下单冲突口径:整栋单查全项目任一户型,指定户型单查「项目级 + 该户型」 |
stay_date | 晚(YYYY-MM-DD,入住当晚)。写入窗口:单次 ≤ 400 晚、可多次滚动写更远(存储无总上限);C 端日历可订窗口 = 当月起 12 个月,建议对账口径与其对齐 |
qty | ★ 放出间数覆盖(1-999;多间口径 2026-09-10)。该晚实际投放的可订间数;不传 / 传 null = 用房型 total_qty。项目级(unit_id=0)不收 qty。不得低于该晚已订间数(booked_qty),否则 400。与 available_qty 语义不同,同一次调用只能传一个 |
available_qty | ★ 净可售(2026-09 方案 B,推荐多渠道商家用):0-999,直接传「这一晚平台还能卖几间」——已经在你们那边扣掉其他渠道售出与暂不可售,可以按你们自己的口径算,不必关心平台卖了多少。平台记下推送时点的已订数作为基线,之后只有平台自己卖掉的才从这个数里扣,取消自动加回;同时以「物理余量(total_qty − 已订)」封顶,防对账漏项导致超售。详见 3.5 |
status | open 可订(默认,未设置过的晚即可订,放出 = total_qty)/ blocked 关房(商家;已订晚 booked_qty>0 不可关房,须先取消订单)/booked 已订满——2026-09-10 起为派生态(剩余 remaining ≤ 0 时出参给出),由平台订单占用计数自动产生,取消自动释放,接口不可直接写 |
booked_qty / remaining | 出参随日历查询下发:该晚已订间数 / 剩余可订间数。remaining 按该晚的放出口径计算:qty(放出总量)= max(0, qty − booked_qty);available_qty(净可售)= clamp(qty − (booked_qty − 基线), 0, total_qty − booked_qty)(取消释放不会越过物理余量)。关房为 0。多间房型当晚 0 < remaining < qty 时状态仍为 open——部分可订,C 端展示「仅剩 X 间」 |
available_qty(出参) | 回显该晚的净可售口径值:null = 该晚按旧「放出总量」口径;有值 = 你们上次推的 available_qty。set 响应还会逐日返回 days[](qty / qty_base / booked_qty / remaining),推完即可对账,不必再查一次日历 |
price_night | 当晚价格覆盖(元),未覆盖回落默认夜价;户型级 > 项目级 > 默认。2026-09-10 起参与下单计价:订单金额 = 逐晚(覆盖价 || 默认夜价)合计 × 间数,与 C 端日历展示同口径——周末 / 节假日分档即按日期批量覆盖实现 |
blocked=关房(可带价可不带;已订晚不可关);open + price_night 和/或 qty=覆盖价 / 放出间数(只改其一就只传其一,另一个保持原值);open 且价、间数均不传=恢复默认(清差异行;有占用的晚保留占用计数、仅清覆盖回默认)。一次调用一个 status 作用于整批 dates。
GET /api/juzhu/projects/{id}/stay-calendar?month=YYYY-MM&unit_id=(公开只读,用于上下架 / 房态验收)返回逐晚三态 + 价格 + qty/booked_qty/remaining 间数 + 最短连住 + 保险标识,与 C 端日历渲染一致。
C 端房源卡上的价格由平台计算并随接口下发(price_from_display / price_unit / price_note),贵方无需传、也不要在自己页面另算一套。单位口径:minsu 与带「旅居」tag 的 rental 按晚;其余 rental 按月(起价语义,price_from 缺省时回落户型默认夜价 × 30)。
按晚房源的取值规则:从今天起按自然月向后扫描(最多 12 个月,与 C 端可订窗口同口径),取第一个存在可售间夜的月份,该月内最低单夜价即展示价;扫满仍无可售 → 不展示价格,文案「暂无可订」。
| 某一晚的情况 | 能不能卖 | 单价取谁 |
|---|---|---|
| 没有房态记录(默认态,绝大多数晚属于这种) | ✅ 能 | 默认夜价(price_night > 月租/30 > 起价/30) |
有记录,blocked(关房) | ❌ 不能 | — |
有记录,open + 有覆盖价 | ✅ 能 | 该覆盖价 |
有记录,open + 无覆盖价 | ✅ 能 | 默认夜价 |
该晚已订满(remaining ≤ 0) | ❌ 不能 | — |
status=open 的记录」是不够的——平台库存模型是没有记录 = 默认可订,差异行只在关房 / 改价 / 改放出间数 / 被订时才产生。若只扫有记录的晚,会把绝大多数可订房源误判成「暂无可订」。
available_qty,多渠道商家)如果同一批房间你们同时在别的渠道卖(OTA、直客、自己的小程序…),或者有房间临时不可售(未保洁、维修),用 available_qty 比 qty 更省事:直接把「这一晚平台还能卖几间」推上来,按你们自己的口径算就行。
| 字段 | 语义 | 平台怎么算 remaining |
|---|---|---|
qty(旧) | 该晚对平台开放的总量,含平台已卖掉的 | max(0, qty − 已订)——所以你们必须先查一次平台已订多少,有竞态 |
available_qty(推荐) | 该晚净可售,按你们的口径(已扣他渠道与不可售) | 记下推送时点的已订数作基线,clamp(可用 − (已订 − 基线), 0, 物理余量)——平台之后卖掉的才扣,取消自动加回,无需你们再算 |
举个你们反馈里的例子:房型 total_qty=6,平台已售 2、其他渠道售 1、还有 1 间未保洁 → 你们算出「能卖 2 间」,直接推 available_qty: 2:
available_qty: 1,基线刷新为当时的已订数 → 剩余 1。total_qty − 已订 封顶,不会卖超。所以推大不会超售,推小才会少卖——对账宁可略保守。
qty 与 available_qty 同一次调用只能传一个(同时传 400)。任一时刻该晚只属于一种口径;用 qty 写回会把基线清空,回到旧语义。
default_closed,可选开关)净可售解决的是「推过的晚怎么算」,默认关房解决的是「没推过的晚怎么办」。默认情况下平台是「没推过的晚 = 可订、放出量 = total_qty」——对多渠道商家这很危险:你们在别处卖掉、或临时不可售的晚,只要没推过,平台照样会放出去卖。
把房型的 default_closed 设为 true(写 units.ext,可经 units/update 或后台配置)后:
qty 或 available_qty 都算);remaining = 0,下单 400);只设过夜价、没设放出量的晚也算没推过;建议需要多渠道对账的房型开启,并按「未来 12 个月」滚动推送放出量(见 5.1)。
room_profile)房源细节统一放在户型级 units.ext.room_profile(来自入驻时的「房源字段」表),经 units/create / units/update 的 room_profile 对象整体写入,C 端详情页「房间档案」卡直接渲染。规则:
null 清除整块。null / 空串)视为未传。\n)。| 字段 | 类型 | 说明 |
|---|---|---|
introduction | string ≤1000 | 房源简介:空间、布局、风格、适用人群、与本房型差异点 |
area_type | enum | 面积口径:building 建筑面积 / usable 使用面积 |
shared_spaces | string ≤300 | 共享空间(如共享厨房、花园;无则填「无」) |
window_type | enum | 窗户类型:exterior 外窗 / interior 内窗 / none 无窗 |
window_count | int 0-20 | 窗户数量 |
window_openable | bool | 窗户是否可开启 |
max_guests / max_adults / max_children | int | 最大入住人数 1-99 / 成人上限 1-99 / 儿童上限 0-99 |
child_age_policy | string ≤300 | 儿童适住年龄(如「0-12 岁;婴幼儿须由监护人陪同」) |
extra_guest_policy | string ≤500 | 加人 / 加床政策:是否允许、最多人数、费用、是否含床品早餐 |
beds | string ≤500 | 卧室与床位明细(如「卧室1:1 张 1.8×2.0m 大床;客厅:1 张沙发床」) |
bath_hot_water | string ≤300 | 洗浴与热水(如「淋浴 · 24 小时热水」) |
smoking | enum | 吸烟属性:no 全屋禁烟 / designated 仅指定区域 / allowed 可吸烟 |
kitchen | string ≤500 | 厨房可用性:独立/共享/简易/不可用;厨具餐具、调料与做饭规则 |
climate | string ≤300 | 空调 / 暖气覆盖(如「全屋空调 · 地暖」) |
network | string ≤200 | 网络(如「免费 Wi-Fi」) |
cleaning_frequency | string ≤200 | 打扫频率(如「一客一扫」) |
linen_frequency | string ≤200 | 床品 / 毛巾更换频率(如「一客一换」) |
feature_image | string ≤1000 | 房间示意图地址:http(s) URL 或站内路径(/、assets/、uploads/);禁换行与引号 |
feature_image_caption | string ≤120 | 房间示意图说明 |
room_profile 只放一条房间示意(feature_image)+ 一堆文字描述;多张实拍图走图集(4.11 photos/sync,带分类与排序)。两者互不影响。
以下示例省略签名三件套(vendor_id / timestamp / sign),实际每个请求体都必须携带(见 §2,或直接用 §7 调试台)。
{}
→ 200 {
"code": 0, "list": [
{ "id": 4, "name": "贵阳", "slug": "guiyang",
"districts": [ { "id": 41, "name": "观山湖区", "slug": "guanshanhu" } ] }
], "total": 1
}
{
"channel": "rental", // 可选过滤:channel / status / city_id / keyword
"status": "online"
}
→ 200
{
"code": 0, "message": "success",
"list": [
{
"id": 1611, "name": "示例·观山遇见旅居", "channel": "rental",
"status": "online", "price_from": 2400,
"min_stay_nights": 15,
"insurance": ["switch_rental", "property"],
"insurance_types": [ { "key": "switch_rental", "label": "换租保险", "icon": "🔄" }, /*…*/ ]
}
],
"total": 1
}
{ "id": 1611 }
→ 200 { "code": 0, "project": { /* 同 4.1,另含 address/tags/ext 等 */ }, "units": [ /* 户型数组 */ ] }
{
"name": "观山湖·遇见旅居",
"channel": "rental",
"city_id": 4,
"district_id": 41,
"address": "观山湖区 · 示例大道 88 号",
"tags": ["旅居", "近地铁"],
"price_from": 2400, // 选填(2026-09);不传则各户型自带价
"contact_phone": "13800001234", // 仅入库(虚拟号绑定),永不回显
"min_stay_nights": 15, // 房源默认值;户型级优先(见 3.2 / §5.2)
"insurance": ["switch_rental", "property"], // 保险标识(见 §6)
"units": [
{ "name": "一居 45㎡", "layout_label": "1室1厅", "area_sqm": 45, "rent_monthly": 2400 },
// 短租房源可只给夜价(rental 同样生效,2026-09):
{ "name": "庭院房", "area_sqm": 30, "price_night": 268, "min_stay_nights": 3 }
],
"status": "draft" // 缺省 draft;draft/offline 不出 C 端
}
→ 200 { "code": 0, "message": "success", "project": { "id": 1611, "status": "draft", /*…*/ } }
{
"id": 1611,
"price_from": 2680,
"tags": ["旅居", "近地铁", "含早"],
"insurance": ["hotel_cancel", "property"],
"min_stay_nights": 20,
"online_booking": true,
"online_payment": true
}
→ 200 { "code": 0, "project": { /* 更新后全量 */ } }
不可改:city_id、channel、owner_vendor_id;改 name 会同步重生成唯一 slug。
{ "id": 1611, "status": "online" } // online 上架 / offline 下架 / draft 转草稿
→ 200 { "code": 0, "message": "success", "id": 1611, "status": "online" }
price_night 或 rent_monthly,也可由房源 price_from 兜底);③ 图集 ≥ 7 张 + 封面;④ 评级 passed。任一不满足返回 400 并指明是哪个户型缺价。C 端目录有 ≤ 15 秒缓存,上架后最迟 15 秒可见、下架后最迟 15 秒消失。
{ "project_id": 1611, "name": "两居 68㎡", "layout_label": "2室1厅",
"area_sqm": 68, "rent_monthly": 3200, "total_qty": 3,
"room_profile": { "max_guests": 4, "beds": "卧室1:1.8×2.0m 大床" } } // 房间档案(见 3.7)
→ 200 { "code": 0, "unit": { "id": 3101, /*…含 room_profile 已解析对象…*/ } }
{ "id": 3101, "rent_monthly": 3380, "price_night": 128, "total_qty": 5,
"min_stay_nights": 3, // 户型级最短连住(2026-09);null 清除回落房源级
"default_closed": false, // 默认关房(见 3.6);null 清除
"room_profile": { "window_type": "exterior", "smoking": "no" }, // 房间档案(见 3.7),只合并传入的键
"cancel_policy": { "enabled": true, "days_before": 1, "cutoff_time": "18:00" } }
→ 200 { "code": 0, "unit": { /*…含 default_night_price / min_stay_nights / room_profile 生效值…*/ } }
min_stay_nights(rental 1-365 / minsu 15-365,越界 400);传 null 或空串清除,回落房源级 → 频道默认。整栋单(不指定户型)按排序最前的户型执行。出参附 min_stay_nights_source(unit/project/default)。room_profile(见 3.7),只合并传入的键、未传的保持原值;传 null 清除整块;未知键静默丢弃,取值/长度非法 400。cancel_policy(非法 days_before/cutoff_time 返回 400);传 null 清除(= 未开通,客户不可取消)。免费取消窗口 = 入住日往前推 days_before 天的 cutoff_time 时刻;客户在窗口内取消自动退款并释放房态。total_qty 须为 1-999;调低到低于未来晚已订间数会返回 400(先处理订单再缩容)。{ "id": 3101 }
→ 200 { "code": 0, "message": "success" }
{ "project_id": 1611, "unit_id": 0, "month": "2026-12" }
→ 200 {
"code": 0, "month": "2026-12", "base_price_night": 80,
"min_stay_nights": 15, "insurance": ["switch_rental", "property"],
"days": [
// 多间口径:房型 total_qty=3,19 晚被订 2 间(部分可订),20 晚已关房
{ "date": "2026-12-19", "status": "open", "price": 80, "qty": 3, "booked_qty": 2, "remaining": 1 },
{ "date": "2026-12-20", "status": "blocked", "price": 80, "qty": 3, "booked_qty": 0, "remaining": 0 },
{ "date": "2026-12-21", "status": "open", "price": 80, "qty": 3, "booked_qty": 0, "remaining": 3 }
]
}
{
"project_id": 1611,
"unit_id": 3101, // 可选;缺省 = 房源级图集(只动房源级,不会碰户型级)
"photos": [
{ "url": "https://cdn.example.com/p1.jpg", "category": "bedroom", "sort": 0, "is_cover": true,
"external_id": "IMG-1001" }, // 你们那边的稳定图 id(URL 带签名会变,靠它认同一张图)
{ "url": "https://cdn.example.com/p2.jpg", "category": "living", "sort": 1,
"width": 1920, "height": 1080, "size_bytes": 480000 } // 声明值可选,见下「校验」
]
}
→ 200 {
"code": 0, "applied": 8, "added": 5, "updated": 3, "removed": 2,
"cover": "https://cdn.example.com/p1.jpg", "truncated": false,
"gallery_total": 12, "warnings": [],
"photos": [ { /* 覆盖后的完整图集(含 category_label),可直接用来核对 */ } ]
}
| 字段 | 说明 |
|---|---|
url | ★ 必填,http/https 绝对地址,≤500 字符;同一实体内不得重复 |
category | ★ 图片分类,可选(缺省 other):bedroom 卧室 / kitchen 厨房 / bathroom 卫生间 / living 客厅 / nearby 周边 / other 其他。未知值 400 |
sort | ★ 展示顺序,从小到大;不传按数组顺序。平台归一化为 0..n-1 落库,C 端据此排序 |
is_cover | ★ 封面;多张标记时取 sort 最靠前的那张。列表里一张都没标 → 取排序第一张。覆盖后自动同步 cover_image |
external_id | ★ 你们侧的稳定图 id(≤120 字符)。匹配键:external_id 优先、URL 兜底——匹配上的原地更新(图片 id 不变、C 端引用不抖),否则插入/删除。URL 带签名会变,建议始终带上 |
width / height / size_bytes | ★ 可选声明值:推送时即时校验(分辨率 ≥800×600、单图 ≤10MB,越界 400,无网络开销);真伪由上架抽检核对 |
sort/数组顺序截取前 100 张,响应回 truncated: true + warnings(不静默丢图);
④ 覆盖后若该房源图集合计不足 7 张,响应会带一条 warnings 提示(不阻断——「≥8 张」是上架闸,不是每次覆盖的闸)。
projects/status online 时会真拉取封面 + 排序靠前的图(默认 2 张)核对大小与分辨率。
确定性不合格(超 10MB / 小于 800×600 / 非图 / 地址非法)→ 400 拒绝上架;
仅网络不可达(超时、DNS、非 200)→ 放行并在响应里回 warnings(CDN 抖动不卡上架)。
抽检会读到你们的图片,平台只读必要字节、不落盘、不转存。
{
"project_id": 1611,
"unit_id": 3101, // 可选;缺省 = 房源级图集
"file_path": "https://cdn.example.com/p1.jpg", // 必填,URL ≤ 500 字符
"is_cover": true, // 设为封面(同实体原封面自动让位)
"category": "bedroom", // 图片分类(可选,缺省 other)
"external_id": "IMG-1001", // 稳定图 id(可选):幂等匹配键
"sort_order": 0 // 不传 = 追加到末尾(2026-09 起传入即生效)
}
→ 200 { "code": 0, "updated": true, "photo": { /* 命中已有图时原地更新(updated=true) */ } }
图集元素字段:id / entity_type / entity_id / file_path / category / category_label / external_id / is_cover / sort_order。category_label 为中文名,C 端直接渲染。
units/create / units/update / projects/detail 的 units[] 同口径):
id / name / slug / area_sqm / layout_label / rent_monthly / price_total / promo_price / total_qty / sort_order / cover_image / tags / amenities / unit_spec / ext,
外加平台算好的生效值:default_night_price(默认夜价)、min_stay_nights + min_stay_nights_source(连住下限与来源)、cancel_policy / cancel_policy_text(取消政策及中文文案)、room_profile(已解析的对象,不用自己 parse ext 字符串)。
photos/sync 单次覆盖不卡这个下限——它是上架闸,便于先建后补),否则 projects/status online 返回 400「上架前须至少上传 8 张房源照片」。
上架闸之一是平台评级审核(rating_status:draft → pending → passed / rejected;rental=好房子 4 维,minsu=旅居彩贝 5 维)。提审与查进度直接走开放接口,不必线下催单:
{
"id": 1611,
"dims": { "comfort": 4.5, "green": 4, "tech": 4.6, "safety": 4.4 }
// minsu 频道为 scenery / facilities / service / location / culture
}
→ 200 { "code": 0, "rating_status": "pending", "rating_code": "SY-RENT-1611", "dims": { /*…*/ } }
{ "id": 1611 }
→ 200 {
"rating_status": "rejected", "rating_code": "SY-RENT-1611",
"dims": { /* 已提交自评分 */ }, "missing_dims": [],
"dims_meta": [ { "key": "comfort", "label": "舒适", "icon": "🛋" } /*…*/ ],
"note": "安全维度证明材料不足", // 驳回原因;passed/rejected 的复核时间见 reviewed_at
"submitted_at": "2026-09-10T03:20:11Z", "reviewed_at": "2026-09-10T07:41:00Z"
}
dims 须覆盖该频道全部维度、数值 0–5;缺维度 / 越界 / 未知维度返回 400 并指明字段。rejected)修订后可重新提审;提审会清除上一轮 note。平台复核通过(passed)后 projects/status online 才会放行。客户在 C 端提交预订单后,商家经开放接口完成接单闭环:定时拉取订单 → 确认生效或拒单 → 拒单自动释放房态。订单按签约商家隔离,联系人手机号只回掩码(139****5678)。
price_night > round(月租/30) > round(起价/30)(minsu 最后一档为 price_from 原值)。整栋单(不指定户型)价格基准 = 房源起价,起价缺失时回落排序最前户型。金额再 × 间数;算不出价的订单直接拒绝(400),不会 0 元成单。佣金按订单金额快照锁定(规则 20)。
{
"status": "pending", // 可选过滤:status / pay_status / project_id
"project_id": 1611
}
→ 200 { "code": 0, "list": [ {
"id": 36, "order_no": "BKG-RENTAL-00036", "project_name": "观山湖·遇见旅居",
"checkin": "2026-12-19", "checkout": "2027-01-08", "nights": 20,
"price_total": 1600, "commission_rate": 8.00, "commission_fee": 128.00,
"status": "pending", "pay_status": null,
"contact_name": "张**", "contact_phone": "139****5678"
} ] }
commission_rate / commission_fee 为下单时锁定的费率与佣金快照(元),结算按快照执行、商家后续费率调整不追溯;未差异化商家按全局基准(缺省 10%)。{ "id": 36 } → 200 { "code": 0, "booking": { /* 同上,单条 */ } }
{ "id": 36 } → 200 { "code": 0, "status": "confirmed" }
{ "id": 36 }
→ 200 { "code": 0, "status": "cancelled", "pay_status": null }
| 字段 | 取值 | 说明 |
|---|---|---|
status | pending → confirmed / cancelled | 确认后订单生效;取消为终态,不可再变更 |
pay_status | unpaid / paid / refunded 或 空 | 由订单交易方式决定,与频道无关:在线支付单为 unpaid 起步;在线预订单为空,商家确认后线下收款 |
| 确认前置 | — | unpaid 的订单不可确认(400),支付完成后可确认;cancelled 不可再变更 |
| 拒单/取消 | — | 自动释放占用的房态晚;已支付订单 pay_status 标记 refunded |
客户动作触发的订单变更,平台会主动推送签名事件到你为商家配置的通知地址(接入单里提供 URL 即可),不必轮询等单:
| event | 触发时机 | 商家应做什么 |
|---|---|---|
booking.created | 客户提交预订单 | 备房;预付单等待支付到账 |
booking.paid | 预付单支付完成(民宿民宿) | 此时方可确认订单 |
booking.cancelled | 客户取消(商家自己拒单不会推送) | 释放已备房源 |
推送为 POST JSON,body 即开放接口同款结构:event + vendor_id + order(订单对象,手机号不外传)+ timestamp + sign。验签与开放接口同一算法(对去掉 sign/timestamp 的参数扁平排序后 HMAC-SHA256),收到后先验签再处理:
// Node 验签示例(与平台 hmac_auth.cjs 同算法)
app.post('/hooks/booking', (req, res) => {
const body = req.body;
const payload = { ...body };
delete payload.sign;
const flat = flatten(payload); // 与请求签名同一套 flatten
flat.timestamp = String(body.timestamp);
const expect = crypto.createHmac('sha256', HMAC_KEY)
.update(Object.keys(flat).sort().map(k => k + '=' + flat[k]).join('&')).digest('hex');
if (expect !== String(body.sign).toLowerCase()) return res.status(401).end();
// 处理 body.event / body.order …
res.status(200).end('ok'); // 2xx 即视为送达
});
bookings/list 定时对账兜底(推荐粒度:每分钟拉一次 status='pending')。订单明细里不含客户明文手机号。
{
"project_id": 1611,
"unit_id": 0, // 0 或缺省 = 项目级(整栋 / 不限房型,容量恒 1)
"dates": ["2026-12-10", "2026-12-11"],
"status": "blocked", // 可选:blocked 关房 / open 开房;缺省 = 保持各晚现状(只改价/净可售)
"price_night": null, // blocked 可同时设价;open + 价格 = 夜价覆盖;open + null = 不改价
"qty": null, // ★ 放出总量覆盖(1-999,仅房型级):open + qty = 该晚只放 N 间;不传 = 用 total_qty
"available_qty": null // ★ 净可售(0-999,推荐,见 3.5):与该晚的 qty 二选一;写回 qty 会把基线清空
}
→ 200 {
"code": 0, "affected": 2, "dates": 2,
"days": [ // 推完即可对账(不必再查一次日历)
{ "date": "2026-12-10", "status": "open", "qty": 2, "qty_base": 2,
"available_qty": 2, "booked_qty": 2, "remaining": 2 }
]
}
status——对应间夜保持原状态(blocked 晚保持关房、open 晚保持可订),无差异行的晚按默认 open 建行。status: open 且价、放出量均不传 = 显式「恢复默认」。[{ "stay_date": "2026-12-10", "available_qty": 0, "status": "open" },
{ "stay_date": "2026-12-11", "price_night": 188 }]
字段缺省含义与顶层一致(status 缺省 = 保持现状)。平铺字符串数组 + 顶层字段形态继续可用(所有晚同值)。available_qty: 0 + status: open 即「该晚 0 间可售」——剩余派生为 0、C 端显示售罄,效果等同关房,且随时可推一个正数恢复;不必在 open / blocked 之间切换语义。booked_qty>0)不可关房:返回 400 并列出日期,须先取消订单;改价 / 调放出量不受限。total_qty(除非该房型开了「默认关房」,见 3.6);「恢复默认」= status=open 且价、放出量均不传:清除差异行,有占用的晚保留占用计数、仅清覆盖回默认。qty 低于该晚已订间数返回 400(先取消订单或调高);qty 改变只影响当晚可订余量,已订单不受影响。剩余 = max(0, qty||total_qty − booked_qty)。qty 与 available_qty 同时传返回 400。详见 3.5。open + price_night;平日不传即回落默认。订单占用不清除当晚覆盖价,取消释放后商家差异行(价 / qty / 关房)原样保留。旅居/短住按连续入住售卖:平台缺省口径为 rental=15 晚、minsu=15 晚。商家可覆盖,2026-09 起生效顺序为「户型 > 房源 > 频道默认」:户型级写 units.ext.min_stay_nights(units/create / units/update 直接传 min_stay_nights),房源级 projects.ext.min_stay_nights 降级为房源默认值。取值范围:rental 1–365 晚,minsu 15–365 晚、不得低于 15 晚(越界返回 400)。
整栋单(下单不指定户型)按排序最前的户型取值——与取消政策同一套回退,因此「最短连住」和「取消政策」两条住宿规则都可以只在户型上配,不必记住哪个在房源、哪个在户型。
三处同口径校验:C 端日历选段、下单页、平台下单接口 POST /api/juzhu/booking(不足返回 400「该房源须连住至少 N 晚」)。下单成功即占用这些晚,取消自动释放。户型数组与房态日历出参均随行返回生效值 min_stay_nights,页面直接读,不要回落到房源级或自设默认值。
projects/create / projects/update 按房源配置两个独立布尔能力:online_booking = 客户在线选房并提交订单、商家确认后线下收款;online_payment = 客户在线选房后进入收银台、支付完成再由商家确认。两项可同时开启,但至少开启一项,与 rental/minsu 频道无关;新建时两项均省略则默认仅开启 online_booking。两项都开时,C 端由客户选择;接口下单用 transaction_mode: "booking" | "payment" 指定,缺省优先 booking。catalog / 详情 / 房态日历出参均返回两个能力位,并保留 bookable 作为“至少一项可用”的兼容汇总字段。
商家为房源配置的「入住保障」,随 catalog / 详情 / 房态日历下发 C 端展示。枚举由平台统一维护,接口只接受以下 key,未知 key 返回 400:
| key | 名称 | 保障口径 |
|---|---|---|
switch_rental | 换租保险 | 租期到期换租衔接期内的房租损失与搬迁费用 |
hotel_cancel | 酒店取消险 | 行程变更按规则退改,未入住部分房费可退 |
property | 财产保险 | 入住期间屋内财产与房屋主体意外损坏 |
配置入口:projects/create / projects/update 传 insurance 数组;清空传 []。出参同时给出 insurance(key 数组)与 insurance_types(含 label/icon,可直接渲染)。
默认行为:评级复核通过后,商家仍需自行调 projects/status 推 online。若希望复核通过即自动上架,在 projects/create 或 projects/update 传 auto_publish: true(存 ext.auto_publish,随时可传 false 关闭)。自动上架复用与商家推送完全相同的上架闸(评级通过 / 逐户型默认夜价 > 0 / 图片抽检)与交易方式校验:闸全过 → 直接 online;任一不过 → 保持 draft,具体原因通过 rating.reviewed webhook 的 auto_publish.reason 带回,商家补齐后自行推送上架即可。
评级复核(通过 / 驳回)完成时,平台向商家 webhook_url POST 一条签名通知,商家无需再轮询 rating/status。webhook_url 由商家自助配置:B 端后台「房源管理」(b-listing-mgmt.html)顶部「🔔 Webhook 通知」卡填写并保存,支持一键发送 webhook.test 连通性测试(同步回传送达结果);推送与测试统一经平台出网防护层(内网 / 环回 / 云元数据地址拒绝)。
| 字段 | 说明 |
|---|---|
event | rating.reviewed |
vendor_id | 商家 id |
data.project_id / data.code / data.channel | 房源 id / 评级编号(SY-RENT-… / MZ-…)/ 频道 |
data.rating_status | passed / rejected |
data.rating_note / data.reviewed_at | 复核备注 / 复核时间(ISO) |
data.auto_publish | {enabled, attempted, result: published|blocked|skipped, reason?, warnings?};未开启 auto_publish 时 result=skipped |
timestamp / sign | 毫秒时间戳与 HMAC-SHA256 签名,对 {event, vendor_id, data} 按第 2 章同算法计算,商家按同规则验签 |
推送 5 秒超时,失败重试 3 次(5s/30s/120s)后放弃——webhook 只通知不担保必达,商家以 projects/rating/status 拉取对账兜底。响应返回任意 2xx 即视为送达。
以下为首批接入方答疑结论,与线上实现同步校准;与本页正文冲突处以正文为准。
| 问题 | 结论 |
|---|---|
| channel 怎么传?保租房是不是 channel? | 字符串枚举 rental / minsu / newhouse / resale / trade,缺省 rental,创建后不可改。长租 + 旅居统一 rental;「保租房」是平台专题(topic)不是频道,用 tags 表达(["保租房"])。支持在线预订的只有 rental / minsu。 |
| city_id / district_id 有枚举接口吗? | 有:regions/list(4.1),只出该商家开放城市及其行政区;未配置城市约束则出全量。 |
| 有经纬度字段吗? | 暂无,只有 address 文本。房源级 POI 打点属新需求,请书面提给平台评估。 |
| slug 可以传我方房源 / 房型编号吗? | 可以(同频道内唯一,未做字符集限制)。传入已存在的 slug 不报错、会静默加 -2 后缀,创建前先 projects/list 核对防重;接口暂无按 slug 幂等 upsert,已列入平台排期。 |
| 只有封面图吗? | 不止:图集走 photos/add(4.11),上架硬性要求 ≥ 7 张 + 封面。 |
| price_from 是基础价吗?平日 / 周末 / 节假日价怎么表达? | price_from 是选填起价(rental=元/月、minsu=元/晚)+ 默认夜价的最后兜底,不分档。分档 = 房态日历逐晚 price_night 覆盖(5.1),订单金额按逐晚覆盖合计。不传起价时由各户型的价承担(见下条)。 |
| 我不按月租卖,只按每晚定价,可以吗? | 可以(2026-09 起)。给户型的 price_night 即可,rental 频道同样生效;rent_monthly 与 price_from 都可以不传。默认夜价顺序 = price_night > 月租/30 > 起价/30。 |
| 不传 price_from,C 端卡片价格显示什么? | 按展示价三件套(3.4)自动算:带「旅居」tag 的 rental 与 minsu 按晚,取最低可售单夜价(从今天起按自然月向后扫 12 个月,取第一个有可售间夜的月份内的最低价);其余 rental 按月,起价缺失时用户型默认夜价 × 30。全窗口无可售时卡片显示「暂无可订」。贵方无需做任何事。 |
| 月租 /30 折算发生在哪侧? | 平台侧(C 端按晚售卖口径):默认夜价 = round(月租/30)。2026-09 起户型 price_night 优先于它(两个频道一致);详情页/下单页直接读接口下发的 default_night_price,不要自己折。 |
| 我们同时在别的渠道卖,怎么让平台显示正确的可售数? | 用 available_qty(净可售,2026-09)直接推「这一晚平台还能卖几间」,按你们自己的口径算(已扣他渠道 / 不可售);平台记基线,之后只扣平台自己卖掉的,取消自动加回,并按物理余量封顶防超售。详见 3.5。 |
| 没推过的日期,怎么让它默认不可订? | 把房型 default_closed 设为 true(2026-09,见 3.6)。之后只有你们推过放出量的晚才可订,避免别处卖掉/临时不可售的晚被平台放出去。缺省关闭,不影响存量房源。 |
| 换图 / 撤图怎么做?现在只能一张张加。 | 用 photos/sync(2026-09,见 4.11.1):把该实体当前完整的图集传上来,平台自动移除不在列表里的旧图、保留并更新列表内的。单张的 photos/add 也保留,且同 URL / 同 external_id 重推 = 原地更新,不再堆重复图。 |
| 图片 URL 带签名、每次都不一样,怎么让平台认出是同一张图? | 传 external_id(你们侧的稳定图 id)。匹配键是 external_id 优先、URL 兜底——带上它,换签名 URL 也只是原地更新那张图,图片 id 不变、C 端引用不抖。 |
| 图集要几张?大小和分辨率有要求吗? | 上架需合计 ≥ 7 张(房源级 + 户型级)且至少 1 张封面;单次 photos/sync 上限 100 张(超出按 sort 截取前 100 并回 truncated + 告警)。单图 ≤10MB、分辨率 ≥800×600:推送时可带 width/height/size_bytes 声明值即时校验;平台在上架时会抽检(默认封面 + 排序靠前的 2 张)真拉取核对。 |
| 房间档案(简介 / 窗户 / 床位 / 入住人数…)怎么传? | 走户型级的 room_profile 对象(2026-09 开放,见 3.7):units/create / units/update 传 room_profile: {...} 即可,只合并传入的键、未传的保持原值,传 null 清除整块。字段清单与取值范围见 3.7;越界会 400 并报出字段中文名与可选值。 |
| 抽检拉图会不会拖慢上架?拉不到图怎么办? | 只拉 2 张、只读必要字节、不落盘。仅网络不可达(超时 / DNS / 非 200)时放行并在响应里回 warnings——你们的 CDN 抖动不会卡住上架;只有确定性不合格(超 10MB / 小于 800×600 / 非图)才拒绝。 |
remaining 是怎么算的?我能自己传吗? | 一律只读,平台算好下发,接口不接受传入。算法随该晚的放出口径:qty(放出总量)= max(0, qty − 已订);available_qty(净可售)= clamp(可用 − (已订 − 基线), 0, 物理余量)。关房 / 未放出(默认关房)= 0。 |
| promo_price 会影响成交价吗? | 不会,当前是「首月特惠」展示标签位;营销价真实成交需另行排期。 |
| amenities 没有枚举怎么映射? | 按下表 10 个 id 传(3.2):ac / washer / fridge / heater / lock / wifi / tv / hood / microwave / induction。不传 = C 端回落展示全部;未知 id 不渲染。枚举字典化在平台排期。 |
| 联系电话必须是 400 吗?后续能改吗? | 相反:须为 11 位手机号(1 开头),400 号码会被拒。号码仅入库用于 C 端虚拟号实时绑定、任何接口不回显;可用 projects/update 更新。 |
| owner_vendor_id 是什么? | 签名商家自动写入的数据归属标记,不可传不可改;一切接口按它行级隔离,订单佣金按它取商家档费率。 |
| 首推后是什么状态?有审核吗?不通过呢? | 新建一律草稿(传 online 创建直接 400)。上架前须过平台评级审核:rating/submit 提审 → pending → 平台复核 passed / rejected(附驳回原因 note,修订后可重新提审)。进度用 rating/status 自查(4.12)。 |
| 上架后更新房源信息要重新提审吗?外网会下架吗? | 不须提审、不下架:内容更新免审即时生效(目录 ≤ 15 秒缓存),外网持续可售。当前契约即「免审直更」,如业务要求重大变更走审核请向平台提出。 |
| 房态 / 房价日历最长设多久?C 端展示多久? | 单次 ≤ 400 晚、可滚动写更远;C 端可订窗口 = 当月起 12 个月,建议按 12 个月滚动维护。 |
| 某间夜的房态和价格必须同时传吗? | 不必,二者独立:blocked 关房;open + price 覆盖价;open + price:null 恢复默认价。一次调用一个 status 作用于整批 dates。 |
在本页直接签名并调用真实接口:选择接口 → 填业务参数 JSON(无需自己写 vendor_id/timestamp/sign)→ 发送。签名在你的浏览器本地完成,hmac_key 只留在本机(可选「记住」,存 localStorage,换机不带)。
常用模板:上架 {"id":123,"status":"online"} · 关房 {"project_id":123,"dates":["2026-12-10"],"status":"blocked"} · 建房源见 §4.3 示例 · 接单 {"id":36}(confirm/cancel 同参,id 取 bookings/list 返回值)。
| HTTP | code | 含义 | 处置 |
|---|---|---|---|
| 401 | — | 缺失签名(sign)或时间戳(timestamp)参数 | 检查签名三件套是否都在 body 里 |
| 401 | — | 请求已过期(±5 分钟窗口) | 校准服务器时间后重签 |
| 401 | — | 签名校验失败 / vendor_id 密钥未配置 | 核对 hmac_key 与签名算法(数组、空值、嵌套展平) |
| 400 | — | name / city_id / project_id 等必填缺失 | 按 message 补齐 |
| 400 | — | channel 非法 / city_id 不属于商家开放城市 / district_id 不属于城市 | 先用 projects/list 或平台侧确认主数据 |
| 400 | — | 上架被拒:有户型算不出默认夜价(缺 price_night/rent_monthly 且无 price_from,message 会点名户型)/ 无户型 / 照片不足 7 张 / 无封面 / 评级未通过 / 商家未过审 | 按 message 补齐;评级走 rating/submit(4.12),图片走 photos/add(4.11) |
| 400 | — | 下单被拒:该房源未配置价格,暂不可预订(2026-09 新增:算不出价不再 0 元成单) | 给户型补 price_night 或 rent_monthly(或房源起价) |
| 400 | — | 评级:dims 缺维度 / 越界(0-5)/ 未知维度;或已在复核队列中重复提审 | 按 4.12 维度表修正;进度用 rating/status 查 |
| 400 | — | insurance 含未知标识 / min_stay_nights 超出频道范围(rental 1–365 / minsu 15–365) | 按 §6 / §5 枚举修正 |
| 400 | — | qty 与 available_qty 同时传(语义不同,只能传一个)/ available_qty 超出 0-999 / 项目级传放出量 | 见 3.5;项目级(unit_id=0)容量恒 1,不接受放出量 |
| 400 | — | default_closed 非布尔 | 传 true / false,null 清除(3.6) |
| 400 | — | room_profile 取值非法:未知枚举值 / 数值越界 / 文本超长 / feature_image 非法地址 | 按 message 里的字段中文名与可选值修正(见 3.7) |
| 400 | — | photos/sync 入参问题:photos 空数组 / 未知 category / 同实体内 url 或 external_id 重复 / 非 http(s) 地址 / 声明分辨率低于 800×600 或超过 10MB | 见 4.11.1;错误信息会指明第几项(photos[i]) |
| 400 | — | 上架被拒:图集抽检确定性不合格(超 10MB / 小于 800×600 / 非图) | 按 message 里的图片地址整改后重推;仅网络不可达不会拒绝(走 warnings) |
| 400 | — | 房态:以下日期已有预订占用 | 先取消订单再改房态 |
| 400 | — | 无可更新字段 / city_id 不支持修改 | 按 message 调整 |
| 400 | — | 订单未支付不可确认 / 订单已取消不可变更 | 支付走收银台后重试确认;取消为终态 |
| 404 | 404 | 订单不存在或不属于该商家(房源 / 户型同理) | 统一 404,不区分「不存在」与「越权」,防探测 |
| 404 | 404 | 未知 vendor 路由 | 核对路径(本页调试台清单) |
| 405 | — | 非 POST 请求 | 全部接口仅支持 POST |
平台提供端到端回归脚本(Node,走真实 HTTP 签名链路),接入方可用它自检签名实现是否正确:
# 覆盖:regions 枚举→创建→评级提审/状态→上架→C 端可见→保险/连住更新→房态/夜价→
# 下单逐晚计价→订单闭环(webhook)→下架→越权负例→清理
node scripts/housing_vendor_hmac_regression.cjs [base_url] # 默认 http://127.0.0.1:8766
node scripts/vendor_hmac_regression.cjs # 家政开放接口同机制回归
版本:v2.2(2026-09-18)· 文档与线上实现同步校准。
v2.2 变更(按商家反馈落地):⓪ 上架图集门槛由 ≥8 张下调为 ≥7 张(含封面,按商家确认的图集标准;房源图 + 户型图合计);① 价格与住宿规则下放到户型——户型 price_night 在 rental 同样生效、price_from 改选填、最短连住下放到户型(见 3.2 / 5.2);② 卡片展示价三件套 price_from_display / price_unit / price_note 与取数规则(3.4);③ 房态净可售 available_qty + set 响应回 days[] 对账、默认关房 default_closed(3.5 / 3.6);④ 图集全量覆盖 photos/sync + 分类/排序 + 上架抽检(4.11);⑤ 房间档案 room_profile 21 个字段对商家开放(3.7)。
v2.1(2026-09-10):新增 regions/list、photos/add、rating/submit|status 端点;夜价覆盖价参与下单计价;amenities 10-id 映射与上架前置清单补全;新增「常见接入疑问」节。
密钥与凭证:由平台统一配置并线下下发;遗失须走平台重置,不要在多个业务间共享 hmac_key。
试点阶段接口字段以本页为准,扩展字段只增不破坏;重大变更会提前在「接入单」里同步。发布节奏随政策与试点进展而定。