跳转到内容

API 参考

生产接入需要的细节:错误长什么样、会触发哪些 webhook 事件、幂等如何工作,以及限流规则。

每个非 2xx 响应都是一个带类型的错误,含有稳定的、机器可读的 code 以及对应的 HTTP 状态。SDK 会把它作为 AgentbankError 抛出(err.codeerr.status) —— 捕获这一个类即可统一处理各种失败。

{ "error": { "code": "PAYMENT_DECLINED", "message": "card declined", "details": { "reason": "insufficient_funds" } } }

code 分支处理,永远不要按 message 文本判断(message 可能变,code 才是契约)。

在 SDK 里,捕获单一的 AgentbankError 类并读取 err.code / err.status。优先用静态方法 AgentbankError.is(err) 而不是 err instanceof AgentbankError:在包边界上,当一个 node_modules 里共存了两份 SDK core(不同的类对象)时,instanceof 会静默失败,而 is() 检查的是形状,能识别任意版本抛出的错误。传输层失败(没有 HTTP 响应 —— 超时、abort、DNS)会以 AgentbankError 的形式出现,status === 0,code 为 timeoutabortednetwork_error

try {
await agentbank.checkout.openACP({ currency, items });
} catch (err) {
if (AgentbankError.is(err) && err.status === 429) {
// back off and retry — see Rate limits below
}
}
code HTTP 含义
VALIDATION_ERROR 400 请求格式错误 —— 字段错误或缺失。details 携带各字段的错误信息。
UNAUTHORIZED 401 缺少或无效的凭据。
PAYMENT_DECLINED 402 支付通道拒绝了扣款。details.reason 是通道给出的原因。
FORBIDDEN 403 已认证,但无权访问该资源。
SANCTIONS_BLOCKED 403 被制裁筛查拦截。
NOT_FOUND 404 无此资源 —— 或你的权限范围看不到它。
CONFLICT 409 状态冲突 —— 例如对已过期的结账做 capture,或幂等键在进行中被复用。
GONE 410 资源曾存在,但已不可用。
RATE_LIMITED 429 请求过多 —— 见 限流
INVARIANT_VIOLATION 500 服务端一致性校验失败。请上报。
UPSTREAM_ERROR 502 某个依赖(支付通道、Curless)失败。可能可重试。
CIRCUIT_OPEN 503 某个依赖的熔断器已打开(多次失败后快速失败)。短暂退避后重试。

注册一个端点(POST /v1/webhook-endpoints)并订阅事件类型(不订阅任何类型 = 接收全部)。每次投递为 { id, type, data },签名为 x-agentbank-signature: t=…,v1=…。用 merchant SDK 的 verifyWebhook 校验 —— 校验与至少一次去重见 Webhooks 一节

商户端点会收到以下事件:

事件 触发时机
order.paid 一次结账成功扣款。
order.refunded 一笔订单被退款(全额或部分)。
order.canceled 一笔订单在未付款的情况下结束 —— 结账过期、被取消,或扣款失败。
payment_intent.captured 底层 PaymentIntent 完成 capture(order.paid 的细粒度孪生事件)。
payment_intent.settled 资金已结算(从 pending 变为可支付)。
payment_intent.refunded PaymentIntent 被退款。
payment_intent.failed 尝试扣款并失败。
payment_intent.expired 一次未付款的结账超过了截止时间 —— 终态,从未扣款。
payment_intent.canceled PaymentIntent 在任何扣款前被取消。

大多数接入需要的是订单级事件(order.*);payment_intent.* 孪生事件以更细的粒度承载相同的生命周期,用于直接对账 PaymentIntent。

投递是至少一次的 —— 按 event.id 去重,并用 2xx 应答重试(返回错误会让事件重新入队)。完整指引见 merchant SDK 的 Webhooks 一节

任何会动钱的变更请求 —— 开启结账、capture、退款 —— 都可以通过发送 Idempotency-Key header 来安全重试(Stripe 风格)。用相同的键重试会重放原始响应,而不是把工作做两遍。

Terminal window
curl -X POST https://mcp.curless.ai/v1/... \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: order-8f3a-2026-07-19" \
-H "content-type: application/json" \
-d '{ ... }'

行为:

  • 相同键、相同请求 → 重放已存储的响应(相同状态与 body),并带上 Idempotent-Replayed: true header。工作只执行一次。
  • 相同键、不同请求 body400 VALIDATION_ERROR(“Idempotency-Key was already used with different request parameters”)。一个键会绑定到首次使用它的那个请求。
  • 相同键、原请求仍在进行中409 CONFLICT(“still being processed; retry shortly”)。稍后重试。
  • 处理器失败(5xx / 崩溃) → 占用会被释放,因此用相同键重试会被当作全新请求(失败永远不会“卡住”)。

键按凭据按 mode 隔离,所以一个 test 键和一个 live 键永远不会共享同一条幂等记录(两者都从你的 Curless 钱包 拿 —— test 模式不动真钱,用于端到端测试)。为每个逻辑操作选一个唯一的键(例如你自己的 order id),而不是每次 HTTP 尝试各用一个。

注意:若干协议流程也接受协议级的幂等键,网关内部会对并发的同键 PaymentIntent 创建做去重 —— 但上面这个 header 是 REST API 的通用机制。

令牌桶限流,每 60 秒 120 次请求RATE_LIMIT_MAX / RATE_LIMIT_WINDOW_MS),突发上限为 120。

  • 已认证路由 —— /v1/* 及各协议路径 —— 按 API key(按主体)限流,所以一个商户的流量绝不会吃掉另一个商户的额度。
  • 公开端点(OAuth token/authorize/register、/mcp 资源服务器、托管的 /pay/v1/integrations)按 IP 限流。

超过限额返回 429 RATE_LIMITED。退避后重试;配合 Idempotency-Key,让被重试的写操作不会重复扣款。

健康/就绪探针(/health/ready)以及 Curless 入站 webhook 有意限流(对它们限流会让负载均衡器误判服务已宕机,或丢掉真实的退款事件)。

以上是默认值;如果你的接入需要更高上限,请联系我们。