On-Ramp
墨西哥 MXN 购买 USDT。收款账号开通与查询、报价、下单、查单、订单状态和 Webhook 事件。接口细节见 API 参考。
概述
On-Ramp 接口让商户代付款人用墨西哥比索(MXN)购买 USDT。付款人通过 SPEI 转账付款。订单完成后,USDT 记入商户在 Stabo 的钱包余额。
本期能力:
- 收款账号:为付款人开通专属 CLABE,并查询开通状态
- 报价:按 MXN 金额查询参考价
- 下单:按 MXN 或 USDT 金额下单,返回付款人专属 CLABE 和付款指引
- 查单:查询订单状态
- 订单通知:订单完成或失败时,通过 Webhook 推送订单
本期范围:
| 项目 | 取值 |
|---|---|
| 国家 | MX |
| 法币 | MXN |
| 付款方式 | SPEI |
| 稳定币 | USDT |
| 付款人类型 | 个人 |
接口字段可能调整,调整时更新变更记录。
版本:v0.1
接入准备
- 创建 API 密钥:在控制台「集成 → 密钥管理」新增密钥,获取
client_id、client_secret和tenant_id。详见快速开始 - 开通功能:联系 Stabo 客户经理确认 On-Ramp 已开通。未开通时接口返回
On-ramp is not enabled - 配置 IP 白名单:在密钥的「修改 IP 白名单」中填写服务器出口 IP
- 配置 Webhook(建议):在控制台「集成 → Webhooks」添加 HTTPS Endpoint,并订阅
onramp.order.completed、onramp.order.failed
鉴权方式、请求头和通用数据格式见快速开始、鉴权和通用约定。On-Ramp 接口不需要 X-Channel-Provider。商户身份从 Token 解析,请求体不接受商户或租户字段。
环境信息
| 环境 | Base URL | 说明 |
|---|---|---|
| 测试环境 | https://api.test.stabofx.com | 用于开发和测试 |
| 生产环境 | https://api.stabo.io | 正式生产环境 |
接入流程
开通收款账号
付款人注册或绑定时,调用开通收款账号接口。用查询收款账号接口确认状态为 ACTIVE。
查询报价
调用报价接口,展示参考价给付款人。报价不锁价,最终价格以下单响应为准。
创建订单
调用下单接口,拿到 paymentInfo.clabe 和应付金额 fiatAmount。
付款人转账
付款人在 expiresAt 之前,向 clabe 转账 fiatAmount MXN。
接收结果
接收 Webhook 通知,或轮询查单接口。状态变为 COMPLETED 时,cryptoAmount USDT 已记入商户钱包。
API 一览
| 模块 | 接口 | 说明 |
|---|---|---|
| Receive Account | POST /openapi/v1/collections/on-ramp/receive-accounts | 开通收款账号 |
| Receive Account | GET /openapi/v1/collections/on-ramp/receive-accounts/{payerId} | 查询收款账号 |
| Quote | GET /openapi/v1/collections/on-ramp/quote | 查询报价 |
| Order | POST /openapi/v1/collections/on-ramp/orders | 创建订单 |
| Order | GET /openapi/v1/collections/on-ramp/orders/{orderId} | 查询订单 |
| Webhook | 商户配置的 HTTPS URL | 接收订单完成、失败事件 |
每个接口的参数、响应和在线调试见 API 参考。
接口说明
开通收款账号
为付款人开通专属收款 CLABE。开通需要几分钟。请在付款人注册或绑定时调用,不要等到付款时再开户。
curl -X POST "https://api.test.stabofx.com/openapi/v1/collections/on-ramp/receive-accounts" \
-H "Authorization: Bearer {accessToken}" \
-H "Content-Type: application/json" \
-d '{
"payerId": "payer-0001",
"fiatCurrency": "MXN"
}'响应示例:
{
"code": 200,
"message": "OK",
"traceId": "trace-uuid-string",
"data": {
"payerId": "payer-0001",
"fiatCurrency": "MXN",
"paymentMethod": "SPEI",
"status": "PENDING",
"clabe": null
}
}开通状态:
| 状态 | 说明 | 处理方式 |
|---|---|---|
PENDING | 开通中 | 用查询收款账号接口查询,直到状态变为 ACTIVE 或 FAILED |
ACTIVE | 已开通 | 可以下单 |
FAILED | 开通失败 | 提供 payerId 和 traceId 联系 Stabo |
注意事项:
- 本接口幂等。同一
payerId重复调用,返回同一个收款账号的当前状态,不会重复开户。不需要Idempotency-Key。 - 开户不需要付款人 KYC。KYC 在下单时提交。
- 本期不推送开户结果通知。请用查询收款账号接口查询,建议间隔 1 分钟以上。
- 收款账号长期有效。同一付款人以后的订单都使用这个 CLABE。
查询收款账号
查询付款人收款账号的开通状态和 CLABE。payerId 为路径参数,fiatCurrency 为查询参数,固定 MXN。
curl -X GET "https://api.test.stabofx.com/openapi/v1/collections/on-ramp/receive-accounts/payer-0001?fiatCurrency=MXN" \
-H "Authorization: Bearer {accessToken}"响应结构与开通收款账号的响应相同。已开通时的响应示例:
{
"code": 200,
"message": "OK",
"traceId": "trace-uuid-string",
"data": {
"payerId": "payer-0001",
"fiatCurrency": "MXN",
"paymentMethod": "SPEI",
"status": "ACTIVE",
"clabe": "706180000000000001"
}
}注意事项:
- 只能查询本商户的付款人。没有开过户的
payerId返回「收款账号不存在」。
查询报价
报价只支持按 MXN 金额查询。下单可以按 MXN(fiatAmount)或 USDT(cryptoAmount)金额。
curl -X GET "https://api.test.stabofx.com/openapi/v1/collections/on-ramp/quote?country=MX&fiatCurrency=MXN&cryptoCurrency=USDT&fiatAmount=954.77" \
-H "Authorization: Bearer {accessToken}"报价不生成报价 ID。下单时不需要传报价信息。
创建订单
Idempotency-Key 必填,最长 128 字符,建议用 UUID。fiatAmount 和 cryptoAmount 必须传且只传一个。示例中的付款人信息均为虚构数据。
curl -X POST "https://api.test.stabofx.com/openapi/v1/collections/on-ramp/orders" \
-H "Authorization: Bearer {accessToken}" \
-H "Idempotency-Key: 7f9c2a1e-0b6d-4c2f-9d7e-1a2b3c4d5e6f" \
-H "Content-Type: application/json" \
-d '{
"referenceNo": "merchant-order-0001",
"country": "MX",
"fiatCurrency": "MXN",
"cryptoCurrency": "USDT",
"cryptoAmount": "50.000000",
"payerId": "payer-0001",
"payer": {
"name": "Juan Perez Lopez",
"email": "juan@example.com",
"phone": "+5215512345678",
"country": "MX",
"address": "Av. Reforma 1, Ciudad de Mexico",
"dateOfBirth": "1990-01-31",
"idType": "NATIONAL_ID",
"idNumber": "XEXX010101HNEXXXA4"
},
"payerAccount": {
"accountType": "BANK",
"accountNumber": "012180001234567891",
"accountName": "Juan Perez Lopez"
},
"remark": "optional"
}'响应示例:
{
"code": 200,
"message": "OK",
"traceId": "trace-uuid-string",
"data": {
"orderId": "bco_8f3k2m9q1x7z4t6w",
"referenceNo": "merchant-order-0001",
"status": "AWAITING_PAYMENT",
"country": "MX",
"fiatCurrency": "MXN",
"fiatAmount": "954.77",
"fiatFee": "13.50",
"cryptoCurrency": "USDT",
"cryptoAmount": "50.000000",
"price": "18.8253",
"paymentInfo": {
"method": "SPEI",
"clabe": "706180000000000001",
"reference": "REF123456"
},
"payer": {
"name": "Juan Perez Lopez"
},
"expiresAt": "2026-11-01T06:15:00Z",
"createdAt": "2026-11-01T10:15:00+08:00",
"completedAt": null,
"failureReason": null
}
}注意事项:
- 付款人必须在
expiresAt之前,向paymentInfo.clabe转账fiatAmountMXN。 - 下单价格由渠道实时确定,可能与报价不同。以下单响应为准。
fiatAmount和cryptoAmount必须传且只传一个。- 按
fiatAmount下单时,到账 USDT 由渠道确认,记账金额以响应中的cryptoAmount为准。渠道确认前,cryptoAmount可能为空。 paymentInfo为空时,表示渠道收款还没确认。用同一Idempotency-Key重试下单,或稍后查单。- 渠道拒绝时,订单置为
FAILED。用同一Idempotency-Key重放会返回该FAILED订单。 - 付款人 KYC 只用于转发给渠道。Stabo 不保存,也不在响应中返回证件号和联系方式。
- 付款人的收款账号必须已开通,见开通收款账号。未开通时,下单返回「收款账号开通中」,不建单。
查询订单
curl -X GET "https://api.test.stabofx.com/openapi/v1/collections/on-ramp/orders/bco_8f3k2m9q1x7z4t6w" \
-H "Authorization: Bearer {accessToken}"响应结构与创建订单的响应相同。
注意事项:
- 只能查询本商户的 On-Ramp 订单。其他订单返回「订单不存在」。
- 建议以 Webhook 为主、查单为辅。轮询时建议间隔 30 秒以上,到达终态后停止。
- Webhook 与查单结果不一致时,以查单结果为准。
订单状态
| 状态 | 说明 | 终态 |
|---|---|---|
AWAITING_PAYMENT | 等待付款人付款,或已付款等待记账 | 否 |
COMPLETED | 已完成。USDT 已记入商户钱包 | 是 |
FAILED | 失败、取消或超时 | 是 |
付款人与收款账号
- 每个付款人有一个专属收款 CLABE。商户用
payerId标识付款人。 - 同一商户的同一
payerId,总是对应同一个 CLABE。 payerId由商户生成,1~64 位,只允许字母、数字、_、-。payerId不得使用邮箱、手机号、证件号等个人信息。- 请在付款人注册或绑定时,调用开通收款账号接口提前开户。开通需要几分钟,状态变为
ACTIVE后才能下单。 - 下单时收款账号还没开通,Stabo 会自动发起开户,下单返回「收款账号开通中」,不建单。这只是兜底,不要依赖它,否则付款人要在付款时等待开通。
幂等性
下单接口必须带 Idempotency-Key,最长 128 字符,建议用 UUID。
- 同一商户内,
Idempotency-Key已存在时,返回原订单,不新建订单。 - 重放时以首次请求的订单为准,不使用新请求体。
Idempotency-Key永久有效,不会过期后重新可用。- 每笔新订单使用新的
Idempotency-Key。 - 以下情况,用同一
Idempotency-Key重试:请求超时、网络中断、返回「收款账号开通中」。 - 以下情况,用新的
Idempotency-Key重新下单:订单FAILED。
通用规则见通用约定。
数据格式差异
On-Ramp 的金额精度与其他产品不同。
| 类型 | 格式 | 示例 |
|---|---|---|
| 金额 | 十进制字符串。MXN 保留 2 位(四舍五入)。USDT 保留 6 位(向下截断) | "954.77"、"50.000000" |
| 汇率 | 十进制字符串,表示 1 USDT 对应的 MXN | "18.8253" |
| 时间 | ISO 8601,带时区偏移。不同字段的偏移可能不同(如 Z 或 +08:00),请按偏移解析 | 2026-11-01T10:15:00+08:00 |
| 国家 | ISO 3166-1 alpha-2 | MX |
请求中的金额字段可以传数字或字符串。建议传字符串,避免浮点精度问题。
业务错误说明
错误响应格式见错误码。请以 HTTP 状态码判断成功与否,body 中的 code 不一定与 HTTP 状态码相同。
业务错误返回 HTTP 400,响应体 code 为 500。响应示例:
{
"code": 500,
"message": "The payer receive account is being opened. Please retry later with the same Idempotency-Key",
"traceId": "trace-uuid-string",
"data": {
"errorCode": "onramp.receive_account.pending"
}
}| HTTP 状态 | 场景 |
|---|---|
| 200 | 成功 |
| 400 | 请求失败,包括参数校验失败和业务错误。响应体 code 为 500。参数校验失败:message 列出不合法的字段,例如 cryptoAmount must be greater than 0,data 为空。业务错误:data.errorCode 为错误码,见下表 |
| 401 | Token 无效或过期 |
| 403 | 无权访问 |
| 500 | 系统异常。保留 traceId 联系 Stabo。下单接口可用同一 Idempotency-Key 重试 |
联系 Stabo 排查问题时,请提供 traceId。
请按 data.errorCode 区分业务错误。message 只用于展示和排查,内容可能调整,不要用于程序判断。
| 错误 | errorCode | message(英文) | 处理方式 |
|---|---|---|---|
| 功能未开通 | onramp.disabled | On-ramp is not enabled | 联系 Stabo 开通 |
| 参数不合法 | onramp.request.invalid | The on-ramp request is missing required fields or has an invalid format | 检查请求参数,见下方说明 |
| 缺少幂等键 | error.idempotent.key.missing | Idempotency-Key header [Idempotency-Key] is required | 下单请求加上 Idempotency-Key 请求头 |
| 收款账号开通中 | onramp.receive_account.pending | The payer receive account is being opened. Please retry later with the same Idempotency-Key | 收款账号还没开通。用查询收款账号接口查询,状态变为 ACTIVE 后,用同一 Idempotency-Key 重试下单 |
| 收款账号不存在 | onramp.receive_account.not_found | The payer receive account does not exist | 先调用开通收款账号接口开户 |
| 收款账号开通失败 | onramp.receive_account.failed | The payer receive account could not be opened. Please contact operations | 联系 Stabo |
| 渠道拒绝 | onramp.provider.rejected | The provider rejected the request: {原因} | 订单已置为 FAILED。检查付款人信息后,用新的 Idempotency-Key 重新下单 |
| 订单不存在 | onramp.order.not_found | On-ramp order not found | 检查 orderId |
| 其他错误 | 其他值 | — | 保留 traceId 联系 Stabo。下单接口可用同一 Idempotency-Key 重试 |
返回「参数不合法」的常见原因:
country、fiatCurrency、cryptoCurrency不是MX、MXN、USDT。- 报价请求没有
fiatAmount,或同时传了cryptoAmount。 - 下单请求同时传了
fiatAmount和cryptoAmount,或两个都没传。 - 下单的
Idempotency-Key已被该商户的其他收款业务使用。
Webhook 事件
订单进入终态时,Stabo 向商户配置的 Webhook 地址推送事件。
事件类型
| 事件类型 | 触发时机 |
|---|---|
onramp.order.completed | 订单完成,USDT 已记入商户钱包。订单状态为 COMPLETED |
onramp.order.failed | 订单失败、取消或付款超时。订单状态为 FAILED |
通知机制
通知机制、请求头和签名验证与其他产品的 Webhook 相同,见 Webhook。
- 请求方式:HTTPS POST,
application/json。 - 请求头:
Webhook-Event-Id(事件唯一 ID)、Webhook-Event-Type(事件类型)、Webhook-Signature(签名,格式t=timestamp,v1=signature)。 - 签名:HMAC-SHA256,待签名字符串为
{Webhook-Event-Id}.{t}.{原始请求体}。商户必须验签。 - 重试:响应不是 2xx 时,按 1 分钟、5 分钟、30 分钟、2 小时、6 小时重试。
- 超时:30 秒。建议先返回 2xx,再异步处理。
事件对象结构
data.object 为订单对象,字段与创建订单的响应 data 相同。
{
"id": "evt_1234567890",
"object": "event",
"type": "onramp.order.completed",
"created": 1762151528,
"data": {
"object": {
"orderId": "bco_8f3k2m9q1x7z4t6w",
"referenceNo": "merchant-order-0001",
"status": "COMPLETED",
"country": "MX",
"fiatCurrency": "MXN",
"fiatAmount": "954.77",
"fiatFee": "13.50",
"cryptoCurrency": "USDT",
"cryptoAmount": "50.000000",
"price": "18.8253",
"paymentInfo": {
"method": "SPEI",
"clabe": "706180000000000001",
"reference": "REF123456"
},
"payer": {
"name": "Juan Perez Lopez"
},
"expiresAt": "2026-11-01T06:15:00Z",
"createdAt": "2026-11-01T10:15:00+08:00",
"completedAt": "2026-11-01T10:32:08+08:00",
"failureReason": null
}
}
}注意事项
- 用
Webhook-Event-Id去重。同一事件可能因重试而重复送达。 onramp.order.failed中,failureReason为失败原因,completedAt为空。- 订单在渠道确认前就失败时,
fiatAmount、cryptoAmount、price、paymentInfo可能为空。 - 订单取消或超时后,付款人仍完成付款时,订单会变为
COMPLETED。商户会先后收到onramp.order.failed和onramp.order.completed。请以最新事件和查单结果为准。
常见问题
错误与支持
通用错误口径见错误码。其他问题见常见问题。如需帮助,可通过 Stabo 客户经理或技术支持渠道联系,并提供 traceId。