一个 API,一套托管流程
CryptoPayIn 按您选定的计价币种为订单定价,锁定经过验证的法币/USD 与加密货币/USD 快照,分配专属收款地址,并通过自有区块链节点监听付款。内部记账、手续费与余额始终以 USD 计算。您的后端会立即收到结账 URL,随后再收到已签名的生命周期事件。
这是一个生产环境 API。没有沙盒前缀。每次成功创建都会分配真实的链上地址。进行端到端测试时请使用小额的受支持币种金额,并将密钥保存在您的服务器端。
接入流程一览
在控制台 -> 开发者 中生成一次密钥。
通过 POST 提交订单币种、金额与所选资产。
将客户引导至返回的托管 URL。
验证 HMAC 签名,并以幂等方式更新您的订单。
创建您的第一笔付款
在商户控制台生成一个 API 密钥,将密钥保存在环境变量中,然后从您的后端创建付款。示例使用 ETH,因此无需选择代币网络即可测试。
curl --request POST https://cryptopayin.com/v1/payments \
--header "Authorization: Bearer $CPI_SECRET_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: order_1042" \
--data '{
"amount": 49.99,
"currency": "USD",
"asset": "ETH",
"order_ref": "order_1042",
"redirect_url": "https://shop.example/orders/1042/paid"
}'
const response = await fetch("https://cryptopayin.com/v1/payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.CPI_SECRET_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "order_1042"
},
body: JSON.stringify({
amount: 49.99, currency: "USD", asset: "ETH",
order_ref: "order_1042",
redirect_url: "https://shop.example/orders/1042/paid"
})
});
if (!response.ok) throw new Error(await response.text());
const payment = await response.json();
$payload = json_encode([
'amount' => 49.99, 'currency' => 'USD', 'asset' => 'ETH',
'order_ref' => 'order_1042',
'redirect_url' => 'https://shop.example/orders/1042/paid',
]);
$ch = curl_init('https://cryptopayin.com/v1/payments');
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CPI_SECRET_KEY'),
'Content-Type: application/json',
'Idempotency-Key: order_1042',
],
]);
$payment = json_decode(curl_exec($ch), true, flags: JSON_THROW_ON_ERROR);
import os, requests
response = requests.post(
"https://cryptopayin.com/v1/payments",
headers={
"Authorization": f"Bearer {os.environ['CPI_SECRET_KEY']}",
"Idempotency-Key": "order_1042",
},
json={
"amount": 49.99, "currency": "USD", "asset": "ETH",
"order_ref": "order_1042",
"redirect_url": "https://shop.example/orders/1042/paid",
}, timeout=15,
)
response.raise_for_status()
payment = response.json()使用响应数据
将付款 id 与您的订单一并保存,然后将客户重定向至 checkout_url。请勿自行计算加密货币金额或收款地址。
{
"id": "P-9F27C1E4KD",
"object": "payment",
"status": "created",
"amount": 49.99,
"amount_decimal": "49.99",
"amount_minor": 4999,
"currency": "USD",
"currency_minor_units": 2,
"amount_usd": 49.99,
"amount_usd_cents": 4999,
"fx_rate_usd": "1.000000000000",
"fx_source": "fixed:USD",
"fx_observed_at": "2026-07-17T13:00:00+00:00",
"fx_discrepancy_bps": 0,
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0",
"deposit_address": "0x71b8c3d4700000000000000000000000000084e2",
"exchange_rate": "3600.00000000",
"exchange_rate_currency": "USD",
"exchange_rate_source": "median:cb,cg,cl",
"exchange_rate_source_count": 3,
"exchange_rate_observed_at": "2026-07-17T13:00:00+00:00",
"exchange_rate_discrepancy_bps": 12,
"confirmations": 0,
"confirmations_required": 12,
"order_ref": "order_1042",
"checkout_url": "https://cryptopayin.com/i/P-9F27C1E4KD",
"expires_at": "2026-07-17T13:30:00+00:00",
"created_at": "2026-07-17T13:00:00+00:00",
"completed_at": null
}身份验证
每个 API 请求都在 HTTP Bearer 请求头中使用密钥。密钥以 csk_live_ 开头。配套的 cpk_live_ 值是用于控制台的公开标识符,不得用作 Bearer 凭证。
Authorization: Bearer csk_live_...所有接口原始密钥仅在创建时返回一次。CryptoPayIn 存储的是密码哈希加带索引的 SHA-256 查找值,绝不存储明文密钥。
可为每个应用或环境创建独立密钥,并单独撤销。每个账户最多可持有 50 个有效密钥。
切勿将 csk_live_ 值放入浏览器 JavaScript、移动应用二进制文件、公开代码仓库或结账页面中。
Webhook 端点可以是账户级别的,也可以绑定到某个 API 密钥,从而实现接入之间的隔离。
缺失、格式错误、已撤销或未知的密钥都会返回 401 unauthorized。被暂停或已关闭的商户账户也会以相同方式被拒绝。有效密钥若超出其被授予的权限范围使用,则返回 403 insufficient_scope。
幂等性
每次创建付款时都应发送唯一的 Idempotency-Key。如果提交后连接中断,请使用相同的密钥重试相同的 JSON:CryptoPayIn 会返回原始付款,而不会分配另一个地址。
| 情形 | 结果 | HTTP |
|---|---|---|
| 首次使用 | 创建并返回一笔新付款。 | 201 |
| 相同密钥 + 相同 JSON | 返回带有 Idempotent-Replayed: true 的现有付款。 | 200 |
| 相同密钥 + 不同 JSON | 以 idempotency_conflict 拒绝该请求。 | 409 |
密钥的作用域限定于该 API 凭证内,可包含 1 到 128 个字母、数字、点、下划线、冒号或短横线。使用持久的订单 UUID 是不错的选择。同一机制也保护提现操作,因此重试的提现请求绝不会导致资金被转移两次。
API 参考
该 API 涵盖付款、支付链接、店铺、产品、余额与提现。响应通过 HTTPS 以 UTF-8 JSON 格式返回;任何创建或更新操作都需要 Content-Type: application/json。写操作受调用密钥的权限限制。我们有意不提供浏览器 CORS 工作流:调用应始终在您的后端进行。
/v1/assets查询可用资产/v1/currencies查询可用法币计价币种/v1/payments创建付款/v1/payments列出并筛选付款/v1/payments/{id}获取付款版本 1 可能会新增向后兼容的字段与接口。若发生破坏性的接口变更,将启用新的基础路径,而不会悄然更改 /v1。
列出资产
/v1/assets需要 Bearer 身份验证请将此接口作为结账可选项的权威数据源。它会返回已启用的目录条目、当前经过独立核验的汇率、最低 USD 等值金额,以及节点与行情源是否就绪。当节点正在同步或价格无法核实时,某条目仍可能以 available: false 状态保留在列表中。
curl https://cryptopayin.com/v1/assets \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"data": [{
"asset": "USDT",
"network": "TRC20",
"type": "token",
"decimals": 6,
"minimum_amount": 1,
"currency": "USD",
"base_confirmations": 19,
"available": true,
"rate_usd": "1.00000000",
"rate_source": "median:cb,cg,cl",
"rate_source_count": 3,
"rate_discrepancy_bps": 4,
"rate_status": "healthy",
"rate_updated_at": "2026-07-17T13:00:00+00:00"
}]
}目录与网络标识符
| 资产 | 网络值 | 简写 | 基础确认数 |
|---|---|---|---|
| BTC | mainnet | BTC | 2 |
| ETH | mainnet | ETH | 6 |
| USDT | TRC20 / ERC20 | USDT.TRC20 | 19 / 6 |
| USDC | ERC20 | USDC.ERC20 | 6 |
| DAI | ERC20 | DAI | 6 |
| SHIB | ERC20 | SHIB | 6 |
| PEPE | ERC20 | PEPE | 6 |
| LTC | mainnet | LTC | 6 |
| TRX | mainnet | TRX | 19 |
| DOGE | mainnet | DOGE | 20 |
| XMR | mainnet | XMR | 10 |
| SOL | mainnet | SOL | 32 |
可用性是动态变化的。请勿将上表硬编码为实时白名单。对于像 USDT 这样存在多个网络的代码,请显式发送 network,或使用 ASSET.NETWORK 简写。
列出法币币种
/v1/currencies需要 Bearer 身份验证返回已启用的计价币种、其 ISO 精度以及当前 USD 换算状态。只应展示带有 available: true 的行。USD 是内在基准币种;其他所有币种都需要实时最新报价与独立参考核验。minimum_amount 会将已启用资产中配置的最低下限换算为该币种金额;所选资产可能要求更高的金额,因此请务必同时读取 GET /v1/assets。
curl https://cryptopayin.com/v1/currencies \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"accounting_currency": "USD",
"data": [{
"currency": "EUR",
"name": "Euro",
"symbol": "€",
"minor_units": 2,
"available": true,
"minimum_amount": "0.86",
"rate_usd": "1.160000000000",
"rate_source": "coinbase+ecb",
"rate_source_count": 2,
"rate_discrepancy_bps": 18,
"rate_updated_at": "2026-07-17T13:00:00+00:00",
"rate_reference_at": "2026-07-16T00:00:00+00:00"
}]
}为保持向后兼容,POST /v1/payments 上省略币种仍表示 USD。零小数位币种(如 JPY)拒绝接受小数金额。请将目录中的最低金额与汇率视为实时数据,切勿硬编码为常量。
创建付款
/v1/payments每个密钥每分钟 120 次请求以请求的计价币种创建发票,锁定经过核验的最新法币/USD 与加密货币/USD 快照,计算精确的加密货币金额,并绑定专属的链上收款地址。
请求体
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| amount | 数字或十进制字符串 | 必填 | 以 currency 表示的数值,精度遵循该币种的 ISO 标准。其锁定的 USD 等值不得超过 $1,000,000.00;同时也适用各资产的最低金额限制。 |
| currency | 字符串 | 可选 | 来自 GET /v1/currencies 的已启用三字母币种代码。默认为 USD。 |
| asset | 字符串 | 必填 | 代码,如 ETH,或简写,如 USDT.TRC20。 |
| network | 字符串 | 视情况而定 | 当某代码存在于多个网络时为必填。例如:ERC20。 |
| order_ref | 字符串 | 可选 | 您的订单标识符,最多 128 个字符。会在 API 响应与事件中返回。 |
| customer_email | 字符串 | 可选 | 有效的电子邮箱地址,最多 190 个字符。随商户付款记录一并存储。 |
| redirect_url | 字符串 | 可选 | HTTPS URL,最多 255 个字符,在结账成功后提供。 |
响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
| id | 字符串 | 以 P- 开头的稳定付款标识符。 |
| status | 字符串 | 当前生命周期状态。 |
| amount / amount_decimal / amount_minor | 数字 / 字符串 / 整数 | 以便捷数值、精确十进制与 ISO 最小单位三种形式表示的请求计价数值。 |
| currency / currency_minor_units | 字符串 / 整数 | 锁定的计价币种及其精度。 |
| amount_usd / amount_usd_cents | 数字 / 整数 | 不可变的内部 USD 记账数值。 |
| fx_rate_usd / fx_source / fx_observed_at | 十进制字符串 / 字符串 / ISO 8601 | 锁定的每计价单位 USD 汇率快照及其审计元数据。 |
| asset / network | 字符串 | 已解析的链上资产。 |
| crypto_amount | 十进制字符串 | 客户必须发送的精确金额。切勿将加密货币小数值解析为二进制浮点数。 |
| crypto_received | 十进制字符串 | 当前在收款地址观察到的总金额。 |
| deposit_address | 字符串 | 为此笔付款分配的专属地址。 |
| exchange_rate | 十进制字符串 | 用于计算 crypto_amount 的锁定加密货币/USD 汇率;该字段沿用其在 v1 中的原始含义。 |
| exchange_rate_source / exchange_rate_observed_at | 字符串 / ISO 8601 | 不可变的加密货币汇率审计快照。 |
| confirmations | 整数 | 当前网络确认数。 |
| confirmations_required | 整数 | 此笔付款所需的确认数阈值。较高的 USD 金额档位可能需要更多确认数。 |
| checkout_url | URL | 展示给客户的托管发票页面。 |
| expires_at | ISO 8601 | 未付款发票的截止时间。 |
| completed_at | ISO 8601 / null | 完成后的最终结算时间。 |
两项实时汇率在创建前都会经过新鲜度、来源数量与偏离度校验。若校验失败,创建操作将返回错误,而不会使用过期汇率。加密货币金额会按对应资产的实用精度向上取整,因此舍入永远不会让商户少收。
列出付款
/v1/payments每个密钥每分钟 240 次请求为已认证的商户账户返回最新的付款,最新的排在最前。请使用游标分页进行对账,并使用精确筛选条件定位订单,而无需遍历完整历史。
查询参数
| 参数 | 默认值 | 说明 |
|---|---|---|
| limit | 20 | 分页大小,范围为 1 到 100。 |
| starting_after | — | 上一页返回的 next_cursor 中的付款 ID。 |
| status | — | 精确的生命周期状态,例如 pending、completed 或 expired。 |
| order_ref | — | 精确的商户订单标识,最多 128 个字符。 |
curl "https://cryptopayin.com/v1/payments?status=completed&limit=20" \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"data": [{
"id": "P-9F27C1E4KD",
"object": "payment",
"status": "completed",
"amount": 49.99,
"currency": "USD",
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0.01388612",
"order_ref": "order_1042",
"confirmations": 12,
"confirmations_required": 12,
"completed_at": "2026-07-17T13:12:42+00:00"
}],
"has_more": true,
"next_cursor": "P-9F27C1E4KD"
}当 has_more 为 true 时,请原样将 next_cursor 作为 starting_after 传递。未知或重复的数组风格查询参数会被拒绝,而不是被忽略。
获取付款
/v1/payments/{id}每个密钥每分钟 240 次请求返回与创建时相同的付款对象,并附带最新的状态、已收金额、交易哈希与确认数。密钥只能获取其所属商户账户下的付款。
curl https://cryptopayin.com/v1/payments/P-9F27C1E4KD \
--header "Authorization: Bearer $CPI_SECRET_KEY"常规订单更新应由 webhook 驱动。获取接口可用于超时后的对账、事件核验、渲染后端状态页面,或修复遗漏的投递。
付款生命周期
请始终以 API 返回的状态为准。切勿仅凭浏览器重定向或客户声称已付款就判断交易已完成。
| 状态 | 含义 | 商户操作 |
|---|---|---|
| created | 发票与地址已分配;尚未检测到任何入账。 | 展示托管结账页面。 |
| pending | 等待可用的链上付款。 | 保持订单处于开放状态。 |
| underpaid | 到账金额低于商户设定的容差范围。 | 请客户支付页面显示的差额。 |
| confirming | 已检测到足额资金;等待确认。 | 尚不应履约发货。 |
| completed | 已达到所需金额与确认数。 | 仅履约发货一次。 |
| overpaid | 确认金额超出预期。 | 正常履约发货,并核对多付部分。 |
| expired | 在到期前未检测到符合条件的付款。 | 创建一笔新的付款。 |
| failed | 地址分配或处理失败。 | 记录错误并创建新的付款。 |
链上转账不可逆,且 CryptoPayIn 不提供退款机制——已确认的付款即为最终结果。任何自愿性退款需由您与客户在平台之外自行协商处理。
托管结账
每笔 API 付款都会附带一个响应式 checkout_url。页面会展示商户信息、请求的计价金额、相关情况下锁定的 USD 等值金额、精确的加密货币金额、收款地址、二维码、网络提示、倒计时以及实时确认进度。
在发票有效期内,客户看到的 crypto_amount 与 API 返回的完全一致。
付款人无需创建 CryptoPayIn 账户,也无需提供任何凭证。
页面会安全地轮询付款状态,依次经历等待、确认到完成的过程。
成功后会提供一个 HTTPS redirect_url;但它并不能作为付款凭证。
请将履约逻辑保留在您的后端。浏览器跳转可能被中止、重复触发或伪造;只有经过验证的 webhook 或已认证的 GET 请求才能证明付款状态。
权限 & 作用域
每个 API 密钥都拥有一组固定的权限,这些权限在您于 控制台 → 开发者 中创建密钥时选定。每个接口在执行任何操作前都会先检查密钥的作用域;超出密钥授权范围的调用会返回 403 insufficient_scope,并附带一个标明缺失权限的 X-Required-Scope 请求头。作用域仅在创建时设定一次,之后无法扩大 — 如需更多权限,请签发新密钥。在作用域功能上线之前创建的密钥,将完整保留其原有能力:payments:read 与 payments:write。
| 作用域 | 授予权限 | 接口 |
|---|---|---|
payments:read | 列出并获取付款 | GET /v1/payments, GET /v1/payments/{id} |
payments:write | 创建托管付款 | POST /v1/payments |
links:read | 列出并获取支付链接 | GET /v1/links, GET /v1/links/{id} |
links:write | 创建、编辑、暂停并删除支付链接 | POST/PATCH/DELETE /v1/links |
shops:read | 列出并获取店铺及其产品 | GET /v1/shops, GET .../products |
shops:write | 创建并编辑店铺、产品与规格 | POST/PATCH/DELETE /v1/shops 及产品接口 |
balance:read | 读取加密货币余额与 USD 估值 | GET /v1/balance |
payouts:read | 列出并获取提现记录 | GET /v1/payouts, GET /v1/payouts/{id} |
payouts:write | 发起链上提现 | POST /v1/payouts |
payouts:write 会在链上转移资金,且不可撤销。请仅将该权限授予您完全信任的密钥,将这些密钥保存在服务器端,并为每个自动化流程配置专用密钥。GET /v1/account 会返回调用密钥的作用域以及您账户的各项限制。
支付链接
可重复使用的托管链接,客户可多次付款。链接拥有与控制台链接构建器相同的定价、资产、交付与结账问题逻辑 — API 只是驱动它的另一种方式。每个账户最多可持有 50 条支付链接。
/v1/linkslinks:read/v1/linkslinks:write/v1/links/{id}links:read/v1/links/{id}links:write/v1/links/{id}links:write请求体
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| title | 字符串 | 必填 | 3–120 个字符。 |
| description | 字符串 | 可选 | 最多 2,000 个字符,显示在结账页面上。 |
| template | 字符串 | 可选 | 结账主题:signature(默认)、midnight、atelier、horizon、compact 或 ledger。 |
| public_label | 字符串 | 可选 | 向买家展示的公开卖家名称(2–80 个字符)。不得为账户 ID。 |
| amount_type | 字符串 | 可选 | fixed(默认)或 open(客户在最小/最大值范围内自选金额)。 |
| currency | 字符串 | 可选 | 来自 GET /v1/currencies 的计价币种。默认为您账户的币种。 |
| amount | 数字或字符串 | 视情况而定 | fixed 时必填。以 currency 表示,精度遵循其 ISO 标准。 |
| min / max | 数字或字符串 | 视情况而定 | open 链接的取值范围。max 可为 0/省略,表示无上限。 |
| accepted_assets | 字符串数组 | 可选 | 资产代码,例如 ["BTC","USDT.TRC20"]。省略则表示支持所有可用资产。 |
| max_uses | 整数 | 可选 | 已完成付款次数上限。0 表示不限次数。 |
| expires_at | ISO 8601 | 可选 | 至少提前 5 分钟,最长 12 个月。使用 UTC 时间。 |
| delivery_type | 字符串 | 可选 | none、text、url 或 keys — 付款完成后交付的数字商品。 |
| delivery_text / delivery_url | 字符串 | 视情况而定 | 对应交付类型的内容(≤50,000 字符)或 https URL。 |
| delivery_keys | 字符串数组 | 视情况而定 | 用于 keys 交付方式,每个元素对应一个密钥。最多 10,000 个,每个 ≤500 字符。 |
| checkout_fields | 数组 | 可选 | 最多 5 个对象 {label, type, required};type 可为 text、email、textarea 或 number。 |
| success_message / redirect_url | 字符串 | 可选 | 付款完成后的提示信息(≤500 字符)以及 https 重定向地址。 |
| status | 字符串 | 可选 | 仅限 PATCH:active 或 paused。 |
curl -X POST https://cryptopayin.com/v1/links \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Pro license",
"amount": 49.99,
"currency": "EUR",
"accepted_assets": ["BTC", "ETH", "USDT.TRC20"],
"delivery_type": "keys",
"delivery_keys": ["ABC-1", "ABC-2", "ABC-3"]
}'{
"id": "PL-N5PKTYB7",
"object": "payment_link",
"url": "https://cryptopaylink.co/pay/PL-N5PKTYB7",
"status": "active",
"title": "Pro license",
"amount_type": "fixed",
"currency": "EUR",
"amount": 49.99,
"amount_decimal": "49.99",
"accepted_assets": [{"asset":"BTC","network":"mainnet"},{"asset":"ETH","network":"mainnet"},{"asset":"USDT","network":"TRC20"}],
"uses": {"started": 0, "completed": 0, "in_flight": 0},
"delivery": {"type": "keys", "keys_available": 3, "keys_total": 3},
"expires_at": null,
"created_at": "2026-07-19T19:00:00+00:00"
}PATCH 是一次局部更新:只需发送您要修改的字段,其余字段(包括尚未售出的授权密钥)将保持不变。对于 keys 链接,发送 delivery_keys 会替换未售出密钥池;已交付的密钥永远不会被改动。删除已有付款记录的链接会被隐式拒绝,以保持其历史记录完整。
智能体结账
每一条有效的支付链接同时也是一个机器可读的结账入口:AI 智能体或任意脚本无需浏览器即可发现该链接、创建发票并读取交付内容——也无需任何 API 密钥,因为这些是链接域名下面向买家的公开接口,而非商户接口。完整协议与实操示例参见 cryptopayin.com/agents。
https://cryptopaylink.co/pay/{link}.json公开 · 发现返回状态、定价、可接受的资产,以及创建发票调用所需的精确输入契约(必填字段、配送信息结构、规格)。
https://cryptopaylink.co/pay/{link}/invoice公开 · 支持 Idempotency-Key通过与托管页面相同的核心逻辑、定价快照与防滥用限制创建发票,并返回收款地址、精确的加密货币金额、钱包 URI 与收据 URL。随后智能体可使用其掌控的任意钱包完成链上付款。
https://cryptopaylink.co/pay/{link}/receipt?p={payment}公开 · 每 5–10 秒轮询一次实时状态与确认数;一旦付款完成,响应中将包含交付内容——您的文本内容、私有 URL,或为该笔付款保留的授权密钥——以及您设置的成功提示信息与重定向 URL。
店铺遵循相同协议
店铺前台在自己的域名下暴露相同的流程:先是带有实时库存的商品目录,再通过单次调用完成购物车校验、库存预留并返回发票。
https://shopycrypto.com/s/{shop}.json公开 · 商品目录https://shopycrypto.com/s/{shop}/order公开 · 购物车 → 发票,支持 Idempotency-Keyhttps://shopycrypto.com/s/{shop}/o/{order}/receipt?p={payment}公开 · 每 5–10 秒轮询一次卖家控制项
智能体结账默认开启,费用同样是固定的 1%。您可以在 控制台 → 设置 → 通用 → AI & 智能体结账 中按账户整体关闭该功能:关闭后,链接与店铺上的机器接口将返回 403 agents_disabled,而面向人类的结账页面仍照常工作。智能体创建的付款不带任何特殊标记——在您的控制台、webhook 与导出数据中,它们都是普通付款。
店铺
一个托管店面,将产品汇集在一个带品牌的页面下。每个账户最多可持有 10 个店铺。产品通过下方的嵌套产品接口进行管理。
/v1/shopsshops:read/v1/shopsshops:write/v1/shops/{id}shops:read/v1/shops/{id}shops:write/v1/shops/{id}shops:write请求体
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| name | 字符串 | 必填 | 2–80 个字符。 |
| tagline | 字符串 | 可选 | 最多 160 个字符。 |
| theme | 字符串 | 可选 | light(默认)或 dark。 |
| accent | 字符串 | 可选 | 取自店铺配色方案的十六进制强调色,作为 accent_palette 在 GET /v1/shops 中返回。 |
| accepted_assets | 字符串数组 | 可选 | 店铺产品的默认资产,例如 ["BTC","LTC","XMR"]。修改后会应用到所有产品。 |
| status | 字符串 | 可选 | 仅限 PATCH:active 或 paused。 |
因政策原因被 CryptoPayIn 停用的店铺无法通过 API 重新激活或删除,将返回 admin_disabled(403)。删除店铺会移除其下的产品;已有的付款记录不受影响。
产品 & 规格
产品归属于某个店铺。每个店铺最多可持有 50 个产品。产品可以是数字商品(即时交付)或实物商品(需设置配送国家),并且最多可暴露 30 种由 1–3 个选项组组合而成的规格。
/v1/shops/{shop}/productsshops:read/v1/shops/{shop}/productsshops:write/v1/shops/{shop}/products/{id}shops:read/v1/shops/{shop}/products/{id}shops:write/v1/shops/{shop}/products/{id}shops:write请求体
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| title | 字符串 | 必填 | 3–120 个字符。 |
| description / blurb | 字符串 | 可选 | 完整描述,以及一行 ≤200 字符的店铺卡片摘要。 |
| emoji | 字符串 | 可选 | 显示在产品卡片上的单个表情符号。 |
| featured | 布尔值 | 可选 | 每个店铺最多可设置一个精选产品。 |
| product_type | 字符串 | 可选 | digital(默认)或 physical。 |
| shipping_countries | 字符串数组 | 视情况而定 | 仅限实物商品:ISO 代码,例如 ["FR","BE"],或使用 ["*"] 表示全球配送。 |
| amount_type / currency / amount / min / max | 混合类型 | 视情况而定 | 基础定价,规则与支付链接相同。实物商品必须为 fixed。 |
| max_uses | 整数 | 可选 | 总销售数量上限(0 表示不限)。 |
| delivery_type + delivery_text/url/keys | 混合类型 | 可选 | 基础产品的数字交付方式,结构与支付链接相同。 |
| variant_options | 数组 | 可选 | 1–3 个 {name, values[]} 选项组,每组包含 2–10 个取值。组合总数不得超过 30 种。 |
| variants | 数组 | 视情况而定 | 每种组合对应一个对象(见下文)。当存在 variant_options 时为必填且必须穷举所有组合。 |
| status | 字符串 | 可选 | 仅限 PATCH:active 或 paused。 |
规格对象
| 字段 | 类型 | 说明 |
|---|---|---|
| options | 字符串数组 | 每个选项组取一个值,按选项组顺序排列,例如 ["Pro","Lifetime"]。 |
| price | 数字或字符串 | 该规格的价格,使用产品所用币种。 |
| stock | 整数或 null | 剩余库存数量,null 表示不限量。 |
| delivery_type + delivery_text/url/keys | 混合类型 | 可选的按规格数字交付覆盖设置(默认 inherit)。密钥在整个产品范围内必须唯一。 |
curl -X POST https://cryptopayin.com/v1/shops/SH-JYRK8TFJ/products \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Software license",
"amount": 30,
"currency": "USD",
"variant_options": [
{"name": "Edition", "values": ["Standard", "Pro"]},
{"name": "Term", "values": ["1 year", "Lifetime"]}
],
"variants": [
{"options": ["Standard","1 year"], "price": 30, "delivery_type": "keys", "delivery_keys": ["S1Y-1"]},
{"options": ["Standard","Lifetime"], "price": 79, "stock": 10, "delivery_type": "keys", "delivery_keys": ["SLT-1"]},
{"options": ["Pro","1 year"], "price": 59, "delivery_type": "keys", "delivery_keys": ["P1Y-1"]},
{"options": ["Pro","Lifetime"], "price": 149, "stock": 5, "delivery_type": "keys", "delivery_keys": ["PLT-1"]}
]
}'PATCH 会保留现有订单与已交付的密钥。若需调整价格或库存,请重新发送对应的 variants 数组;被省略的组合,如果已有订单则会被暂停,否则将被移除。一个产品的基础规格与各变体合计最多可持有 10,000 个有效授权密钥,且每个密钥在该产品内必须唯一。
余额
/v1/balancebalance:read返回按资产划分的已结算加密货币余额,并附上尽力而为的 USD 估值以及提现时收取的网络费用。内部记账始终以 USD 为准;余额来自已完成付款、扣除商户手续费后的净额累积。
{
"object": "list",
"accounting_currency": "USD",
"minimum_payout_usd": 25,
"data": [{
"asset": "USDT",
"network": "TRC20",
"amount": "99.099",
"usd_estimate": 99.02,
"payout_network_fee": "2.445463"
}]
}当经过核验的实时汇率暂时不可用时,usd_estimate 会为 null;但底层余额本身依然精确。这些数值可用于决定是否提现,但不应作为最终记账依据。
提现
将已结算的加密货币转出至外部钱包。由于提现操作不可撤销,此接口会强制执行与控制台相同的每一项安全保障:面向该资产的有效目的地址、经过核验的实时汇率、账户最低限额、包含网络费用在内的充足余额,以及在账户已启用双因素验证时的二次确认。
/v1/payoutspayouts:read/v1/payoutspayouts:write · 每个密钥每分钟 30 次/v1/payouts/{id}payouts:read请求体
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| asset | 字符串 | 必填 | 代码或简写,例如 LTC 或 USDT.TRC20。 |
| network | 字符串 | 视情况而定 | 当该代码存在于多个网络时为必填。 |
| amount | 数字或字符串 | 必填 | 要发送的金额,不含网络费用,按该资产的精度表示。其 USD 等值必须达到账户最低限额。 |
| address | 字符串 | 必填 | 目的地址,会针对该资产所在链进行校验。 |
| note | 字符串 | 可选 | 您自己的备注信息,最多 255 个字符。 |
| totp_code | 字符串 | 视情况而定 | 当前的 6 位验证码或恢复代码。账户启用双因素验证时为必填。 |
curl -X POST https://cryptopayin.com/v1/payouts \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: withdraw-2026-07-19-01" \
-d '{
"asset": "USDT.TRC20",
"amount": "50",
"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"note": "weekly settlement"
}'{
"id": "W-EM64ZCJB",
"object": "payout",
"status": "requested",
"asset": "USDT",
"network": "TRC20",
"amount": "50",
"fee": "2.445463",
"total_debited": "52.445463",
"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"txid": null,
"confirmations": 0,
"created_at": "2026-07-19T19:10:00+00:00"
}状态流转
| 状态 | 含义 |
|---|---|
requested | 已从您的余额中预留;等待运营审核或自动批准。 |
approved / processing | 已审核通过,正排队等待执行器广播。 |
sent | 已在链上广播;txid 字段已填充。 |
confirmed | 已达到所需确认数,为最终状态。 |
failed | 发送失败;failure_message 会说明原因,且余额将被退回。 |
cancelled | 在广播前被取消;预留的余额将被退回。 |
请发送 Idempotency-Key,以确保网络重试永远不会产生第二笔提现:相同密钥配合相同请求体会返回原始的提现记录(Idempotent-Replayed: true);相同密钥配合不同请求体会返回 409 idempotency_conflict。双因素验证码被特意排除在幂等指纹之外,以避免因验证码轮换而触发误判的冲突。预留操作会立即扣减您的余额;提现失败或被取消后,该余额将被退回。
账户
/v1/account任意有效密钥返回您的账户资料、调用密钥的作用域、您的平台手续费以及所有实时限制 — 适用于自适应配置的接入方案或上线前检查。
{
"object": "account",
"id": "MC67T3PHQZ",
"fee_bps": 100,
"fee_percent": 1,
"default_currency": "USD",
"two_factor_enabled": false,
"api_key": {"label": "production", "scopes": ["payments:read","payments:write"]},
"limits": {
"shops": {"used": 1, "max": 10},
"payment_links": {"used": 0, "max": 50},
"products_per_shop_max": 50,
"variant_combinations_per_product_max": 30,
"license_keys_per_product_max": 10000,
"active_api_keys_max": 50,
"checkout_fields_per_link_max": 5
},
"minimum_payout_usd": 25
}Webhook
在控制台 -> 开发者中最多可添加 10 个公开 HTTPS 端点。每个端点都会获得专属的 whsec_... 签名密钥,仅显示一次。端点可以监听整个账户,也可以绑定到某个特定的有效 API 密钥;绑定密钥的端点只会收到使用该密钥创建的付款事件。
解析前先验证
CryptoPayIn 使用端点密钥对原始请求体本身进行签名。版本 1 对 timestamp + "." + raw_body 进行签名。请在接受事件前拒绝过期的时间戳。
import crypto from "node:crypto";
const timestamp = req.headers["x-cpi-timestamp"];
const signature = req.headers["x-cpi-signature"];
const rawBody = req.rawBody; // Buffer captured before JSON parsing
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
throw new Error("stale webhook");
}
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.CPI_WEBHOOK_SECRET)
.update(Buffer.concat([Buffer.from(`${timestamp}.`), rawBody]))
.digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
if (!valid) throw new Error("invalid webhook signature");
$rawBody = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_CPI_TIMESTAMP'] ?? '';
$received = $_SERVER['HTTP_X_CPI_SIGNATURE'] ?? '';
if (!ctype_digit($timestamp) || abs(time() - (int)$timestamp) > 300) {
http_response_code(400); exit('stale webhook');
}
$expected = 'sha256=' . hash_hmac(
'sha256', $timestamp . '.' . $rawBody, getenv('CPI_WEBHOOK_SECRET')
);
if (!hash_equals($expected, $received)) {
http_response_code(401); exit('invalid signature');
}
$event = json_decode($rawBody, true, flags: JSON_THROW_ON_ERROR);
import hashlib, hmac, os, time
raw_body = request.get_data() # bytes, before JSON decoding
timestamp = request.headers.get("X-CPI-Timestamp", "")
received = request.headers.get("X-CPI-Signature", "")
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
raise ValueError("stale webhook")
signed = timestamp.encode() + b"." + raw_body
expected = "sha256=" + hmac.new(
os.environ["CPI_WEBHOOK_SECRET"].encode(), signed, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, received):
raise ValueError("invalid signature")投递请求头
| 请求头 | 示例 | 用途 |
|---|---|---|
| Content-Type | application/json | UTF-8 JSON 请求体。 |
| X-CPI-Timestamp | 1784293200 | 包含在已签名消息中的 Unix 时间戳(秒)。 |
| X-CPI-Signature | sha256=... | 十六进制 HMAC-SHA256 值。 |
| X-CPI-Signature-Version | v1 | 签名方案版本。 |
| X-CPI-Event-Id | evt_a12b... | 稳定的逻辑事件 ID;重试时保持不变。 |
| X-CPI-Delivery-Id | 1842 | 稳定的端点投递记录 ID。 |
付款事件负载
{
"event_id": "evt_a12b34c56d78e90f12345678",
"event": "payment.completed",
"id": "P-9F27C1E4KD",
"status": "completed",
"order_ref": "order_1042",
"amount": 49.99,
"amount_decimal": "49.99",
"amount_minor": 4999,
"currency_minor_units": 2,
"currency": "USD",
"amount_usd": 49.99,
"amount_usd_cents": 4999,
"fx_rate_usd": "1.000000000000",
"fx_source": "fixed:USD",
"fx_observed_at": "2026-07-17T13:00:00Z",
"fx_discrepancy_bps": 0,
"exchange_rate": "3600.00000000",
"exchange_rate_currency": "USD",
"exchange_rate_source": "median:cb,cg,cl",
"exchange_rate_source_count": 3,
"exchange_rate_observed_at": "2026-07-17T13:00:00Z",
"exchange_rate_discrepancy_bps": 12,
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0.01388612",
"txid": "0x9d81...75af",
"confirmations": 12,
"confirmations_required": 12,
"deposit_address": "0x71b8c3d4700000000000000000000000000084e2",
"sent_at": "2026-07-17T13:12:42Z"
}重试与端点安全
HTTP 200-299 均视为投递成功。请将耗时操作放到异步处理,并尽快返回响应。
原始请求体与事件 ID 会被保留;失败后将分别在约 1 分钟、5 分钟、30 分钟、2 小时与 6 小时后重试。
不会跟随 3xx 响应。请直接注册最终的 HTTPS URL。
私有地址、环回地址、链路本地地址与保留 IP 均会被拦截;每个 DNS 解析结果都会被校验,且连接会被固定。
投递保证至少送达一次。请在履约前先以唯一约束记录 event_id,从而让您的处理逻辑具备幂等性。在核对意外事件时,请调用 API 获取对应对象。
事件参考
payment.completed预期金额已确认。payment.overpaid确认金额超出预期。payment.underpaid检测到入账金额低于容差范围。payment.expired未付款发票的有效期已结束。payment.failed付款创建或处理失败。payout.sent提现已在链上广播。payout.confirmed提现已达到所需确认数。payout.failed提现未能完成。webhook.test手动连通性测试。提现事件结构
{
"event_id": "evt_b98c76d54e32a10f87654321",
"event": "payout.sent",
"id": "W-8J2K7M4RQP",
"status": "sent",
"asset": "ETH",
"network": "mainnet",
"amount": "0.25",
"fee": "0.00081768",
"address": "0x84f2...9bc1",
"txid": "0xa1c4...07ee",
"confirmations": 0,
"note": "weekly treasury",
"sent_at": "2026-07-17T14:08:31Z"
}错误与速率限制
错误响应始终使用同一种 JSON 封装格式。请基于 error.type 进行分支处理;面向人类阅读的提示信息可能会在不改变版本号的情况下被改进。联系支持团队时,请引用 error.request_id 或对应的 X-Request-Id 响应头。
{
"error": {
"type": "ambiguous_asset",
"message": "specify network (e.g. USDT.ERC20 or USDT.TRC20)",
"request_id": "b942e21f8dca4b06b8672eb9"
}
}| HTTP | 常见类型 | 含义 |
|---|---|---|
| 400 | invalid_request, unknown_parameter | JSON、查询参数或幂等请求头格式有误。 |
| 401 | unauthorized | 凭证/账户缺失、无效或未激活。 |
| 403 | insufficient_scope, admin_disabled | 有效密钥缺少所需权限(参见 X-Required-Scope),或资源已被管理员锁定。 |
| 404 | not_found | 未知接口,或资源不属于该商户账户。 |
| 405 | method_not_allowed | 请使用 Allow 请求头中标明的方法。 |
| 409 | idempotency_conflict | 同一密钥搭配了不同的 JSON 重复使用。 |
| 413 | request_too_large | JSON 请求体超过 64 KiB。 |
| 415 | unsupported_media_type | POST 请求体未声明为 application/json。 |
| 422 | invalid, limit, invalid_amount, below_minimum, bad_address, 2fa_required, unsupported_asset | 请求格式正确,但未通过确定性校验,或触及资源上限。 |
| 429 | rate_limited | 请等待 Retry-After。 |
| 500 | server_error | 意外故障;可使用相同的幂等密钥安全重试。 |
| 503 | maintenance, temporarily_unavailable, asset_unavailable, no_rate, price_stale, fiat_rate_unavailable, fiat_rate_stale, derive_failed | 平台、节点、行情或地址分配出现暂时性故障。系统不会以过期汇率进行替代。 |
当前限制
| 范围 | 限制 | 窗口 |
|---|---|---|
| Nginx 单 IP 安全上限 | 10 次请求/秒,突发上限 30 | 持续生效 |
| 未认证 IP 上限 | 300 次请求 | 60 秒 |
| POST /v1/payments, links, shops, products | 每个 API 密钥 120 次请求 | 60 秒 |
| POST /v1/payouts | 每个 API 密钥 30 次请求 | 60 秒 |
| GET 接口 | 每个 API 密钥 240 次请求 | 60 秒 |
账户限制
| 资源 | 上限 |
|---|---|
| 每账户店铺数 | 10 |
| 每账户支付链接数 | 50 |
| 每店铺产品数 | 50 |
| 每产品规格组合数 | 30 |
| 每产品/链接授权密钥数 | 10,000 |
| 每链接结账问题数 | 5 |
| 每账户有效 API 密钥数 | 50 |
可通过 GET /v1/account 查看您当前用量相对于这些上限的实时情况。
成功但受应用层限流影响的响应会携带 X-RateLimit-Limit、X-RateLimit-Remaining 与 X-RateLimit-Reset。对于 429、500 与 503 状态,请采用指数退避加抖动的策略重试。对于 POST 请求,请始终复用原始的 Idempotency-Key 与完全相同的 JSON。
接入安全
在运行时加载密钥;切勿记录完整密钥值,也不得将其提交到源码仓库。
浏览器或移动端客户端无法安全地持有商户密钥。
在解析 JSON 之前,先检查时间戳的新鲜度,并使用恒定时间比较验证签名。
以事务方式记录已处理的事件/订单,确保重试不会导致重复发货。
当事件出乎预期,或与您的本地状态不一致时,请调用接口获取该付款的最新状态。
创建替换密钥,部署上线,确认流量正常后再删除旧密钥。
账户访问由一个不可找回的 16 位商户密钥控制,并可选择性地通过 TOTP 加以保护。请以对待钱包凭证同等的谨慎程度,妥善保管商户访问密钥与 API 密钥。
上线检查清单
请勿在多个服务之间复用开发者的个人密钥。
使用 GET /v1/assets 与 GET /v1/currencies;只渲染同时存在且 available: true 的条目。
妥善保存一次性显示的签名密钥;验证时间戳与签名,然后对稳定的事件 ID 去重。
模拟一次重复重试,确认只存在一个付款 ID。
在法币汇率过期、资产不可用、确认延迟等各种非正常路径下,您的订单状态都应保持安全一致。
将您的订单与 API 付款状态、webhook 日志以及商户账本进行核对。
准备好开始接入了吗?
几秒钟内即可开户,生成密钥,并将本文档留在手边随时参考。