开发文档
1stDibs API 参考
1stDibs 4 个操作的 action id 与端点、带边界和规则的输入字段,以及返回字段。
正在核对当前可用状态与已批准价格…
调用约定
共有 4 个 action,均以 POST /api/v1/firstdibs/ 加 action id 的方式调用:`post-1stdibs-search`(POST /api/v1/firstdibs/post-1stdibs-search)、`post-1stdibs-filters`(POST /api/v1/firstdibs/post-1stdibs-filters)、`post-1stdibs-detail`(POST /api/v1/firstdibs/post-1stdibs-detail)和 `post-1stdibs-seller`(POST /api/v1/firstdibs/post-1stdibs-seller)。输入放在 `body` 下的 JSON 对象中。只接受本参考列出的字段名:其他名称,例如 `q`、`limit`、`colour`、`item_id` 或 `dealer`,会作为未声明的键被拒绝。输入校验不检查 slug 与 id 的格式。
bodypost-1stdibs-searchpost-1stdibs-filterspost-1stdibs-detailpost-1stdibs-seller
post-1stdibs-search:范围输入
在这个 action 上,输入校验中的输入均为可选,但该 action 需要提供 `body.query` 或 `body.category` 之一;两者都缺失的请求能通过输入校验,但不满足这一要求,因此请始终提供其中之一。`body.query` 是与站点搜索框相同形式的自由文本,例如 `eames lounge chair`。`body.category` 是一到四层、以斜杠分隔的小写路径,与站点 URL 中的写法一致,例如 `furniture/seating/lounge-chairs`。`body.vertical` 取 `furniture`、`art`、`jewelry` 或 `fashion` 之一;它是顶级类目的简写,只要提供了 `body.category` 就会被忽略。slug 筛选 `body.style`、`body.period`、`body.material`、`body.origin`、`body.creator`、`body.location` 和 `body.color` 接受 1stDibs 的 slug,例如 `art-deco`、`20th-century`、`mahogany`、`austrian`、`nestor-toro`、`france-europe` 和 `blue`。年代还接受世纪 slug 以及 1920s 到 1990s 的十年 slug,对艺术品而言材质维度标注为 Medium。origin 是作品的制造地,location 是经销商的发货地;颜色维度由 1stDibs 根据照片判定。可用的 slug 取决于类目,1stDibs 不认识的值会使请求失败,而不会被丢弃。
post-1stdibs-searchbody.querybody.categorybody.verticalbody.stylebody.periodbody.materialbody.originbody.creatorbody.locationbody.color
post-1stdibs-search:价格、促销、排序与分页
`body.price_min` 和 `body.price_max` 是不小于 0 的美元数值;只给其中一个即可作为单侧边界。`body.on_sale` 是布尔值,默认 `false`;为 true 时只返回经销商已降价的商品。`body.sort` 取 `recommended`(默认)、`newest`、`price-high`、`price-low` 或 `popular` 之一;两种价格排序按美元标价排列。`body.max_results` 是 1 到 200 的整数,默认 50;设上限是为了控制响应大小和耗时。`body.page` 是 1 到 6001 的整数,默认 1。结果窗口在偏移量 6000 处结束:最后可达页为 6000 除以 `body.max_results` 再加 1,超出该页时 `page_exists` 为 false 且没有结果行。
post-1stdibs-searchbody.price_minbody.price_maxbody.on_salebody.sortbody.max_resultsbody.page
post-1stdibs-search:返回字段
返回的页面级字段包括 `total_available`、`page_size`、`last_reachable_page`、`has_more`、`applied_filters` 和 `results`。`results` 中的每一行含 `item_id`、`url`、`title`、`category_path`、`price`、`currency`、`price_status`、`discount_percent`、`is_sold`、`is_on_hold`、`creators`、`seller`、`ships_from_country` 和 `images` 等字段。`seller` 中的 `order_count` 与 `is_distinguished` 在这些列表行中为空,需从详情和店铺操作中获取。
post-1stdibs-searchdata
post-1stdibs-filters
输入:`body.query`、`body.category`、`body.vertical`、`body.style`、`body.period`、`body.material`、`body.origin`、`body.creator` 和 `body.location`,含义和规则与搜索相同,包括必须提供 `body.query` 或 `body.category` 之一(两者都缺失的请求能通过输入校验,但不满足这一要求),以及给出类目时忽略 `body.vertical`。这里没有颜色、价格、排序或分页输入。返回 `total_available`、`filter_count`、`categories`(所请求层级的子类目)和 `filters`;每个筛选项含 `name`、`label`、`value_count` 和 `values`,其中条目含 `value`、`label`、`count`、`linkable`、`currency` 和 `hex_code`。在存在对应参数时,筛选项的 `name` 就是它所对应的搜索输入名,筛选维度的集合取决于类目。
post-1stdibs-filtersbody.querybody.categorybody.verticalbody.stylebody.periodbody.materialbody.originbody.creatorbody.location
post-1stdibs-detail
`body.item` 是必填字符串:站点上显示的商品 id,例如 `f_52078502`(前缀为:家具 f_、艺术品 a_、珠宝 j_、腕表 v_),或一个 1stdibs.com 商品链接,id 从链接中的 /id- 路径段读取。一次调用可接受用逗号分隔的多达 10 个 id。返回 `requested`、`found`、`missing` 和 `items`。`items` 中的每个条目是在搜索行基础上增加字段,包括 `description`、`condition`、`condition_notes`、`materials`、`dimensions_display`、`seller_location`、`shipping`、`sku`、`listing_views_6m`、`schema_org_offer` 和 `price_mismatch`,最后一个字段报告标价与 schema.org 报价之间的不一致。
post-1stdibs-detailbody.item
post-1stdibs-seller
`body.seller` 必填:1stdibs.com/dealers/ 链接中的店铺 slug,例如 `morentz`,或完整的店铺链接。`body.sort`、`body.page` 和 `body.max_results` 的取值、默认值和边界与搜索相同,分页窗口同样在偏移量 6000 处结束。返回 `seller_slug`、含 `seller_id`、`name`、`order_count`、`is_distinguished` 和 `ships_from_country` 的 `seller` 信息块,以及 `total_available`、`page`、`page_size`、`page_exists`、`has_more` 和 `results`,其中的行与搜索结果行相同。
post-1stdibs-sellerbody.sellerbody.sortbody.pagebody.max_results
{
"body": {
"item": "f_52078502,a_18430382"
}
}
{
"body": {
"seller": "morentz",
"sort": "newest",
"max_results": 10
}
}
操作示例
公共网关操作统一使用 POST /api/v1/{project}/{action}。
商品详情
POST /api/v1/firstdibs/post-1stdibs-detail
使用 JSON 对象,按文档将参数放入 path、query、headers 和 body,省略未使用的位置。input.headers 是受结构校验的数据,不是浏览器请求头。请勿在此填写凭证。按文档保留 body 的数组、标量或 null;省略与 null 含义不同。
{
"body": {
"item": "f_52078502"
}
}示例响应
null筛选项与类目
POST /api/v1/firstdibs/post-1stdibs-filters
使用 JSON 对象,按文档将参数放入 path、query、headers 和 body,省略未使用的位置。input.headers 是受结构校验的数据,不是浏览器请求头。请勿在此填写凭证。按文档保留 body 的数组、标量或 null;省略与 null 含义不同。
{
"body": {
"category": "furniture/seating/lounge-chairs"
}
}示例响应
null商品搜索
POST /api/v1/firstdibs/post-1stdibs-search
使用 JSON 对象,按文档将参数放入 path、query、headers 和 body,省略未使用的位置。input.headers 是受结构校验的数据,不是浏览器请求头。请勿在此填写凭证。按文档保留 body 的数组、标量或 null;省略与 null 含义不同。
{
"body": {
"category": "furniture/seating/lounge-chairs",
"max_results": 10
}
}示例响应
null经销商店铺
POST /api/v1/firstdibs/post-1stdibs-seller
使用 JSON 对象,按文档将参数放入 path、query、headers 和 body,省略未使用的位置。input.headers 是受结构校验的数据,不是浏览器请求头。请勿在此填写凭证。按文档保留 body 的数组、标量或 null;省略与 null 含义不同。
{
"body": {
"max_results": 10,
"seller": "morentz"
}
}示例响应
null网关调用参考
以下规则适用于本站所有显示本节的 API。
发起调用
向 POST /api/v1/<project>/<action> 发送 JSON 请求体。需要以下三个请求头:
x-api-key:在控制台创建的密钥。其权限必须包含<project>:<action>,或包含<project>:*(项目的全部操作,包括以后新增的操作)。Content-Type: application/json。请求体不超过 64 KiB。Idempotency-Key:8–128 个字母、数字、冒号、下划线或连字符。每个预期请求生成一个,并保留到得到最终结果为止。
Idempotency-Key 规则
- 幂等 key 归属于你的账户:你的所有 API 密钥和真实调试请求共用同一组幂等 key。
- 首个请求完成后,以同一个 key 发送相同请求(项目、操作和输入均相同):24 小时内返回已保存的响应,不会再次执行操作,也不会再次扣费。
- 同一个 key 但请求不同:返回 409
IDEMPOTENCY_CONFLICT。 - 首个请求仍在进行或结果尚未确认时再次使用同一个 key:返回 409
REQUEST_PENDING。 - 结果未确认的请求被释放后再次使用同一个 key:返回 504
OUTCOME_UNKNOWN_RELEASED,未扣费。 - 成功请求的已保存响应过期后再次使用同一个 key:返回 410
RESULT_EXPIRED,不会再次执行或扣费。 - 受理前被拒绝的请求(错误表第一组)不会记录 key,修正问题后可用同一个 key 重发;
IDEMPOTENCY_CONFLICT除外,此时该 key 已属于另一个请求。请求一旦被受理,该 key 即归属于它,即使请求随后失败。
请求体
请求体是一个 JSON 对象,最多包含四个可选成员:path、query、headers 和 body。按操作文档放置每个参数,省略未使用的成员。这里的 headers 是按操作校验的 JSON 数据,不是 HTTP 请求头,切勿在其中放入凭证。
不符合操作要求的输入会在请求执行之前被拒绝,且不扣费:未通过操作输入结构校验(包括未知成员,或 path、query、headers 中未声明的参数)时,在受理前返回 INVALID_PARAM;body 内含未声明字段、某个值无法安全发送(例如路径参数中含 "/" 或 "%")或超出传输限制时,在受理后返回 INVALID_INPUT(该 key 随即被占用)。
响应
{
"ok": true,
"data": "<the result of the operation>",
"meta": {
"requestId": "<request id>",
"chargedCreditUnits": "<price in credit units>",
"…": "…"
}
}data 是操作的结果。meta.requestId 标识已记录的请求,meta.chargedCreditUnits 是实际扣费金额。
{
"ok": false,
"error": {
"code": "OPERATION_TIMEOUT",
"message": "…"
},
"meta": {
"requestId": "<request id>",
"chargedCreditUnits": "0",
"status": "uncertain"
}
}此时 meta.chargedCreditUnits 始终为 "0"。请求确定未成功时 meta.status 为 "failure",结果无法确认时为 "uncertain"。
{
"ok": false,
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "…"
},
"requestId": "<reply id>"
}这种响应没有 meta,也不扣费。请读取 ok 和 error.code,不要只依赖 HTTP 状态码。
计费
- 只有调用成功时才按标价扣费,失败的调用不扣费。
- 请求受理时会从可用余额中预留价格。可用余额低于价格时,请求以
INSUFFICIENT_CREDITS被拒绝。 - 结果无法确认时,价格最多预留 900 秒(15 分钟),之后释放,不会事后扣费。
- 金额以整数积分单位表示:1 积分 = 100 积分单位,因此
"250"表示 2.5 积分。
限流
每个被受理的请求都会计入你账户的限额(突发 10 个请求,之后每 0.2 秒恢复 1 个),以及所有客户共享、适用于此操作或一组操作的限额(包括同时进行请求数的上限)。因此即使你自己的流量不大,也可能收到 RATE_LIMITED 或 CONCURRENCY_LIMIT。两种响应都带有以秒为单位的 Retry-After 请求头;至少等待该时长后,使用同一个 Idempotency-Key 重发。
自动停用
当操作的结果多次不符合其文档化契约,或执行该操作的成本高于(或无法再核对)其定价所依据的成本时,操作可能被自动停用;你每次调用支付的价格不会因此改变。运营方也可以手动停用。停用期间调用返回 503 OPERATION_SUSPENDED,不会执行,也不扣费。部分自动停用会在一小时后解除,以便通过调用确认操作是否恢复;这些调用与普通调用一样执行和计费。
验证状态
在本页的可用状态表中,“已由真实流量验证”表示该操作在当前价格和契约下已有真实调用成功完成,并通过了本站对该操作的自动成本核对。
错误码
| 错误码 | HTTP | 是否扣费 | 含义 | 处理方式 |
|---|---|---|---|---|
| 受理前被拒绝:无 meta;不会记录 key(IDEMPOTENCY_CONFLICT 除外:该 key 已属于另一个请求) | ||||
AUTH_FAILED | 401 | 否 | x-api-key 请求头缺失、格式错误、不存在、已撤销或已过期。 | 使用有效的密钥,切勿把密钥写入日志。 |
ACCOUNT_FROZEN | 403 | 否 | 账户受到限制或邮箱尚未验证,不能发起计费请求。 | 在控制台检查账户状态。 联系页面 |
SCOPE_DENIED | 403 | 否 | 密钥权限既不包含 <project>:<action>,也不包含 <project>:*。 | 使用权限覆盖此操作的密钥。 |
UNSUPPORTED_MEDIA_TYPE | 415 | 否 | Content-Type 请求头不是 application/json。 | 修正请求后重新发送,可继续使用同一个 Idempotency-Key。 |
PAYLOAD_TOO_LARGE | 413 | 否 | 请求体超过 64 KiB。 | 修正请求后重新发送,可继续使用同一个 Idempotency-Key。 |
INVALID_ENCODING | 400 | 否 | 请求体不是有效的 UTF-8。 | 修正请求后重新发送,可继续使用同一个 Idempotency-Key。 |
INVALID_REQUEST | 400 | 否 | 请求体不是有效的 JSON。 | 修正请求后重新发送,可继续使用同一个 Idempotency-Key。 |
IDEMPOTENCY_KEY_REQUIRED | 400 | 否 | Idempotency-Key 请求头缺失,或不是 8–128 个字母、数字、冒号、下划线或连字符。 | 提供有效的 Idempotency-Key。 |
IDEMPOTENCY_CONFLICT | 409 | 否 | 你的账户已将此 Idempotency-Key 用于不同的项目、操作或输入。 | 新请求请使用新的 key。如需读取先前结果,请原样重发先前的请求。 |
OPERATION_NOT_FOUND | 404 | 否 | 没有与此项目和操作对应的已注册操作。 | 对照文档检查端点路径。 |
INVALID_PARAM | 400 | 否 | 输入未通过操作的结构校验,包括未知成员,或 path、query、headers 中未声明的参数。 | 修正请求后重新发送,可继续使用同一个 Idempotency-Key。 |
INSUFFICIENT_CREDITS | 402 | 否 | 可用余额(余额减去预留金额)低于此操作的价格。 | 等待预留金额结算或释放,或在开放购买后充值。 |
OPERATION_DISABLED | 503 | 否 | 该操作未启用真实调用。 | 重试前请在 API 页面查看当前可用状态。 |
OPERATION_SUSPENDED | 503 | 否 | 该操作已被自动或由运营方停用,请求未被执行。 | 稍后重试,并在 API 页面查看当前可用状态。 |
OPERATION_HEALTH_UNAVAILABLE | 503 | 否 | 网关无法确认该操作是否已停用,因此拒绝了调用。 | 稍后使用同一个 Idempotency-Key 重试,不要高频循环重试。 |
NOT_CONFIGURED | 503 | 否 | 服务的必要组成部分(如数据库、密钥保护或该操作的配置)不可用。 | 稍后使用同一个 Idempotency-Key 重试,不要高频循环重试。 |
RATE_LIMITED | 429 | 否 | 触发了限流:可能是你账户的限额,也可能是与其他客户共享、适用于此操作或一组操作的限额。 | 等待 Retry-After 指定的秒数后,使用同一个 Idempotency-Key 重发。 |
CONCURRENCY_LIMIT | 429 | 否 | 此操作(或共享同一上限的一组操作)同时进行中的请求过多(所有客户共享此上限)。 | 等待 Retry-After 指定的秒数后,使用同一个 Idempotency-Key 重发。 |
| 已受理但失败——meta.chargedCreditUnits 为 "0";该 Idempotency-Key 已归属于此请求 | ||||
INVALID_INPUT | 400 | 否 | body 内含未声明字段、某个值无法安全发送(例如路径参数中含 "/" 或 "%"),或请求超出传输限制。操作未被执行。 | 修正输入后,使用新的 Idempotency-Key 发送。 |
SERVICE_UNAVAILABLE | 503 | 否 | 由于服务端的状况,该操作目前无法执行。与你的 API 密钥或钱包余额无关。 | 稍后使用新的 Idempotency-Key 重试;此 key 之后会一直返回这一失败结果。 |
SERVICE_BUSY | 503 | 否 | 该操作在服务端暂时达到处理上限。 | 稍后使用新的 Idempotency-Key 重试;此 key 之后会一直返回这一失败结果。 |
REQUEST_REJECTED | 502 | 否 | 该操作拒绝了此请求。 | 对照文档检查输入,修正后使用新的 Idempotency-Key 发送。 |
REQUEST_NOT_FULFILLED | 502 | 否 | 该操作报告未成功。 | 对照文档检查输入,修正后使用新的 Idempotency-Key 发送。 |
OPERATION_FAILED | 502 | 否 | 该操作未完成,未产生结果。 | 稍后使用新的 Idempotency-Key 重试;此 key 之后会一直返回这一失败结果。 |
OPERATION_TIMEOUT | 504 | 否——价格最多预留 900 秒后释放 | 该操作未在时限内完成或报告超时,可能仍已执行。 | 不要自动换新的 Idempotency-Key 重发:该操作可能已经执行。是否发起新请求请审慎决定。 |
OUTCOME_UNKNOWN | 504 / 502 | 否——价格最多预留 900 秒后释放 | 该操作失败或意外中断,结果未知。 | 不要自动换新的 Idempotency-Key 重发:该操作可能已经执行。是否发起新请求请审慎决定。 |
RESULT_INVALID | 502 | 否——价格最多预留 900 秒后释放 | 结果不是该操作可识别的有效响应,或未通过网关的最终检查。 | 不要自动换新的 Idempotency-Key 重发:该操作可能已经执行。是否发起新请求请审慎决定。 |
RESULT_TOO_LARGE | 502 | 否——价格最多预留 900 秒后释放 | 结果超出大小限制。 | 不要自动换新的 Idempotency-Key 重发:该操作可能已经执行。是否发起新请求请审慎决定。 |
| 无 meta,可能发生在操作执行之后(此时 key 可能已被记录) | ||||
RESPONSE_TOO_LARGE | 502 | 否——价格最多预留 900 秒后释放 | 操作已返回结果,但响应过大,网关无法保存,因此未返回。 | 不要自动换新的 Idempotency-Key 重发:该操作可能已经执行。是否发起新请求请审慎决定。 |
CREDIT_SCHEMA_UNAVAILABLE | 503 | 仅当已记录的请求成功时扣费。 | 积分记账未处于预期状态(例如维护迁移期间)。通常发生在受理前;少数情况下发生在操作执行之后。 | 稍后使用同一个 Idempotency-Key 重试:仅当请求从未被受理时才会执行,否则返回已记录的状态。 |
INTERNAL_ERROR | 500 | 仅当已记录的请求成功时扣费。 | 服务端意外错误,可能发生在操作执行之前或之后。 | 稍后使用同一个 Idempotency-Key 重试:仅当请求从未被受理时才会执行,否则返回已记录的状态。请保留 requestId。 联系页面 |
| 重复使用已受理请求的 Idempotency-Key | ||||
REQUEST_PENDING | 409 | 本次重试不扣费;原请求仅在成功时扣费,否则在 900 秒内释放。 | 使用此 key 的请求仍在进行,或结果尚未确认。 | 请等待,不要换新 key 重试;结果未确认的请求在 900 秒后释放,不扣费。 |
RESULT_EXPIRED | 410 | 否 | 请求已成功,但保存的响应已超过 24 小时。不会再次执行,也不会再次扣费。 | 新请求请使用新的 Idempotency-Key(成功后会再次扣费)。 |
OUTCOME_UNKNOWN_RELEASED | 504 | 否 | 结果始终未能确认,预留价格已释放,未扣费。 | 自行决定是否使用新的 Idempotency-Key 发起新请求;成功后会扣费。 |
有些响应并非由网关产生:POST 以外的方法会收到 HTTP 405;运行超过 60 秒的调用会被托管平台终止,返回的响应不是上述 JSON 格式。此时 key 可能已被记录;使用同一个 key 重发时,若请求从未被受理则会执行,否则返回已记录的状态。