PayArrive 商户接入指南

为每位用户提供长期 BSC USDT 充值地址,接收确认事件,再由商户自己的账本完成入账。字段、认证和状态见商户 OpenAPI,它由唯一公共机器合同生成,仅包含五个商户业务接口。本文示例中的用户、UUID、充值地址、交易 hash 和 token 均为合成数据,不可用于转账。

1. 接入前提

控制台使用邮箱登录,创建 Project 后立即取得 Project ID,在 API keys 页面点击“生成密钥”即可取得项目级 Server Key。商户不需要自行申请 Privy App。Project ID 是公开标识,不能用于认证;服务端凭据独立于网页登录,退出网页不会撤销 Key。

凭据分层固定如下:

凭据 作用与存放位置
Project ID 公开项目标识;用于启动自检和展示,不承担认证,也不能切换租户
Project Server Keypa_sk_... 当前 Project 的后端 Secret;使用 Bearer 调用五项商户 API,存放在商户后端或获授权的 MCP 宿主
Session client token 单个充值展示会话的短期能力,只交付对应 C 端页面
PayArrive Privy App ID/Secret PayArrive 平台内部控制台配置;商户无需申请、提交或读取

一个 Project 可以同时保留多个 Server Key 以支持无停机轮换;Secret 只在首次创建成功时展示,丢失后只能撤销并重新创建。

登记 BSC 收款地址后,平台排队部署和验证固定 Factory,技术核验完成后形成可用收款配置;商业收款需要运营审核并开通预付费账户。无需连接钱包或另付部署费。排队、部署、核验和阻塞状态可在网页查询;新开通 Gas 每 UTC 日预算 0.01 BNB,预算耗尽自动排队。收款 destination 可以跨 Project 相同,各 Project 的用户账户仍隔离。激活后不可修改原路径,轮换新增版本。

可先生成 Key、完成代码接入并查询接入状态,再等待地址核验、运营审批和服务余额就绪。创建 Project、取得 Key 或读取文档本身不表示账户已经可以展示。公开版本不要求商户来源 IP 白名单;接口基址为 https://receive.payarrive.com,使用服务端环境变量 PAYARRIVE_BASE_URLPAYARRIVE_SERVER_KEY。部署可用性以实际服务返回为准。

服务费由 B 端预付余额承担,默认 1%:C 端转入 10 USDT,C 端信用及企业链上本金仍为 10 USDT,PayArrive 在确认时记 0.1 USDT 服务费。服务余额由运营确认凭证后充值, 在控制台“服务账单”核对余额、欠费、流水及关联充值。仅开通后首次入库的充值收费, 具体生效时间和整数舍入以已接受的商户条款为准;旧已入库充值不追收。

欠费或零服务余额时新会话返回 409 billing_admission_closed;未审批的新收款版本可返回 409 billing_activation_required,未开放服务可返回 409 admission_paused。请联系运营 充值或完成审核,不得把这些结果显示为用户转账失败。旧 Session 幂等读取和已确认信用 继续恢复,deposit.settled 不再次收费或增加 C 端余额。后端可读取既有 integration context 的真实 BSC Rail metadata,但新链不能由商户填写 RPC/Token/destination 即启用。

商户负责用户登录、用户标识、余额和业务处置;PayArrive 负责充值地址、链上确认、事件及固定目的地归集。无需商户自行查询 RPC,也不要提交客户钱包私钥。当前不提供订单支付、EasyPay 兼容、提现、退款或公共 Webhook。

2. 服务端鉴权、Project ID 与用户归属

五个业务接口都使用 Authorization: Bearer ${PAYARRIVE_SERVER_KEY}。Key 绑定一个 Project,不能通过请求参数改选 Project、destination 或收款版本。不同 Project 的用户与充值事实隔离。创建 Session 的未知字段会被拒绝。

操作 必需权限
getIntegrationContext 任意有效商户 Key
createRechargeSession sessions:write
getRechargeSession sessions:read
listDeposits deposits:read
listEvents events:read

