Skip to main content
需要 Silver 或更高等级的会员 — 申请时需要,之后每一次已认证的调用同样需要。若密钥所有者的会员到期,项目会被冻结,直到其重新订阅。
一套 REST API,让你的应用在 Discord 内直接操作用户的 Vito 余额:读取、扣款、充值,或在用户之间转移。所有端点都返回 JSON,并在 /v1 下进行版本管理。
Vito 永远不会与真实货币互相兑换。 它只在 Vetox 余额之间流动。
所有端点都位于 https://api.vetox.io/public/vito 之下。本页写出的路径——/v1/deduct/v1/balance/:discordId 等——都是相对于该前缀的,而这个前缀正是 SDK 替你补上的。若你自行调用,请使用完整 URL:
https://api.vetox.io/v1/deduct 并不是一个路由,会返回 404。
在用 Node.js 开发?不必手写 REST 调用 — 请使用官方软件包 @vetox-bot/vito。它涵盖全部九个端点以及 webhook 校验,并替你处理幂等性与重试。详见下方的官方 Node.js SDK

获取访问权限

访问权限按项目授予。以下四项缺一不可:
1

有效的 Silver 或更高等级会员

每次调用都会检查,而不只是在审批时检查。
2

已获批准的开发者申请

在控制面板的 Vito API 页面提交,由 Vetox 团队人工审核。
3

已接受的 API 开发者条款

在提交申请时确认。
4

项目所需的 scope

由 Vetox 团队根据你的描述授予。
请具体说明你要做什么、以及会如何保存密钥。被拒绝的往往正是描述含糊的申请。

Scope

身份验证

将密钥作为 Bearer 令牌发送:
两个可选层级可进一步加固项目:
  • IP 白名单 — 将调用限制在特定的服务器 IP
  • 速率限制 — 按项目设定的上限,随所有者的会员等级提升

密钥、轮换与保管

密钥和签名密钥只会显示一次。 获批后你有 7 天的窗口期可在 API 密钥标签页中查看它们。Vetox 只保存哈希,无法再次显示 — 错过窗口期就只能轮换以获取新的。
  • 只将其保存在服务端 — 任何持有它的人都能向你的用户扣款
  • 在 API 密钥标签页中轮换。旧密钥会继续生效 24 小时作为宽限期,让你不停机完成部署
  • webhook 签名密钥单独轮换,拥有各自的 24 小时重叠期
  • 一旦泄露,请立即轮换

官方 Node.js SDK

官方软件包 @vetox-bot/vito 封装了全部九个端点以及 webhook 校验。它替你处理 Idempotency-Key 请求头、带指数退避的重试、超时以及错误分类。

安装

需要 Node.js 20 或更高版本。该软件包没有任何运行时依赖 — 它使用内置的 fetchnode:crypto — 同时提供 ESM 和 CommonJS 两种格式,并附带完整的 TypeScript 类型定义。

初始化

若不传 apiKey,SDK 会从环境变量读取 VITO_API_KEY。密钥格式在构造时即被校验,因此格式错误的密钥会立刻失败,而不会白白花掉一次网络往返和一个 401。
这把密钥可以转移资金 — 请始终保存在服务端,绝不要放进客户端打包产物或浏览器。console.log(vito) 打印的是 [redacted] 而非密钥;对于非本地主机,SDK 会拒绝任何使用 http://baseUrl,以免密钥以明文传输。

客户端选项

可用方法

每个方法都直接返回已解包的 data 字段 — 你永远不需要自己去取 successdata。所有方法还接受按次调用的选项:{ timeoutMs, maxRetries, signal, headers },写入类方法另外接受 { idempotencyKey }

使用示例

启动时校验密钥

读取余额

向用户扣款(售出商品)

此处只把订单记为待处理。扣款尚未发生 — 请在收到 confirmation.completed webhook 时发货,而不是在这条响应时。

为用户充值

遍历交易

幂等性与重试

SDK 会在每一次写入deductcredittransfer)时发送 Idempotency-Key 请求头。如果你没有提供,它会每次调用只生成一次,并在每次重试时重发完全相同的键,因此重试绝不可能把同一笔操作结算两次。 当同一个逻辑操作可能从新的进程重新发起时 — 任务执行器、队列重投递或定时扫描 — 请自行提供键:
auth.rotateKey() 是刻意排除的 — 在那里重试会签发第二把密钥,并使第一次调用返回的那把作废。
Retry-After 超过 maxRetryDelayMs(说明你的每小时配额确实已经耗尽),SDK 会立即抛出 VitoRateLimitError,而不是把你整个请求预算耗在等待上。

用 SDK 校验 webhook

constructEvent 会检查 5 分钟的重放窗口,以常数时间与请求头中的每一个 h1 签名比对 — 因此在 24 小时的密钥轮换重叠期内自动可用 — 随后解析载荷并返回带类型的事件。 在 Next.js(App Router)的路由处理函数中,请使用会自行读取原始请求体的变体:
签名覆盖的是原始字节。在 Express 中,请为 webhook 路由挂载 express.raw({ type: 'application/json' })express.json() 会消费掉请求体,之后每一次校验都会失败。在 Next.js 中,不要在 constructEventFromRequest 之前调用 request.json()
投递是至少一次的。在执行任何副作用之前,请先按 event.eventId 去重。

