Skip to content
登录
Veridien Docs

接口约定

每个接口在状态码、错误、重试与分页上都遵守同一套约定。学一次,处处适用。

状态码含义
200成功。
201创建了一个资源(一位客人、一次锁房或一笔费用)。
400请求无效:JSON 格式有误,或某个参数没通过校验。
401认证失败:API 密钥缺失或无效。
403密钥有效,但缺少所需的权限范围。
404该路由或资源不存在(或不属于你)。
405路径存在,但不支持这个 HTTP 方法。
409冲突:没有房量、Idempotency-Key 被复用,或积分余额不足。
429触发限流。请在 Retry-After 头指示的时间之后重试。
500服务端内部错误。
503维护中。平台暂时不可用。请在 Retry-After 头指示的时间之后重试。

每次失败都会返回对应的状态码和一个 error 对象:

{
  "error": {
    "type": "permission",
    "code": "insufficient_scope",
    "message": "Missing required scope: reservations:write.",
    "request_id": "req_a1b2c3d4e5"
  }
}
  • type:错误类别,取值为 invalid_requestauthenticationpermissionnot_foundconflictrate_limitserver
  • code:稳定、可被程序识别的标识。请按它分支处理,而不是按 message
  • message:给人看的说明。可以记日志,但不要解析。
  • param:引发错误的请求字段。只在 400 字段校验错误时出现,其余情况会省略。
  • estimated_end:维护窗口预计结束时间的 ISO 时间戳。只在 503 时出现,且只在设置了结束时间时才有。它比由它推导出的 Retry-After 头更精确,所以要显示「恢复时间」时优先用它。
  • request_id:唯一标识这次请求。联系支持时请附上它。

按 code 判断,别按 message

message 的文案可能变动,code 不会。请让错误处理逻辑基于 error.code 分支(例如 no_availabilityrate_plan_not_foundinsufficient_points)。

你会遇到的常见 code:

Code类别出现时机
missing_api_key / invalid_api_keyauthentication缺少 Authorization 头,或密钥未知、已停用、已过期。
insufficient_scopepermission密钥缺少该接口所需的权限范围。
invalid_parameters / invalid_jsoninvalid_request某个字段没通过校验,或请求体不是有效的 JSON。
unknown_routenot_found没有接口匹配这个路径。
no_availabilityconflict该房型在所选日期已售罄。
idempotency_key_reuseconflict同一个 Idempotency-Key 被用在了不同的请求体上。
idempotency_in_progressconflict使用同一个 Idempotency-Key 的上一次请求仍在处理中。请稍后重试。
insufficient_pointsconflict积分兑换超出了可用余额。
rate_limitedrate_limit超出了单把密钥的请求上限。
maintenance_modeserver平台处于维护窗口。请在 Retry-After 头指示的时间之后重试。

Veridien 的所有资源 id 都是 UUID,例如 7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27。给客人看的预订编号是另一回事:confirmation_code 是一串便于人读的短代码(例如 B7XKQ4M2NZ),展示给客人和员工看,绝不用作资源 id。请求 id 以 req_ 开头。由你提供的字段,例如 payment_reference,对 Veridien 是不透明的,保留你自己系统里的格式。

POSTPATCH 请求是会改变状态的那一类:创建客人、锁定库存、确认预订、兑换积分、入账费用。为了让重试安全,请发送一个带唯一值的 Idempotency-Key 头(用 UUID 就很合适):

curl -X POST https://veridien.app/api/v1/holds \
  -H "Authorization: Bearer vrdn_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1d2c9a-8b3e-4a17-9c2f-1e5b7d0a4c83" \
  -d '{ "room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63", "rate_plan_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02", "check_in": "2026-08-01", "check_out": "2026-08-04", "guest_id": "3f8a2c1b-9d4e-4c6a-8b7f-5e2d1a9c0b34", "adults": 2 }'
  • 带某个 key 的第一个请求正常执行,它的响应会被保存下来。
  • 用同样的 key 和同样的请求体重试,会重放保存下来的响应:不会有第二次锁房,也不会有第二笔费用。
  • 用同样的 key 配不同的请求体,返回 409 idempotency_key_reuse
  • 在第一个请求还没结束时并发发送同样的 key,返回 409 idempotency_in_progress。稍等片刻再试,你就会拿到保存下来的响应。key 在操作执行前就已被占用,因此第二个请求绝不会真的执行它。
  • 失败的请求会释放它的 key,因此一次正当的重试会重新执行,而不是重放那次失败。只有成功的响应会被保存:因一时售罄返回的 409 no_availability 不会在房间重新空出来之后还被永远重放。

key 的作用范围是单把 API 密钥。每个逻辑操作用一个新的 Idempotency-Key

确认接口有双重幂等

确认锁房(POST /holds/{id}/confirm)对它的 payment_reference 也是幂等的:重复确认一条已确认的预订,或重放同一个付款凭据,都会返回已有的确认结果并带上 "already_confirmed": true,而不会再次收款。

GET /reservationslimitoffset 分页。其他列表接口(/room-types/services/rate-plans)会一次返回该酒店的全部数据,不分页。

参数默认值最大值含义
limit25100返回多少条记录。
offset010000跳过多少条记录。

响应把结果放在 data 里,并说明是否还有更多:

{
  "has_more": true,
  "data": [ /* ... */ ]
}

要取下一页,就把 limit 加到上一次的 offset 上。当 has_morefalse 时停止。

每个金额都是十进制字符串,绝不是浮点数:是 "1310.40",不是 1310.4。请用十进制类型解析,不要用二进制浮点类型。

一家酒店有一种本位币,而一张账单可以同时挂着多种币种的明细(美元的房费加上一条马尔代夫拉菲亚的餐厅明细,很常见)。由此有两条规则:

不同币种的金额永远不会相加。 凡是报告余额的地方,都会有一个 balances 数组给出各币种的实际数字,那才是可信的数字:

"balances": [
  { "currency": "USD", "charges": "1310.40", "payments": "0.00", "balance": "1310.40" },
  { "currency": "MVR", "charges": "1500.00", "payments": "1500.00", "balance": "0.00" }
]

只有当任何币种下都不欠款时,账单才是 settled。一笔美元欠款绝不会被一笔拉菲亚的贷方抵消。

汇总数字是一种估值,而且可能是 null balancetotal_chargesfolio_balance 这类字段,是按酒店本位币折算出来的便捷数字,依据的是写入每一行时冻结在该行上的汇率。因为汇率是冻结的,之后的汇率变动绝不会改变一笔已有费用的报告金额。如果某一行的币种在这家酒店没有配置汇率,它就无法折算,这些字段会是 null,而不是一个错的数字。做算术之前先处理 null

限流按每把 API 密钥使用漏桶(令牌桶)算法。你的桶最多装 600 个令牌,并以恒定的每秒 10 个令牌(每分钟 600 个)补充。每个请求消耗一个令牌:

  • 突发时可以一次把整桶用完,也就是连续 600 个请求。
  • 持续吞吐等于补充速率,即每秒 10 个请求

桶空时,请求会返回 429 并带上 Retry-After 头。请至少退避到它指示的秒数之后再重试。尽量缓存读取结果(/property/room-types/services 带有较短的 Cache-Control/availability/rates 是实时库存,有意不做缓存,所以你自己也不要缓存它们),并避免密集轮询。

每个响应,无论成功还是失败,都关联着一个 request_id(错误响应体里以及 /me 的返回中也会给出)。把它记下来。当你反馈问题时,支持人员可以凭请求 id 追踪到那次具体调用。