网页一键生成充值接入 Key,自动命名,包含四项商户权限,有效期为 90 天,无需填写表单。控制台 API 仍支持按需选择权限和 30/90/365 天有效期;Secret 只展示一次,数据库只保存哈希。创建响应丢失后以原幂等键重试,返回元数据且 secret: null 时,撤销该 Key 并重新创建。轮换时先创建新 Key、迁移服务配置并验证,再撤销旧 Key。到期或撤销立即阻止后续调用,包括已连接 MCP。普通 Key 不能创建其他 Key、变更收款路径或调用内部信用接口。

curl --fail-with-body "$PAYARRIVE_BASE_URL/v1/integration-context" \
  -H "Authorization: Bearer $PAYARRIVE_SERVER_KEY"

返回 project_idscopes、官方 Rail、api_revisiondocs_revisionserviceservice.statuspending_activationavailablepausedunavailablereason 为可处理错误码。 这个接口不签发充值地址;展示仍须通过 Session 接口的实时核验。

external_user_ref 必须由商户后端从已验证的登录身份派生,在同一 Project 内稳定且唯一。不要直接信任浏览器传来的用户 ID、昵称、金额或 query。查询某用户记录前,商户后端同样要核对当前登录用户的权限。

Server Key 只留在商户后端或获授权的 MCP 宿主运行环境;不放入模型参数、浏览器、URL、日志、分析埋点或公开代码。浏览器仅取得单个 Session 的短期凭据。商户操作员通过 MCP 选择已有用户引用不等于完成该用户登录;面向 C 端的入口仍从商户后端验证身份。CloudAIKey 身份由既有 Sidecar 调用私有 /api/v1/auth/me 验证,无需另建身份或信用服务。

3. 创建 RechargeSession

POST /v1/recharge-sessions 创建的是展示会话,不是支付订单。一次会话可以没有充值,也可以收到多笔充值。

curl --fail-with-body "$PAYARRIVE_BASE_URL/v1/recharge-sessions" \
  -H "Authorization: Bearer $PAYARRIVE_SERVER_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: demo-session-001' \
  --data '{"external_user_ref":"user_demo_001","asset_id":"bsc-usdt"}'
字段 规则
Idempotency-Key 必填请求头,商户后端生成并持久保存;同一逻辑请求重试使用原值
external_user_ref 必填非空字符串,服务端会去掉两端空格
asset_id bsc-usdt;省略或 null 也选择该资产
display_amount_atomic 可选正整数字符串或 null,18 位精度的展示金额;不用于订单匹配或判定实收金额

首次成功为 201,响应示例:

{
  "recharge_session_id": "11111111-1111-4111-8111-111111111111",
  "asset_id": "bsc-usdt", "chain_id": 56, "network": "BSC",
  "receiving_address_version": 1,
  "deposit_account": "0x1111111111111111111111111111111111111111",
  "token_address": "0x55d398326f99059ff775485246999027b3197955",
  "token_symbol": "USDT", "token_decimals": 18,
  "display_amount_atomic": null, "credit_decimals": 6, "rounding": "floor",
  "client_token": "EXAMPLE_ONLY",
  "checkout_url": "https://receive.payarrive.com/pay/11111111-1111-4111-8111-111111111111#token=EXAMPLE_ONLY",
  "status_url": "/v1/session-status/11111111-1111-4111-8111-111111111111",
  "status": "waiting",
  "created_at": "2026-09-09T00:00:00.000Z",
  "expires_at": "2026-09-09T00:15:00.000Z"
}

同一 Project、同一幂等键和相同用户/资产/展示金额返回原 Session,状态码 200;改变这些值返回 400 recharge_session_idempotency_conflict。有效会话重放可返回短期凭据,但不会延长原 expires_at

网络超时或响应丢失时,必须用原幂等键和原请求重试。已到期的会话重放返回 200,不返回 client_tokencheckout_url;仍为 waiting 时显示 status: expired,已有充值时保留原资金状态。展示凭据到期不撤销到账或信用。确认原请求结果且需要新的展示会话后才生成新幂等键;同一用户在同一收款版本下仍复用原长期地址。

4. 展示地址与长期有效性

通用接入使用 POST 返回的 checkout_url 打开托管充值页。短期 token 位于 URL 的 fragment 中;不要记录或分享完整链接。自行展示时使用返回的账户、链和官方资产信息,不允许用户提交替代地址。短期 token 可用于返回的 status_url,不能访问服务端业务接口。