错误处理

SDK 抛出的一切都继承自 VitoError,并携带 codestatustyperequestIdretryable
请始终记录 requestId — 支持团队正是靠它来追踪某一次具体调用。

取消一次调用

取消同时会终止仍在等待的重试,并抛出错误码为 VITO_SDK_ABORTEDVitoConnectionError

向用户扣款

仅凭密钥无法转移用户的 Vito。 每一笔扣款都需要用户在 vetox.io 上用钱包 PIN 批准 — 绝不会在你的应用内,也不会在 Discord 内进行。
1

你的应用调用 POST /v1/deduct

附带用户、金额、发起的 guildId 以及商品详情。
2

Vito 返回 confirmUrl

一条待确认记录,有效期 10 分钟。用户同时会收到私信。
3

用户用 PIN 批准

vetox.io 上完成。
4

Vito 结算并通知

余额被扣除,交易被记录;若你配置了 webhook,会发送一条带签名的通知。
5

你的应用验证并完成

校验签名,然后解锁内容或发放商品。
只在收到 confirmation.completed 时才完成你的操作 — 绝不要依据 /deduct 的响应。在那一刻扣款尚未最终确定。

请求参数 — /v1/deduct

为用户充值

POST /v1/add 从你自己的余额为用户充值 Vito,用于奖励或退款。除 guildIdproduct 外,字段与 /deduct 相同。
与扣款不同,充值没有确认步骤 — 会立即结算。需要 credit:create scope 和足够余额,否则调用返回 402 VITO_INSUFFICIENT_OWNER_FUNDS

费用

每笔扣款在扣除平台手续费后结算给你 — 采用与应用内 Vito 转账相同的费率,依据你的会员等级:
5 Vito 及以下的金额免手续费,通过 /v1/add 的充值则始终免手续费。

Webhook

在设置标签页中添加一个或多个 https 回调地址。每当一条确认记录进入终态,Vito 就会发送一条带签名的 POST
只有当项目同时具备回调地址签名密钥时,webhook 才会发送。请在 API 密钥标签页中一次性查看密钥(whsec_…)。

校验签名

每次投递都带有 X-Vito-Signature 请求头:
每次投递还会附带另外两个请求头 — 请用 X-Vito-Event-Id 作为去重键,因为重试会发送相同的 id:
在签名密钥轮换期间,该请求头会携带不止一个签名,最新的在前:
只要任意一个 h1 匹配就应接受这次投递。只读取第一个的校验代码会拒绝所有 webhook,直到它部署了新密钥 — 而这恰恰让 24 小时重叠期失去了意义。
在 Node.js 上:@vetox-bot/vito 中的 Webhooks.constructEvent 会替你完成下面这一切 — 重放窗口、与每一个 h1 签名比对,以及常数时间比较 — 并返回带类型的事件。下方代码适用于自行实现或使用其他语言的场景。
用你的签名密钥对 <ts>:<rawBody> 重新计算 HMAC,并以常数时间比较。
请针对原始请求体进行校验,要在任何 JSON 解析或中间件改写之前完成。

事件

共五种事件类型,全部共用同一种载荷结构。结果由 data.status 承载。
webhook 会以退避策略重试 5 次。请尽快返回 2xx,并异步执行你的发货逻辑。

错误码

每个响应都包在一层信封里。成功携带 data,失败携带 error,两者绝不会同时出现:
每个错误码都带有 VITO_ 前缀。 请以完整字符串进行判断 — 裸的 RATE_LIMITEDFORBIDDEN 绝不会出现在响应中。

速率限制

此外还有按 IP 的限制,为你每分钟配额的一半,最低不少于 30。
在高负载下,写入端点会「失败即拒绝」 — 宁可拒绝这笔扣款,也不冒重复扣款的风险;读取端点则「失败即放行」。请把被拒绝的写入视为「没有发生过」并重试。
发送 Idempotency-Key 请求头,即可安全地对重试去重。

端点

限制

  • 确认记录会在 10 分钟后过期 — 请把未确认的请求当作已放弃
  • amount 必须是正整数
  • metadata 最多 10 个键
  • 单笔与每日上限由 Vetox 团队设定,在设置标签页中以只读方式展示

安全检查清单

API 密钥与签名密钥绝不属于客户端代码。任何一个泄露都要立即轮换。
对照原始请求体校验签名,并拒绝早于约 5 分钟的投递。
切勿依据 /deduct 的响应发货 — 扣款要到 confirmation.completed 才算最终确定。
只申请你真正使用的 scope,并启用 IP 白名单。

疑难排查

所有者的会员已到期。它在每次调用时都会重新检查。
无法找回 — 系统只保存哈希。请轮换以获取新的密钥。
在 24 小时重叠期内请同时接受新旧两个密钥。
用户没有批准。确认记录会在 10 分钟后过期。
项目需要同时具备回调地址和签名密钥。只有其中之一时,什么都不会发送。
这是结算手续费。使用 5 Vito 及以下的金额可以避免,或把它计入你的定价。
/v1/add 由你自己的余额出资,并非凭空产生。请先充值。

Vito

余额、PIN 与费用。

付款请求

你向用户扣款时,他们看到的界面。

npm 上的 @vetox-bot/vito

官方 Node.js 软件包 — 一次安装,完整集成。