mcpField
S
spree-api-v3

spree-api-v3

github.com/spree开发10226 次安装4 周前更新
代码仓库

关于 spree-api-v3

spree-api-v3 是面向开发者的技能,介绍 Spree 6 中供店铺前台、管理员和市场卖家使用的 REST API。内容涵盖认证、权限、资源约定、筛选、分页及购物车到订单的流程。

主要功能

  1. 01介绍 Store、Admin 和 Seller API
  2. 02说明认证与权限机制
  3. 03记录购物车、结账和订单流程
  4. 04涵盖筛选、分页与扩展字段
  5. 05说明 ID、字段和响应格式

适用场景

  1. 01构建 Spree 店铺前台集成
  2. 02连接后台或 ERP 系统
  3. 03实现卖家面板 API 访问
  4. 04迁移或排查 API 请求

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/spree/agent-skills --skill spree-api-v3

安装后在 Claude Code 中输入/spree-api-v3确认已加载。

附带文件references/scopes.md

详细介绍

Spree API v3

Spree 6 在 /api/v3/ 下提供三个 REST 接口,它们遵循同一套约定:

接口路径调用方身份验证授权
Store API/api/v3/store/*店面、移动应用、购物者X-Spree-Api-Key: pk_… + 可选的 Authorization: Bearer <jwt>(aud: store_api)+ 访客 X-Spree-Token所有权(参见 spree-auth-permissions)
Admin API/api/v3/admin/*集成、后台应用、仪表板X-Spree-Api-Key: sk_… 或 Authorization: Bearer <jwt>(aud: admin_api)密钥作用域 / 角色权限键
Seller API/api/v3/seller/*市场卖家面板卖家 JWT(aud: seller_api)+ X-Spree-Seller-Id卖家角色键 + current_seller 作用域(参见 spree-marketplace)

为某个受众签发的令牌在其他接口上会被拒绝。Spree 6 中不存在 v2 Storefront/Platform API。如果你要迁移旧集成,请参见 node_modules/@spree/docs/dist/api-reference/store-api/migrating-from-storefront-api-v2.md。

Store API

  • 匿名浏览只需要 X-Spree-Api-Key: pk_…。可公开密钥可安全地用于客户端代码。
  • 访客购物车 / 结账 / 订单:还需发送 X-Spree-Token: <cart.token>。
  • 已登录客户:还需发送 POST /api/v3/store/auth/login 返回的 Authorization: Bearer <jwt>。响应正文包含 token、refresh_token 和 user。通过 POST /auth/refresh 和 { "refresh_token": "…" } 轮换令牌。
  • 上下文标头:
    • X-Spree-Country 用于解析市场,并据此设置默认语言区域和货币。
    • X-Spree-Locale 和 X-Spree-Currency 可覆盖这些默认值。
    • X-Spree-Channel: <code> 用于选择渠道;如果未提供,则使用商店默认值。绑定到渠道的可公开密钥会决定渠道本身;如果标头与之冲突,则返回 channel_mismatch。
  • 响应仅包含适合客户查看的内容:不包含成本价或内部备注。对于向访客隐藏价格的渠道,货币字段会返回 null,因此应将其类型设为 string | null。
  • Store API 默认只读。写入操作仅限于购物车、结账、客户自己的账户(/customers/me/*)、心愿单、客户本人订单的退货 / 索赔,以及新闻邮件 / 公司自助服务。
curl -H "X-Spree-Api-Key: pk_xxx" -H "X-Spree-Country: DE" \
     "https://shop.example.com/api/v3/store/products?q[name_cont]=shirt&expand=default_variant"
购物车和订单是不同的资源

购物车(cart_…、/api/v3/store/carts)可修改且没有状态。完成购物车后会创建不可变的订单(or_…)。

POST   /carts                         → cart (token in response)
POST   /carts/{id}/items              { variant_id, quantity }
PATCH  /carts/{id}                    { email, shipping_address, billing_address, use_shipping, … }
PATCH  /carts/{id}/fulfillments/{id}  { selected_delivery_rate_id }
POST   /carts/{id}/payment_sessions   … gateway flow …
POST   /carts/{id}/complete           → the Order (or an OrderGroup for split marketplace checkouts)
GET    /orders/{id}                   → order by or_ id, OR by the original cart_ id
  • 完成后,GET /carts/{id} 会返回 404(cart_not_found),因为已完成的购物车不再出现在购物车查询结果中。使用 GET /orders/{cart_id} 读取结果。订单接口接受购物车的带前缀 ID,并将其解析为由该购物车创建的订单(order.cart_id)。访客继续使用同一个 X-Spree-Token。
  • POST /carts/{id}/complete 可以安全重试:如果支付 webhook 已完成购物车,重试会返回现有订单。
  • 购物车上的 requirements[] 会列出仍阻止完成购物车的事项,格式为 { step, field, code, message }(例如 { "step": "delivery", "field": "delivery_method", "code": "delivery_method_required" })。步骤仅供参考;完成购物车才是唯一的硬性关卡。应根据 requirements 驱动结账界面,而不是根据状态名称。参见 spree-checkout。
  • 优惠券:POST /carts/{id}/discount_codes { code }。购物车和订单都会公开 coupon_code。
  • 已登录客户的订单历史位于 GET /customers/me/orders。
你将使用的订单字段
  • status(Admin API):draft | placed | canceled。使用 q[status_eq]=placed 筛选。
  • payment_status:none、authorized、partially_paid、paid、partially_refunded、refunded、overcharged、voided。
  • fulfillment_status:unfulfilled、partial、fulfilled、delivered、backorder、canceled(迁移的订单中可能会出现旧版 pending / ready / shipped)。
  • 总额:item_total、delivery_total、discount_total、tax_total(included_/additional_)、fee_total、gift_card_total、store_credit_total、total、amount_due,每项都配有对应的 display_*。
  • withdrawal_period_ends_at / within_withdrawal_period(欧盟撤回权)。

没有 state、payment_state 或 shipment_state,也没有 ship_total/promo_total/adjustment 行。金额按税费明细行、折扣和费用逐项列出(参见 spree-order-totals)。

Admin API

Secret key(集成):X-Spree-Api-Key: sk_…。密钥决定其对应的商店。 JWT(人员):POST /api/v3/admin/auth/login { email, password }(或使用 { provider, … } 进行 SSO)。响应正文为 { token, user }。刷新令牌会作为 HttpOnly cookie 写入,作用域限定为 /api/v3/admin/auth,且 POST /auth/refresh 不需要请求正文。Admin JWT 默认 5 分钟后过期。对于多商店主机,请发送 X-Spree-Store-Id。

如果请求同时携带两种凭据,则以 JWT 为准。

权限

每个 Admin 控制器都会将其操作映射到一个权限键:index/show → read_<resource>,其他所有操作(包括 /orders/{id}/cancel 等单条记录操作)→ write_<resource>。write_* 隐含 read_* 权限。

  • Secret key 会根据其作用域进行检查。检查失败时返回 403 access_denied,并附带 details.required_scope。
  • JWT 员工用户会根据其在此商店中的角色权限键进行检查。检查失败时返回 403,并附带 details.required_permission。如果 403 响应中没有该详情,则表示记录级规则拒绝了请求——这些规则来自 Spree.ability_class(可通过 Spree::Dependencies.ability_class 替换;secret key 则使用 Spree::ApiKeyAbility)。参见 spree-auth-permissions。
  • 密钥不会决定你能看到哪些行:每个端点都会限定在当前商店的范围内。
  • Secret key 的作用域在创建时固定。要更改作用域,请创建新密钥并撤销旧密钥。

完整的作用域列表及其分组和涵盖的资源见 references/scopes.md。运行时,GET /api/v3/admin/permissions 会返回相同的列表,Ruby 中的 Spree::ApiKey.known_scopes 也会提供该列表。常见选择:

Order sync out ............ read_orders (+ read_payments, read_fulfillments)
Warehouse / 3PL ........... read_orders, write_fulfillments, write_stock
ERP product feed .......... write_products (+ write_categories / write_collections)
Refund automation ......... read_orders, write_refunds
Staff provisioning ........ write_staff
Everything (avoid) ........ write_all

员工角色是数据(/api/v3/admin/roles)。参见 spree-auth-permissions。

仅限 Admin 的响应特征
  • 时间戳、内部备注、成本价格、status,以及店面不可见的自定义字段。
  • 操作者信息对。 会记录操作者的记录(canceler、approver、created_by、refunder 等)会公开 *_id 和 *_type。ID 对员工用户为 adm_…,对 secret key 为 key_…;*_type 为 admin_user 或 api_key。请将 *_type 视为开放列表。expand=canceler 会返回 { id, type, label }。

共享约定

带前缀的 ID

读取和写入时,ID 始终是 Stripe 风格的带前缀字符串("variant_id": "variant_k5nR8xLq")。绝不要发送或期望整数 ID。常见前缀:

前缀资源前缀资源
prod_商品variant_变体
cart_购物车or_订单
ogrp_订单组(拆分结账)li_行项目
py_付款re_退款
ful_履约ret_退货
tl_税费行disc_折扣
fee_费用cust_客户
adm_管理员用户addr_地址
ctg_类别coll_集合
sl_库存水平sloc_库存位置
mkt_市场ch_渠道
sel_卖家media_媒体
cf_自定义字段promo_促销
gc_礼品卡role_角色
key_ApiKey 记录(不是 pk_/sk_ 令牌)store_商店

前缀用于标识资源类型,因此封装对象上没有 type 字段。使用 grep -rn has_prefix_id spree/core/app/models 验证其他前缀。不存在 adj_,因为 Spree 6 中没有 Adjustment。

封装对象、分页与排序

列表返回 { data: [...], meta: { page, limit, count, pages, from, to, in, previous, next } }。单条记录以裸对象形式返回。分页:?page=2&limit=50(默认值为 25,最大值为 100)。排序:?sort=-completed_at,number。

扩展与字段
  • ?expand=default_variant,media,variants.prices 会附带关联数据;点号表示法可访问嵌套关联。允许的键因资源而异(参见 OpenAPI 规范)。
  • Admin API 的扩展会按路径段进行权限检查:order(s) 需要 read_orders,payment(s)/payment_splits 需要 read_payments,customer(s) 需要 read_customers,gift_card(s) 需要 read_gift_cards,store_credit(s) 需要 read_store_credits(因此 orders.payments 需要同时具备两项权限)。调用方无权访问的路径会被静默丢弃,而非返回 403。除非调用方持有 read_gift_cards 权限,否则礼品卡的 code 会被遮蔽(除末四位外全部隐藏)。
  • ?fields=name,slug 会返回稀疏响应(始终包含 id)。
过滤(Ransack)

q[<attr>_<predicate>]=value,例如 q[name_cont]=shirt、q[status_eq]=placed、q[completed_at_gteq]=2026-09-01。谓词包括 _eq、_not_eq、_in、_cont、_start、_gt、_gteq、_lt、_lteq、_present、_blank。模型的 Ransack 允许列表之外的属性会被静默忽略:请求仍返回 200,但过滤条件会被丢弃。使用 Spree.ransack.add_attribute(Spree::Product, :brand_id) 将属性加入允许列表。

允许列表会根据受众范围缩小(Ransack auth_object:Admin 使用 nil,Store 使用 :store,Seller 使用 :seller):

  • Store API 仅使用模型的 storefront_ransackable_associations(商品:tags、categories、collections;其他所有模型均为空),并排除模型的 private_ransackable_attributes[:store](例如订单的 email、considered_risky、coupon_code 以及 search/multi_search 作用域;变体的 cost_price;商店信用的 memo)。
  • Seller API 不使用任何关联,并排除 private_ransackable_attributes[:seller](订单的 email、considered_risky、coupon_code,以及 search/multi_search 作用域)。
  • Admin API 可使用完整的允许列表。因此,Spree.ransack.add_association(Spree::Product, :brand) 会使 q[brand_name_eq] 仅对员工生效——若要让购物者也能通过此关联过滤,请添加 Spree::Product.storefront_ransackable_associations |= %w[brand](仅限店面可查看其数据的关联)。通过 add_attribute 添加的属性会对所有受众开放,除非将其列为私有属性。
地址

使用 first_name、last_name、address1、city、postal_code、country_code(ISO2)和 state_code。对于购物车,use_shipping: true 会将配送地址复制为账单地址。响应中仍会出现 country_iso/state_abbr,但它们已弃用。

富文本

富文本属性会返回两次:description 为纯文本,description_html 为经过清理的 HTML。渲染 *_html,并写入纯文本名称(发送的值为 HTML)。Spree 会在保存时清理 HTML。

金额

金额是十进制字符串("29.99"),每个金额都配有一个格式化后的 display_* 字符串。隐藏价格时,值为 null。写入时,价格是数组:"prices": [{ "currency": "USD", "amount": "29.99" }]。

幂等性

在 POST/PUT/PATCH/DELETE 请求中发送 Idempotency-Key: <uuid>(最多 255 个字符)。在 24 小时内,使用相同键和请求体重试会重放已存储的响应(响应头 Idempotent-Replayed: true)。使用不同请求体重用同一个键会返回 422 idempotency_key_reused。5xx 响应不会缓存。SDK 和 CLI 会自动添加该键。

错误

{ "error": { "code": "validation_error", "message": "Email can't be blank",
             "details": { "email": ["can't be blank"] } } }
状态常见的 code
401authentication_required、invalid_token、authentication_failed、invalid_refresh_token
403access_denied(details.required_scope / required_permission)、channel_mismatch
404record_not_found、cart_not_found、order_not_found、line_item_not_found、variant_not_found
422validation_error(每个属性对应一个 details,表单级错误使用 base)、cart_cannot_complete、insufficient_stock、payment_failed、idempotency_key_reused
413request_too_large(请求体超过 max_request_body_size,即 100 KB)
429rate_limit_exceeded

速率限制

基于 Rails rate_limit 构建,计数器存储在 Rails.cache 中。此缓存必须在多个进程间共享(Solid Cache 或 Redis)。可通过 Spree::Api::Config 或以下环境变量进行配置:

配置项(环境变量)默认值限制范围
rate_limit_per_key(SPREE_RATE_LIMIT_PER_KEY)每个时间窗口 300 次发布密钥 + 客户端 IP(按访问者计算);未发送密钥时按客户端 IP 计算
rate_limit_per_secret_key(SPREE_RATE_LIMIT_PER_SECRET_KEY)每个时间窗口 600 次每个密钥,在整个 API 范围内计算
rate_limit_window(SPREE_RATE_LIMIT_WINDOW)60 s
rate_limit_login5按 IP 计算:商店/管理员/卖家登录、接受邀请
rate_limit_register3按 IP 计算:客户注册、订阅新闻简报
rate_limit_refresh10按 IP 计算:刷新、注销、管理员身份验证提供方
rate_limit_password_reset3按 IP 计算

响应包含 X-RateLimit-Limit、X-RateLimit-Remaining,达到限制时还会包含 Retry-After。入站支付/履约 Webhook 端点有自己的固定限制:每分钟 120 次。

调试指南

  • 所有请求都返回 401:将 pk_ 密钥发送到了 Admin API,或将 sk_ 密钥发送到了 Store API;密钥已撤销;管理员 JWT 已超过 5 分钟(通过 Cookie 刷新);客户令牌发送到了 Admin API(aud 错误)。
  • Admin API 返回 403:查看 details.required_scope / required_permission。对于密钥,创建一个具有相应范围的新密钥。对于员工,将该密钥添加到其在此商店中的角色中。
  • 结账后购物车立即返回 404:这是预期行为。获取 GET /orders/{cart_id}。
  • 列表为空,但记录确实存在:渠道错误(X-Spree-Channel 或绑定了渠道的密钥);商品未在该渠道发布;所请求币种或市场没有价格;或 Ransack 筛选条件被静默丢弃。
  • 从终端进行探测:spree api get /orders/or_xxx --expand payments,fulfillments(参见 spree-cli)。

了解更多

  • OpenAPI 规范(权威):node_modules/@spree/docs/dist/api-reference/store.yaml、admin.yaml、seller.yaml
  • Store API 指南:node_modules/@spree/docs/dist/api-reference/store-api/(身份验证、本地化、幂等性、速率限制、查询、关联)
  • Admin API 指南:node_modules/@spree/docs/dist/api-reference/admin-api/(身份验证、错误、查询)
  • Webhook 事件:node_modules/@spree/docs/dist/api-reference/webhooks-events.md
  • 相关技能:spree-auth-permissions、spree-typescript-sdk、spree-cli、spree-resource(添加端点)、spree-checkout、spree-marketplace(Seller API)、spree-events-webhooks。

评论

支持 Markdown