CloudAIKey 的 USDT (BSC) 入口由同源 Sidecar 完成身份验证和会话创建。客户原生弹窗在 /purchase 显示长期地址与二维码,旧 /collect 保留兼容;实际安装以交付记录为准。该入口不转发支付宝金额、不生成法币订单,也不能凭它认定余额可以购买订阅套餐。流水读取失败不等于转账失败;余额以客户实际信用结果为准,归集不重复上账。

Session 默认十五分钟的期限只控制展示凭据,不让充值地址失效或转交其他用户。地址归属由 Project、可信用户标识、链、资产和收款版本共同确定;同一身份反复打开会复用该版本的地址。商户轮换收款配置只能新增版本,不能修改既有地址的资金路径,旧地址和历史继续保留。

每笔实际官方 USDT Transfer 都独立记录;多笔、同金额、迟到到账不能按最近一次 Session 或页面金额猜归属。接口拒绝展示或账户不可用时不要继续显示缓存地址,按错误状态处理;准入暂停不改变既有长期地址的归属。

5. 查询会话与充值记录

GET /v1/recharge-sessions/{session_id} 用 Server Key 查询同一 Project 的会话;它不签发 client_tokencheckout_url。需要重新取得有效展示凭据时按上一节的 POST 规则处理。

curl --fail-with-body "$PAYARRIVE_BASE_URL/v1/recharge-sessions/11111111-1111-4111-8111-111111111111" \
  -H "Authorization: Bearer $PAYARRIVE_SERVER_KEY"

200 响应的基础字段与创建结果相同,凭据字段省略。下面是尚无充值时的完整响应;有链上活动时附加 Deposit 字段:

{
  "recharge_session_id": "11111111-1111-4111-8111-111111111111",
  "asset_id": "bsc-usdt", "chain_id": 56, "network": "BSC",
  "receiving_address_version": 1,
  "deposit_account": "0x1111111111111111111111111111111111111111",
  "token_address": "0x55d398326f99059ff775485246999027b3197955",
  "token_symbol": "USDT", "token_decimals": 18,
  "display_amount_atomic": null, "credit_decimals": 6, "rounding": "floor",
  "status_url": "/v1/session-status/11111111-1111-4111-8111-111111111111",
  "status": "waiting",
  "created_at": "2026-09-09T00:00:00.000Z",
  "expires_at": "2026-09-09T00:15:00.000Z"
}

GET /v1/deposits 用于展示指定用户最近的充值记录:

curl --fail-with-body --get "$PAYARRIVE_BASE_URL/v1/deposits" \
  -H "Authorization: Bearer $PAYARRIVE_SERVER_KEY" \
  --data-urlencode 'external_user_ref=user_demo_001' --data-urlencode 'limit=100'
{
  "deposits": [{
    "deposit_id": "22222222-2222-4222-8222-222222222222",
    "tx_hash": "0x1111111111111111111111111111111111111111111111111111111111111111",
    "log_index": 0, "amount_atomic": "1000000000000000000",
    "confirmations": 15, "deposit_status": "confirmed",
    "settlement_status": null, "credited_value": "1.000000",
    "discarded_atomic": "0", "first_seen_at": "2026-09-09T00:02:00.000Z"
  }]
}

limit 默认 100,允许 1..1000。这是近期列表,没有历史分页游标;空列表不能证明完整历史无充值,最新一笔也不能代表整个会话。恢复全部事件应使用 Cursor。

deposit_statusdetected / confirming / confirmed / reverted。成功交易 hash 本身不证明到账;确认还须匹配官方资产、账户归属、金额及链上确认策略。单笔待确认通常约五秒复查,但这不是五秒到账承诺。credited_value 只是归一化展示值,不证明商户余额已经增加。

6. 金额精度

BSC 官方 USDT 使用十八位精度,1 USDT = "1000000000000000000" 原子单位。amount_atomic 等原子金额用十进制整数字符串,credited_value 是六位小数字符串;禁止用 NumberparseFloat 或浮点乘法计算资金。

六位归一化采用逐笔向下截断。以下仅演示精度计算,不执行信用或客户余额转换:

