先看结论:对接分四步。服务器调用 POST /api/v1/payment 创建支付,拿到 url 和 reference_id;把客户带到 url 付款;用 Webhook 收到付款通知,并用状态接口再确认一次;最后按订单号对账。
1. 准备:基础地址与 API 密钥
- 基础地址(BASE_URL):你打开后台用的地址,在后台 设置 → 站点地址(Site URL)里可以看到。PayRamHost 商家的后台和 API 共用同一个地址。
- API 密钥:每个项目有自己的密钥,在后台为项目生成。调用时放在请求头
API-Key里。多个项目就用多个密钥,便于区分和单独停用。
API 密钥只能放在你的服务器上,不要写进网页或手机 App。如果怀疑泄露,立即在后台更换。
2. 第一步:创建支付
在你的服务器上,用你的订单信息创建一笔支付:
curl --location 'https://pay.payramhost.com/api/v1/payment' \
--header 'API-Key: <your_api_key>' \
--header 'Content-Type: application/json' \
--data-raw '{
"customerEmail": "buyer@example.com",
"customerID": "1001",
"amountInUSD": 49.9,
"invoiceID": "ORDER-20260001"
}'
| 字段 | 必填 | 说明 |
|---|---|---|
customerEmail | 是 | 客户邮箱 |
customerID | 是 | 客户在你系统里的唯一编号 |
amountInUSD | 是 | 金额,按美元计 |
invoiceID | 否 | 你自己的订单号,会在 Webhook 里原样返回,强烈建议传 |
expire | 否 | 过期时间,RFC 3339 格式。不传默认 24 小时 |
currency | 否 | 限定只能用某个币种,例如 USDC。不传则由客户自己选 |
network | 否 | 限定只能用某条链,例如 BASE,要和 currency 一起用 |
返回内容:
{
"host": "https://pay.payramhost.com",
"reference_id": "c80f5363-0397-4761-aa1a-3155c3a21470",
"url": "https://pay.payramhost.com/payments?reference_id=c80f5363-...&host=https://pay.payramhost.com"
}
url是现成的付款页面,可以直接发给客户。reference_id是这笔支付的唯一编号,请和你的订单关联起来保存,后面查询和对账都靠它。
支付链接默认 24 小时过期。过期后支付状态变为 CANCELLED。如果你的订单保留时间更短或更长,用 expire 自己指定。
Node.js 示例
async function createPayment(order) {
const res = await fetch(`${process.env.PAYRAM_BASE_URL}/api/v1/payment`, {
method: 'POST',
headers: {
'API-Key': process.env.PAYRAM_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
customerEmail: order.email,
customerID: String(order.userId),
amountInUSD: order.totalUsd,
invoiceID: order.id,
}),
});
if (!res.ok) throw new Error(`PayRam ${res.status}`);
return res.json(); // { host, reference_id, url }
}
Python 示例
import os, requests
def create_payment(order):
r = requests.post(
f"{os.environ['PAYRAM_BASE_URL']}/api/v1/payment",
headers={"API-Key": os.environ["PAYRAM_API_KEY"]},
json={
"customerEmail": order["email"],
"customerID": str(order["user_id"]),
"amountInUSD": order["total_usd"],
"invoiceID": order["id"],
},
timeout=15,
)
r.raise_for_status()
return r.json() # {"host": ..., "reference_id": ..., "url": ...}
3. 第二步:把客户带到付款页
最简单的做法是把客户重定向到返回的 url。客户在页面上选择币种和网络,页面会给出一个专属充值地址,并持续监听到账,状态自动更新。
如果你想做自己的支付界面,官方还提供了其他接口,比如给用户分配固定充值地址、查询支持的币种。细节以 PayRam 官方文档 为准。
4. 第三步:确认到账
订单状态不要靠客户“点了已付款”,要靠 PayRam 的确认。两个办法一起用:
- Webhook(主要方式):付款状态变化时 PayRam 主动通知你的服务器。务必校验签名并做幂等,见 Webhook 完全指南。
- 状态接口(兜底和复核):用
reference_id主动查询。
curl --location 'https://pay.payramhost.com/api/v1/payment/reference/c80f5363-0397-4761-aa1a-3155c3a21470' \
--header 'API-Key: <your_api_key>'
返回的 paymentState 就是当前状态。含义和处理办法见 支付状态详解。
5. 第四步:对账
Webhook 偶尔会漏,所以要有一个定时任务做兜底:
- 每隔几分钟,找出你系统里“还在等待付款”的订单。
- 逐个用保存的
reference_id调用状态接口。 - 如果状态已经是
FILLED,就按正常流程更新订单;如果是CANCELLED,就关闭订单。
你传的 invoiceID 会在 Webhook 里原样返回,所以财务对账时,可以直接用你自己的订单号去查。
6. 一个完整的下单流程
- 客户点击“用加密货币支付”。你的服务器创建订单,状态为“待付款”。
- 服务器调用创建支付接口,保存返回的
reference_id,把客户重定向到url。 - 客户在付款页转账。PayRam 检测到账,等待所需的区块确认数。
- PayRam 向你的 Webhook 地址发送通知,状态为
FILLED。 - 你的服务器校验签名,用状态接口复核一次,然后把订单改为“已付款”并发货。
- 资金由 SmartSweep 自动归集到你的冷钱包,见 SmartSweep 详解。
7. 常见问题
金额必须用美元吗?
创建支付时,金额字段是 amountInUSD,按美元计。客户付款时,页面会把它折算成所选币种的数量。
同一个客户多次付款,会用同一个地址吗?
PayRam 为每位客户分配专属充值地址,官方文档说明一旦分配,同一个区块链家族下该地址会固定,后续付款复用它。EVM 家族的 Ethereum、Base、Polygon 共用同一个地址。
怎么避免重复创建支付?
在你的订单表里保存 reference_id。客户刷新页面或再次点击付款时,先看这个订单有没有未过期的支付,有就直接复用它的 url,不要新建。
用 Shopify 或 WooCommerce 怎么办?
PayRam 提供对应的插件,部署和配置方式以官方文档为准。如果你用的是平台托管的 PayRamHost,请先联系我们确认插件是否适用。
有没有现成的 SDK?
有官方 TypeScript / JavaScript SDK,可以少写很多样板代码,见 SDK 入门。
相关阅读
- Webhook 完全指南:PayRam Webhook 怎么接:在后台添加回调地址,用 X-Payram-Signature 校验签名,理解重试规则与支付状态,做幂等处理,附 Node.js 和 Python 示例。
- 支付状态详解:PayRam 的五个支付状态是什么意思,少付(PARTIALLY_FILLED)、多付(OVER_FILLED)和过期(CANCELLED)该怎么处理,以及如何用 Webhook 和状态接口把订单状态对准。
- TypeScript SDK:用官方 TypeScript / JavaScript SDK 对接 PayRam:安装、初始化客户端、创建支付、查询状态、接收 Webhook(Express、Fastify、Next.js),以及它的校验方式和你该补什么。
- 商家上手指南:PayRam 商家后台中文上手指南:从登录后台到收到第一笔付款,涵盖节点、钱包、热钱包、支付链接、API 与 Webhook 配置。