const amountAtomic = BigInt("1234567890123456789");
const microUnits = amountAtomic / (10n ** 12n); // 1234567n
const discardedAtomic = amountAtomic % (10n ** 12n); // 890123456789n
const normalized = `${microUnits / 1000000n}.${(microUnits % 1000000n).toString().padStart(6, "0")}`;
// normalized === "1.234567"

尾数保留为 discarded_atomic,不能跨 Deposit 累计;不足一个六位单位时保留原充值事实,不增加余额。商户余额的币种、换算和最终账本由商户拥有,CloudAIKey 的专用信用适配不可作为通用商户余额 API 使用。

7. Cursor 事件与唯一入账

GET /v1/events 返回当前 Project 的追加式事件。初次从 cursor=0 开始,重启从已持久化的游标继续:

curl --fail-with-body --get "$PAYARRIVE_BASE_URL/v1/events" \
  -H "Authorization: Bearer $PAYARRIVE_SERVER_KEY" \
  --data-urlencode 'cursor=0' --data-urlencode 'limit=100'
{
  "events": [{
    "sequence": "42", "event_id": "33333333-3333-4333-8333-333333333333",
    "type": "deposit.confirmed", "deposit_id": "22222222-2222-4222-8222-222222222222",
    "external_user_ref": "user_demo_001", "amount_atomic": "1000000000000000000",
    "asset_id": "bsc-usdt", "created_at": "2026-09-09T00:03:00.000Z"
  }],
  "next_cursor": "42"
}

cursorsequencenext_cursor 始终作为字符串保存;序号可能有间隔,不自行加一。limit 同样默认 100、最大 1000。按返回顺序读到空页,空页保持传入游标;空闲后再轮询,不持续空转。

可靠消费需要两层幂等:

  1. 投递去重: 在商户数据库事务中保存整页事件及待处理工作,并更新该 Project 的 cursor;用 event_id 防重复。先落盘再推进,失败时保留旧 cursor。
  2. 账务唯一:(Project, deposit_id) 约束最多一次正向信用,不能仅按 event_id 去重。同库余额与信用记录在同一事务提交,按 Deposit 顺序处理事件并先检查已收取的修正;同页已有 deposit.reverted 时不能盲目执行较早的确认事件。
事件 处理方式
deposit.confirmed 允许开始一次幂等信用;确认用户、资产、金额和该 Deposit 尚未信用
deposit.settled 固定收款目的地归集对账,不再次增加余额
deposit.reverted 停止未执行信用;已有信用保留事实并进入人工对账,不静默扣除或删除
settlement.reverted 归集证据被修正;不能据此冲销仍规范的入站充值

调用外部余额系统前,持久化原操作身份和参数;响应丢失或超时标记 unknown,查询原操作并恢复,不能换 code、key 或请求体再次加款。充值已被修正时只查询既有结果,不重放信用;无法证明结果时保留待处理状态。CloudAIKey 已有 Sidecar 负责这条路径,不要再并行接入第二个信用 consumer。

8. 错误处理与接入验收

响应 建议动作
400 检查参数和幂等冲突;未知结果的重试不能靠换 Key 绕过
401 修正失效、撤销或错误凭据;不尝试退回 query token
404 资源不存在于当前 Project;检查归属,不跨项目补查
409 admission_paused 新会话或账户准入暂停,等待恢复
409 deposit_account_unavailable 账户不可用,停止展示缓存地址
413 缩小请求体后按原逻辑操作处理
500 / 503 或网络超时 保存未知结果,使用原操作身份有限退避重试;告警后等待恢复,不无限重试

创建请求必须是 JSON 对象,否则返回 400 request_body_invaliddisplay_amount_atomic 不接受 JSON 数字,即使数值看似是整数也返回 400 display_amount_invalid;发送十进制整数字符串,避免大整数在传输前被舍入。

读取 Deposit/事件仍可能在 Observer 停用时可用,不代表新地址或确认服务健康。地址接口不可用时不要靠缓存继续开放;界面只展示已知状态,不能把 unknown 写成“未充值”。

接入验收至少确认:同一身份反复打开复用地址;不同用户和 Project 隔离;失效身份不取得地址;同笔事件重放和进程重启不重复信用;修正和未知结果可暂停、恢复及对账。示例与页面可访问不等于完成这些验收。正式开放仍按实际开通范围及客户验收执行,不通过文档扩大流量或追加测试资金。

9. SDK、MCP 与接入示例

本指南与 API 合同随发布物提供,API 版本为 0.1.0-alpha。当前业务开通范围仍以第 1 节为准;文档可访问不表示商户已激活、资金服务已开通或某个 AI 客户端已通过兼容性验证。

Node.js SDK

下载 SDK 与 MCP 安装包。它从本次发布的源码构建,包名为 @payarrive/merchant、版本为 0.1.0,不依赖 npm registry 中存在同名发布。使用 Node 22.22.3,在商户后端项目中安装已取得的包:

npm install ./payarrive-merchant-0.1.0.tgz
import { PayArriveServerClient, PayArriveApiError } from "@payarrive/merchant";

const client = new PayArriveServerClient(
  process.env.PAYARRIVE_BASE_URL!,
  process.env.PAYARRIVE_SERVER_KEY!,
);

async function inspectRecharge(
  savedRequest: { externalUserRef: string; idempotencyKey: string },
  storedCursor: string,
) {
  const context = await client.getIntegrationContext();
  if (context.service.status !== "available") throw new Error(context.service.reason ?? "service_unavailable");
  const session = await client.createRechargeSession(savedRequest);
  const status = await client.getRechargeSession(session.recharge_session_id);
  const history = await client.listDeposits({
    externalUserRef: savedRequest.externalUserRef, limit: 100,
  });
  const eventPage = await client.listEvents({ cursor: storedCursor, limit: 100 });
  return { session, status, history, eventPage };
}

savedRequest 应先由商户后端验证用户并持久保存;storedCursor 来自本地持久游标。上述函数展示五个 SDK 调用,事件页仍须按第 7 节事务落盘后才能推进游标或处理信用。创建结果包含短期凭据,不要记录整个返回对象。SDK 的 camelCase 输入转换为 REST/MCP 的 snake_case 字段;金额与 Cursor 仍为字符串。已有 getDepositHistory(externalUserRef, limit) 调用继续可用。

SDK 默认每次请求十秒超时、拒绝 HTTP 重定向且不自动重试。PayArriveApiError 提供 statuscoderetryable 及可选 retryAfterMs;未取得 HTTP 响应时 statusnull。只按这些安全字段分类,不记录原始响应或凭据。retryable 不是失败已回滚的证明;创建结果未知时,保存并复用原用户、金额和幂等键。响应不符合官方资产、金额或事件合同也会抛错,不能据此自行构造充值地址。

商户业务 MCP

同一安装包提供 payarrive-mcp 命令。它使用 Server Key 调用真实商户 API,开放以下五个工具;不管理余额、签名或归集任务。

工具 输入 结果
getIntegrationContext Key 对应 Project、有效权限、Rail、开通状态及资料 revision
createRechargeSession external_user_ref、必填 idempotency_key;可选 asset_iddisplay_amount_atomic 创建或恢复原会话;有效时返回短期 checkout 凭据
getRechargeSession session_id 同一 Project 的会话状态,不签发浏览器凭据
listDeposits external_user_ref、可选 limit 指定用户近期充值记录
listEvents 可选字符串 cursor、可选 limit 追加事件页及 next_cursor,不保存游标或执行信用

MCP 的用户引用、幂等键和 Session ID 为 1 至 256 字符,不能带两端空格;asset_id 仅接受 bsc-usdtnull 或省略。展示金额为正整数字符串、null 或省略,金额及 Cursor 最多 78 位;limit 为 1 至 1000 的整数。工具拒绝额外字段,不能传入 Key、Project、destination、任意 URL、请求头或内部信用指令。创建前应在商户系统中取得并保存原幂等键,结果未知时继续使用原值。获授权操作员可选择已有 external_user_ref,但模型提供该值不能证明 C 端身份已验证。

Codex stdio 配置: 安装包之后,在 Codex 的 config.toml 中配置已安装命令的绝对路径。通过启动 Codex 的环境提供 Key 与 API 基址,配置内容和模型参数均不写入 Key 值。

[mcp_servers.payarrive]
command = "/absolute/merchant/node_modules/.bin/payarrive-mcp"
env_vars = ["PAYARRIVE_SERVER_KEY", "PAYARRIVE_BASE_URL"]

PAYARRIVE_BASE_URL 使用可信 HTTPS API origin,本地集成允许 loopback HTTP。有仓库的开发者也可执行 npm run start:merchant-mcp。公开商户版本通过 Key 与权限认证,不依赖模型名称或商户 IP 白名单。

Codex 远程 HTTP 配置: 服务端业务 MCP 入口为 https://receive.payarrive.com/mcp/merchant。使用商户 Server Key 的 Bearer 认证;每次调用重新验证 Key 的权限、到期和撤销,不把连接成功当作长期授权。

[mcp_servers.payarrive]
url = "https://receive.payarrive.com/mcp/merchant"
bearer_token_env_var = "PAYARRIVE_SERVER_KEY"

两份配置选用一份。本地 API 测试可使用 http://127.0.0.1:4342/mcp/merchant;API 进程显式设置 MERCHANT_MCP_PORT=4342 后启用独立 loopback listener。实际安装与反代由服务方配置,本文中的 URL 不代替实际部署检查。宿主须支持 MCP 或通过 function calling 调用;普通模型网页端的原生 MCP 能力不作承诺。

创建工具会把短期 client_token 和带 token fragment 的 checkout_url 返回获授权的宿主及模型,供打开充值页使用。这些是敏感展示能力:不要写入日志、索引或公开分享。Server Key 不进入工具输出;只删除 client_token 字段也不能消除完整 checkout 链接中的凭据。

可运行示例

公开发布物提供示例说明及同目录的 merchant.tsdemo.tslive.tsheadless.tstsconfig.jsonpackage.json,共七个文件,无需访问项目仓库。在同一目录使用 Node 22.22.3 执行 npm installnpm run build。准备名为 payarrive_merchant_demo 的隔离本地 PostgreSQL 数据库,设置 MERCHANT_DEMO_DATABASE_URL 后,npm start 默认运行合成数据示例,不调用真实 API。

显式真实 API 模式在同一示例目录执行 npm run live;仓库内执行 npm run example:merchant:live。这两个脚本已包含 CLI 必需的 --live 标志,不要重复追加。它使用 PAYARRIVE_BASE_URLPAYARRIVE_SERVER_KEYMERCHANT_PROJECT_REFMERCHANT_EXTERNAL_USER_REFMERCHANT_IDEMPOTENCY_KEY,通过五项真实 API 操作(含接入上下文)并将事件持久保存到上述开发数据库。Project 引用必须等于控制台取得的 Project ID;示例先通过接入上下文核对 Key 的 Project,匹配后才创建会话和写入本地账本,避免凭据配置错误导致跨商户混账。用户引用应由获授权测试操作员提供。创建会话会产生真实 API 持久记录,必须使用获准的开发环境与测试身份。

示例信用和余额始终是隔离开发数据库中的演示记录,即使事件来自实际 API 也不是生产客户余额。不要把固定测试身份或示例账本接入生产,不要与 CloudAIKey 既有 Sidecar 并行执行第二个信用 consumer。外部余额系统的 unknown 恢复仍按第 7 节查询原操作;示例成功不替代外部验证。

文档 MCP 与 AI 编码

让 AI 为既有项目接入时,先读取本指南和商户 OpenAPI,复用已有登录与数据库,再使用已安装的 SDK。文档 MCP 入口为 https://receive.payarrive.com/mcp/docs,只开放 get_integration_guideget_api_operationsearch_docs,不需要 Server Key,不访问商户数据。它与上述业务 MCP 的权限独立。

[mcp_servers.payarrive_docs]
url = "https://receive.payarrive.com/mcp/docs"

下载包、示例和远程 MCP URL 均属于此次发布物;是否已部署需检查实际 HTTP 响应。Codex 的实际工具调用与生成代码应先在合成数据和隔离数据库中验证幂等、重放、崩溃恢复及撤销处理;本指南不声称其他模型或宿主已通过验证。