icpay
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseICPay Skill
ICPay 技能文档
Instruction manual for working with the ICPay project: SDK, widget, payment links, accounts, webhooks, relay payments, X402 v2, refunds, split payments, email notifications, demo site, and integrations (WordPress, WooCommerce, Shopify).
ICPay项目操作手册:涵盖SDK、Widget、支付链接、账户、Webhook、中继支付、X402 v2、退款、分账支付、邮件通知、演示站点以及各类集成(WordPress、WooCommerce、Shopify)。
Feature overview
功能概述
- Relay payments — Per-chain recipient addresses (EVM, IC, Solana); funds forwarded to your specified addresses; optional relay fee in account settings.
- X402 v2 — HTTP 402 “Payment Required” flow for IC, EVM, and Solana; sign authorization, ICPay facilitator settles; card/onramp-friendly.
- Currency — Payment links have ; user/account profile can set default fiat for payment (USD, EUR, etc.).
fiatCurrencyId - QR and mobile — WalletConnect QR for desktop; deep links for mobile browsers so users can pay with mobile phone wallet apps.
- Wallet adapters — EVM: MetaMask, Coinbase, Brave, Rabby, OKX, WalletConnect. Solana: Phantom, Backpack. IC: Plug, Internet Identity (II), Oisy, NFID. Configurable enable/disable per adapter.
- Split payments — Optional: multiple merchants share revenue via split rules (target account + percentage in basis points).
- Refunds — Refund completed payments; execute-refunds worker; webhook ; email notification for refund completed.
payment.refunded - Email notifications — Payment completed and refund completed emails to account; configurable templates; process-notifications worker.
- Webhooks — Merchant endpoint receives payment/refund events; HMAC-SHA256 verification.
- demo.icpay.org — Live demo/playground for building and testing custom widgets (all components, configurable options).
- betterstripe.com — Sandbox environment: same features as icpay.org but on testnets (Solana devnet, Base Sepolia, Ark network testnet, and other testnets) for developers.
- Filter tokens/chains — Widget config: ,
tokenShortcodes,chainShortcodesto show only specific tokens or chains.chainTypes
- 中继支付 — 支持各链收款地址(EVM、IC、Solana);资金将转至您指定的地址;可在账户设置中配置可选的中继手续费。
- X402 v2 — 针对IC、EVM和Solana的HTTP 402“需要支付”流程;签署授权后,由ICPay服务商完成结算;支持卡片/入金通道。
- 货币设置 — 支付链接包含;用户/账户资料可设置支付默认法币(美元、欧元等)。
fiatCurrencyId - 二维码与移动端支持 — 桌面端显示WalletConnect二维码;移动端浏览器提供深度链接,用户可通过手机钱包应用完成支付。
- 钱包适配器 — EVM链:MetaMask、Coinbase、Brave、Rabby、OKX、WalletConnect。Solana链:Phantom、Backpack。IC链:Plug、Internet Identity (II)、Oisy、NFID。可配置每个适配器的启用/禁用状态。
- 分账支付 — 可选功能:多个商户通过分账规则共享收益(目标账户+基点百分比)。
- 退款 — 可对已完成的支付发起退款;由execute-refunds worker处理;退款完成时触发Webhook 并发送邮件通知。
payment.refunded - 邮件通知 — 账户将收到支付完成和退款完成的邮件;支持配置模板;由process-notifications worker处理。
- Webhook — 商户端点接收支付/退款事件;采用HMAC-SHA256验证。
- demo.icpay.org — 用于构建和测试自定义Widget的在线演示/沙箱环境(包含所有组件和可配置选项)。
- betterstripe.com — 沙箱环境:功能与icpay.org完全一致,但基于测试网(Solana devnet、Base Sepolia、Ark网络测试网及其他测试网),供开发者使用。
- 筛选代币/链 — Widget配置项:、
tokenShortcodes、chainShortcodes,用于仅显示特定代币或链。chainTypes
Public Project layout
公开项目结构
- icpay-sdk — : typed client for browser/server; create payments, wallet helpers, events.
@ic-pay/icpay-sdk - icpay-widget — Web Components + React wrappers: pay-button, amount-input, tip-jar, paywall, etc.
- icpay-docs — Documentation site (docs.icpay.org); MDX under .
src/app/
Use pnpm for install/build across the repo. Main technical reference: repo root .
technical.md- icpay-sdk — :适用于浏览器/服务器的类型化客户端;支持创建支付、钱包辅助功能、事件监听。
@ic-pay/icpay-sdk - icpay-widget — Web组件 + React封装:包含支付按钮、金额输入框、小费罐、付费墙等组件。
- icpay-docs — 文档站点(docs.icpay.org);基于下的MDX文件构建。
src/app/
在整个仓库中使用pnpm进行安装/构建。主要技术参考文档:仓库根目录下的。
technical.mdKeys and auth
密钥与认证
- Publishable key (/
pk_live_*): safe for client; used by widget and public SDK calls.pk_test_* - Secret key: server-only; required for protected API (payments list, account info, webhook verification). Never expose in browser.
- Auth: for both keys. API base:
Authorization: Bearer <key>(or envhttps://api.icpay.org).API_URL
- 可发布密钥 (/
pk_live_*):可安全用于客户端;供Widget和公开SDK调用使用。pk_test_* - 密钥:仅用于服务器端;受保护的API(支付列表、账户信息、Webhook验证)需要此密钥。绝不能在浏览器中暴露。
- 认证方式:两种密钥均使用请求头。API基础地址:
Authorization: Bearer <key>(或通过环境变量https://api.icpay.org配置)。API_URL
SDK (@ic-pay/icpay-sdk
)
@ic-pay/icpay-sdkSDK (@ic-pay/icpay-sdk
)
@ic-pay/icpay-sdkInstall: .
pnpm add @ic-pay/icpay-sdkBrowser (publishable key):
ts
import { Icpay } from '@ic-pay/icpay-sdk';
const icpay = new Icpay({
publishableKey: 'pk_live_xxx',
apiUrl: 'https://api.icpay.org',
debug: false,
});Create payment (USD): Prefer (e.g. , ). For / you must provide wallet context: + (IC) or + connected address (EVM).
tokenShortcodeic_icpbase_usdccreatePaymentUsdcreatePaymentactorProviderconnectedWalletevmProviderts
const tx = await icpay.createPaymentUsd({
amountUsd: 5,
metadata: { orderId: 'ORDER-123' },
});X402 v2 (IC, EVM, Solana): Use for sign-and-settle flows; SDK builds EIP-712 (EVM) or Solana message/transaction, sends to ICPay facilitator, returns terminal status. Fallback to regular when X402 not available. When you have an existing payment intent (e.g. from a pay link), pass or in config or in the request so the SDK sends it to the x402 intent endpoint and the API reuses that intent instead of creating a second one.
createPaymentX402Usd(request)createPaymentUsdpaymentIntentIdpaymentIntentServer (secret key): Use for : , , , , , etc.
icpay.protected.*getPaymentByIdlistPaymentsgetPaymentHistorygetDetailedAccountInfogetVerifiedLedgersPrivatePrefer SDK methods over raw fetch. Handle errors via ; subscribe to SDK events for lifecycle (see SDK events below).
IcpayError安装:。
pnpm add @ic-pay/icpay-sdk浏览器端(使用可发布密钥):
ts
import { Icpay } from '@ic-pay/icpay-sdk';
const icpay = new Icpay({
publishableKey: 'pk_live_xxx',
apiUrl: 'https://api.icpay.org',
debug: false,
});创建美元支付订单: 优先使用(例如、)。调用 / 时,必须提供钱包上下文:IC链需 + ,EVM链需 + 已连接地址。
tokenShortcodeic_icpbase_usdccreatePaymentUsdcreatePaymentactorProviderconnectedWalletevmProviderts
const tx = await icpay.createPaymentUsd({
amountUsd: 5,
metadata: { orderId: 'ORDER-123' },
});X402 v2(IC、EVM、Solana): 使用实现签署-结算流程;SDK构建EIP-712(EVM)或Solana消息/交易,发送至ICPay服务商,返回终端状态。当X402不可用时,回退至常规方法。若已有支付意向(例如来自支付链接),请在配置或请求中传入**或**,SDK会将其发送至x402意向端点,API将复用该意向而非创建新的意向。
createPaymentX402Usd(request)createPaymentUsdpaymentIntentIdpaymentIntent服务器端(使用密钥): 用于相关方法:、、、、等。
icpay.protected.*getPaymentByIdlistPaymentsgetPaymentHistorygetDetailedAccountInfogetVerifiedLedgersPrivate优先使用SDK方法而非原生fetch请求。通过处理错误;订阅SDK事件以监听生命周期(详见下方SDK事件)。
IcpayErrorWidget (@ic-pay/icpay-widget
)
@ic-pay/icpay-widgetWidget (@ic-pay/icpay-widget
)
@ic-pay/icpay-widgetInstall: .
pnpm add @ic-pay/icpay-widget @ic-pay/icpay-sdkComponents: , , , , , , , .
icpay-pay-buttonicpay-amount-inputicpay-tip-jaricpay-premium-contenticpay-article-paywallicpay-coffee-shopicpay-donation-thermometericpay-progress-barHTML (bundler):
html
<script type="module"> import '@ic-pay/icpay-widget'; </script>
<icpay-pay-button
id="pay"
publishableKey="YOUR_PK"
tokenShortcodes="base_usdc"
amountUsd="5"
></icpay-pay-button>Set on the element (object with , , , etc.). Listen for , on the element or .
configpublishableKeytokenShortcodeamountUsdicpay-payicpay-errorwindowReact: Use wrappers from (e.g. , ) with prop and / .
@ic-pay/icpay-widget/reactIcpayPayButtonIcpayTipJarconfigonSuccessonErrorHosted embed (no bundler): Script from ; then .
https://widget.icpay.org/v{VERSION}/embed.min.jsICPay.create('pay-button', { publishableKey, amountUsd, defaultSymbol, ... }).mount('#el')Filter tokens/chains: In config set (e.g. ), (e.g. ), or (e.g. ) to restrict which tokens or chains are shown in the widget.
tokenShortcodes['ic_icp','base_usdc']chainShortcodes['ic','base']chainTypes['ic','evm','sol']Relay payments: Set in config; funds are relayed to those addresses. Optional relay fee is set per account in dashboard (Settings → ICPay Fees → Relay Fee).
recipientAddresses: { evm?: string, ic?: string, sol?: string }QR and deep links: Payment links support (default true) and ; WalletConnect shows QR on desktop and deep links on mobile so users can open wallet apps.
showWalletConnectQrshowBaseWalletQrHandle success/error via events, not console. Theming: CSS variables on or component (e.g. , ). See widget-reference.md for options, wallet adapters, and component-specific config.
:root--icpay-primary--icpay-surface安装:。
pnpm add @ic-pay/icpay-widget @ic-pay/icpay-sdk组件列表: 、、、、、、、。
icpay-pay-buttonicpay-amount-inputicpay-tip-jaricpay-premium-contenticpay-article-paywallicpay-coffee-shopicpay-donation-thermometericpay-progress-barHTML(使用打包工具):
html
<script type="module"> import '@ic-pay/icpay-widget'; </script>
<icpay-pay-button
id="pay"
publishableKey="YOUR_PK"
tokenShortcodes="base_usdc"
amountUsd="5"
></icpay-pay-button>可在元素上设置对象(包含、、等参数)。监听元素或上的、事件。
configpublishableKeytokenShortcodeamountUsdwindowicpay-payicpay-errorReact环境: 使用中的封装组件(例如、),传入属性及 / 回调。
@ic-pay/icpay-widget/reactIcpayPayButtonIcpayTipJarconfigonSuccessonError托管嵌入(无需打包工具): 引入脚本;然后调用。
https://widget.icpay.org/v{VERSION}/embed.min.jsICPay.create('pay-button', { publishableKey, amountUsd, defaultSymbol, ... }).mount('#el')筛选代币/链: 在配置中设置(例如)、(例如)或(例如),以限制Widget中显示的代币或链。
tokenShortcodes['ic_icp','base_usdc']chainShortcodes['ic','base']chainTypes['ic','evm','sol']中继支付: 在配置中设置;资金将转至这些地址。可在仪表盘的账户设置中配置可选的中继手续费(Settings → ICPay Fees → Relay Fee)。
recipientAddresses: { evm?: string, ic?: string, sol?: string }二维码与深度链接: 支付链接支持(默认开启)和;WalletConnect在桌面端显示二维码,在移动端提供深度链接,方便用户打开钱包应用。
showWalletConnectQrshowBaseWalletQr通过事件处理成功/错误,而非依赖控制台输出。主题定制:在或组件上使用CSS变量(例如、)。详见widget-reference.md获取配置选项、钱包适配器及组件专属配置说明。
:root--icpay-primary--icpay-surfaceSDK events (icpay-sdk)
SDK事件(icpay-sdk)
The SDK emits named events so agents and apps can react to payment lifecycle and method outcomes without polling. Subscribe with ; unsubscribe with . Events can be disabled via config: (default is ). In browsers the SDK uses /; in Node it uses an in-memory emitter.
icpay.on(type, (detail) => { ... })icpay.off(type, listener){ enableEvents: false }trueEventTargetCustomEventSDK会触发命名事件,以便代理和应用无需轮询即可响应支付生命周期和方法执行结果。使用订阅事件;使用取消订阅。可通过配置禁用事件(默认开启)。浏览器环境下SDK使用/;Node环境下使用内存事件发射器。
icpay.on(type, (detail) => { ... })icpay.off(type, listener){ enableEvents: false }EventTargetCustomEventSuccess event (crucial for apps)
成功事件(对应用至关重要)
icpay-sdk-transaction-completed- When it fires: After the payment is confirmed (on-chain and/or backend reconciliation). Emitted from ,
createPayment,createPaymentUsd, and from polling/notify flows when status becomescreatePaymentX402Usd.completed - Payload (detail): A TransactionResponse-shaped object:
- (number) — Canister/backend transaction id.
transactionId - .
status: 'completed' - (string) — Amount in smallest unit.
amount - (string).
recipientCanister - (Date).
timestamp - ,
description?(e.g. yourmetadata?).orderId - — When present, includes
payment?,paymentId,paymentIntentId,status,canisterTxId(fromtransactionId).PublicNotifyResponse
- What to do: Use or
detail.paymentIntentIdanddetail.payment?.paymentIntentIdfor idempotency. Fulfill the order, persist success, show a success UI. Do not rely only on the widget callback; listening to this event ensures you capture completion even if the user navigates or the widget is unmounted.detail.payment?.paymentId
Example (SDK instance):
ts
const unbind = icpay.on('icpay-sdk-transaction-completed', (detail) => {
const paymentIntentId = detail.payment?.paymentIntentId ?? detail.paymentIntentId;
const paymentId = detail.payment?.paymentId;
// Fulfill order, update DB, show success (idempotent by paymentId/paymentIntentId)
});
// later: unbind();Example (window — e.g. when using the widget, which forwards SDK events to ):
windowts
function handleSuccess(e: CustomEvent) {
const detail = e.detail ?? e;
const paymentIntentId = detail.payment?.paymentIntentId ?? detail.paymentIntentId;
const paymentId = detail.payment?.paymentId;
// Fulfill order, update DB, show success (idempotent by paymentId/paymentIntentId)
}
window.addEventListener('icpay-sdk-transaction-completed', handleSuccess as EventListener);
// later: window.removeEventListener('icpay-sdk-transaction-completed', handleSuccess as EventListener);icpay-sdk-transaction-completed- 触发时机: 支付确认后(链上确认及/或后端对账完成)。在、
createPayment、createPaymentUsd方法执行后,或轮询/通知流程中状态变为createPaymentX402Usd时触发。completed - 负载(detail): 符合TransactionResponse格式的对象:
- (数字) — 容器/后端交易ID。
transactionId - 。
status: 'completed' - (字符串) — 最小单位的金额。
amount - (字符串)。
recipientCanister - (Date类型)。
timestamp - 、
description?(例如自定义的metadata?)。orderId
- 处理逻辑: 使用或
detail.paymentIntentId及detail.payment?.paymentIntentId实现幂等性。完成订单、更新数据库、显示成功界面。不要仅依赖Widget回调;监听此事件可确保即使用户导航离开或Widget被卸载,仍能捕获支付完成状态。detail.payment?.paymentId
示例(SDK实例):
ts
const unbind = icpay.on('icpay-sdk-transaction-completed', (detail) => {
const paymentIntentId = detail.payment?.paymentIntentId ?? detail.paymentIntentId;
const paymentId = detail.payment?.paymentId;
// 完成订单、更新数据库、显示成功界面(通过paymentId/paymentIntentId实现幂等)
});
// 后续取消订阅:unbind();示例(window对象 — 例如使用Widget时,Widget会将SDK事件转发至window):
ts
function handleSuccess(e: CustomEvent) {
const detail = e.detail ?? e;
const paymentIntentId = detail.payment?.paymentIntentId ?? detail.paymentIntentId;
const paymentId = detail.payment?.paymentId;
// 完成订单、更新数据库、显示成功界面(通过paymentId/paymentIntentId实现幂等)
}
window.addEventListener('icpay-sdk-transaction-completed', handleSuccess as EventListener);
// 后续取消订阅:window.removeEventListener('icpay-sdk-transaction-completed', handleSuccess as EventListener);Transaction lifecycle events
交易生命周期事件
- — Payment intent created; user still has to send funds. Detail:
icpay-sdk-transaction-created. Not emitted for onramp-only flows.{ paymentIntentId, amount, ledgerCanisterId, expectedSenderPrincipal?, accountCanisterId? } - — Status changed (e.g. pending → processing). Detail: same shape as TransactionResponse (or with extra
icpay-sdk-transaction-updated,status,requestedAmountwhen relevant). Use for progress UI.paidAmount - — Payment failed (rejected, timeout, or backend marked failed). Detail: TransactionResponse-like; check
icpay-sdk-transaction-failedand optionalstatus: 'failed'for messaging.reason - — Paid amount does not match requested amount. Detail: includes
icpay-sdk-transaction-mismatched,requestedAmountplus TransactionResponse fields. Followed bypaidAmountwithicpay-sdk-transaction-updated. Use to prompt user to correct or refund/partial-fulfill per business rules.status: 'mismatched'
- — 支付意向创建完成;用户仍需完成资金划转。负载:
icpay-sdk-transaction-created。仅入金流程不会触发此事件。{ paymentIntentId, amount, ledgerCanisterId, expectedSenderPrincipal?, accountCanisterId? } - — 状态变更时触发(例如pending → processing)。负载格式与TransactionResponse一致(或包含额外的
icpay-sdk-transaction-updated、status、requestedAmount字段)。用于显示进度界面。paidAmount - — 支付失败时触发(被拒绝、超时或后端标记为失败)。负载格式类似TransactionResponse;检查
icpay-sdk-transaction-failed及可选的status: 'failed'字段以生成提示信息。reason - — 支付金额与请求金额不符时触发。负载包含
icpay-sdk-transaction-mismatched、requestedAmount及TransactionResponse字段。随后会触发**paidAmount**事件,状态为icpay-sdk-transaction-updated。用于提示用户修正或根据业务规则发起退款/部分履约。mismatched
Method lifecycle events (generic)
方法生命周期事件(通用)
Every SDK method that uses the internal emitter fires:
- — Method invoked. Detail:
icpay-sdk-method-start(e.g.{ name: string, args?: any },name: 'createPayment').args: { request: { amountUsd, ... } } - — Method finished successfully. Detail:
icpay-sdk-method-success(e.g.{ name: string, result?: any },name: 'createPayment'is the return value or a summary).result - — Method threw. Detail:
icpay-sdk-method-error.{ name: string, error: any }
Method names include: , , , , , , , , , , , , , , , , , , , , , , , , , , , , and protected API method names when using .
notifyPaymentgetAccountInfoquoteAtxpRequestpayAtxpRequestexecuteAtxpRequestgetVerifiedLedgersgetChainsgetLedgerCanisterIdBySymboltriggerTransactionSyncshowWalletModalconnectWalletgetWalletProvidersisWalletProviderAvailablegetAccountAddressgetLedgerBalancecreatePaymentcreatePaymentUsdcreatePaymentX402UsdpollTransactionStatusnotifyLedgerTransactiongetTransactionStatusPublicsendFundsToLedgergetTransactionByFiltergetExternalWalletBalancesgetSingleLedgerBalancecalculateTokenAmountFromUSDgetLedgerInfogetAllLedgersWithPricesicpay.protected.*For payment success, prefer over for //, because the transaction-completed event carries the final payment state and is emitted at the right semantic time.
icpay-sdk-transaction-completedicpay-sdk-method-successcreatePaymentcreatePaymentUsdcreatePaymentX402Usd所有使用内部事件发射器的SDK方法都会触发以下事件:
- — 方法被调用时触发。负载:
icpay-sdk-method-start(例如{ name: string, args?: any },name: 'createPayment')。args: { request: { amountUsd, ... } } - — 方法执行成功时触发。负载:
icpay-sdk-method-success(例如{ name: string, result?: any },name: 'createPayment'为返回值或摘要信息)。result - — 方法执行抛出错误时触发。负载:
icpay-sdk-method-error。{ name: string, error: any }
方法名称包括:、、、、、、、、、、、、、、、、、、、、、、、、、、、,以及使用时的受保护API方法名称。
notifyPaymentgetAccountInfoquoteAtxpRequestpayAtxpRequestexecuteAtxpRequestgetVerifiedLedgersgetChainsgetLedgerCanisterIdBySymboltriggerTransactionSyncshowWalletModalconnectWalletgetWalletProvidersisWalletProviderAvailablegetAccountAddressgetLedgerBalancecreatePaymentcreatePaymentUsdcreatePaymentX402UsdpollTransactionStatusnotifyLedgerTransactiongetTransactionStatusPublicsendFundsToLedgergetTransactionByFiltergetExternalWalletBalancesgetSingleLedgerBalancecalculateTokenAmountFromUSDgetLedgerInfogetAllLedgersWithPricesicpay.protected.*对于支付成功事件,优先使用****而非//对应的事件,因为交易完成事件携带最终支付状态,并在语义正确的时机触发。
icpay-sdk-transaction-completedcreatePaymentcreatePaymentUsdcreatePaymentX402Usdicpay-sdk-method-successError event
错误事件
- — Any SDK error (including from method-error). Detail: an IcpayError-like object (
icpay-sdk-error,code,message). Use for logging and user-facing error messages.details?
- — 任何SDK错误触发(包含方法错误)。负载:类似IcpayError的对象(包含
icpay-sdk-error、code、message字段)。用于日志记录和用户友好的错误提示。details?
Optional / internal
可选/内部事件
- — Emitted when an onramp-only flow creates an intent (e.g. Transak). Detail:
icpay-sdk-onramp-intent-created. Useful for UI that shows “redirect to onramp” state.{ paymentIntentId, amountUsd?, onramp? }
- — 仅入金流程创建意向时触发(例如Transak)。负载:
icpay-sdk-onramp-intent-created。用于显示“跳转至入金通道”状态的界面。{ paymentIntentId, amountUsd?, onramp? }
Summary table
事件汇总表
| Event | When | Detail (main fields) |
|---|---|---|
| icpay-sdk-transaction-completed | Payment succeeded | TransactionResponse + |
| icpay-sdk-transaction-created | Intent created | paymentIntentId, amount, ledgerCanisterId, … |
| icpay-sdk-transaction-updated | Status changed | TransactionResponse (+ status/requestedAmount/paidAmount when relevant) |
| icpay-sdk-transaction-failed | Payment failed | TransactionResponse, optional reason |
| icpay-sdk-transaction-mismatched | Amount mismatch | TransactionResponse + requestedAmount, paidAmount |
| icpay-sdk-method-start | Method called | name, args |
| icpay-sdk-method-success | Method resolved | name, result |
| icpay-sdk-method-error | Method rejected | name, error |
| icpay-sdk-error | Any SDK error | IcpayError-like |
| icpay-sdk-onramp-intent-created | Onramp intent created | paymentIntentId, amountUsd?, onramp? |
| 事件 | 触发时机 | 负载(核心字段) |
|---|---|---|
| icpay-sdk-transaction-completed | 支付成功 | TransactionResponse + |
| icpay-sdk-transaction-created | 意向创建完成 | paymentIntentId, amount, ledgerCanisterId, … |
| icpay-sdk-transaction-updated | 状态变更 | TransactionResponse (+ 相关的status/requestedAmount/paidAmount字段) |
| icpay-sdk-transaction-failed | 支付失败 | TransactionResponse, 可选reason字段 |
| icpay-sdk-transaction-mismatched | 金额不符 | TransactionResponse + requestedAmount, paidAmount |
| icpay-sdk-method-start | 方法调用 | name, args |
| icpay-sdk-method-success | 方法执行成功 | name, result |
| icpay-sdk-method-error | 方法执行出错 | name, error |
| icpay-sdk-error | 任何SDK错误 | 类似IcpayError的对象 |
| icpay-sdk-onramp-intent-created | 入金意向创建 | paymentIntentId, amountUsd?, onramp? |
Payment links
支付链接
Payment links are per-account entities with a unique shortcode. Public pay page: .
https://icpay.org/pay/<shortcode>- Create (user/dashboard): API ; DTO includes
PaymentLinksService.createForAccount(accountId, dto),name,description,amountUsd,collectEmail,requireEmail,widgetOptions, etc. Shortcode is generated (unique). User endpoints:showWalletConnectQrwith JWT (see Flow: I am an agent).POST /user/payment-links - Create (POS / publishable key): with publishable key in
POST /sdk/public/payment-links. Body: CreatePosPaymentLinkDto —Authorization: Bearer <pk_...>(required, min 0.01), optionalamountUsd,name,description(array; when exactly one, the payment intent is created with that token; otherwise intent has no token and user selects on pay page),tokenShortcodes(default false for POS),showWalletConnectQr(default true). Creates the link and an associated payment intent; response includesshowBaseWalletQrandshortcode. Use the pay page URLpaymentIntentId(optionallyhttps://icpay.org/pay/<shortcode>for pre-filled intent). POS-only: recipient addresses are not set on the link.?paymentIntentId=<id> - Public fetch: returns
GET /public/payment-links/:shortcode(link config + account publishableKey/branding). Used by{ link, account }pay page.icpay-web - Merchant UI: → Payment Links → create/edit; link to
icpay-webshown after create./pay/<shortcode>
Payment link entity: . Fields: , , (display currency for the link), collect/require for email, name, address, phone, quantity (min/max/default), (JSON), , , .
icpay-api/src/entities/payment-link.entity.tsamountUsdshortcodefiatCurrencyIdwidgetOptionsshowWalletConnectQrshowBaseWalletQrisActive支付链接是每个账户的专属实体,包含唯一的短代码。公开支付页面地址:。
https://icpay.org/pay/<shortcode>- 创建(用户/仪表盘): 调用API ;DTO包含
PaymentLinksService.createForAccount(accountId, dto)、name、description、amountUsd、collectEmail、requireEmail、widgetOptions等字段。短代码自动生成(唯一)。用户端点:携带JWT调用showWalletConnectQr(详见流程:我是代理)。POST /user/payment-links - 创建(POS / 可发布密钥): 携带可发布密钥()调用
Authorization: Bearer <pk_...>。请求体:CreatePosPaymentLinkDto — 必填POST /sdk/public/payment-links(最小值0.01),可选amountUsd、name、description(数组;若仅包含一个值,支付意向将使用该代币创建;否则意向无指定代币,用户需在支付页面选择)、tokenShortcodes(POS场景默认关闭)、showWalletConnectQr(默认开启)。创建链接及关联的支付意向;响应包含showBaseWalletQr和shortcode。使用支付页面地址paymentIntentId(可附加https://icpay.org/pay/<shortcode>预填充意向)。POS专属规则:链接上不设置收款地址。?paymentIntentId=<id> - 公开查询: 调用返回
GET /public/payment-links/:shortcode(链接配置 + 账户可发布密钥/品牌信息)。供{ link, account }支付页面使用。icpay-web - 商户界面: 在中进入Payment Links → 创建/编辑;创建完成后显示
icpay-web链接。/pay/<shortcode>
支付链接实体定义:。字段包括:、、(链接显示货币)、邮箱收集/必填设置、名称、地址、电话、数量(最小/最大/默认值)、(JSON格式)、、、。
icpay-api/src/entities/payment-link.entity.tsamountUsdshortcodefiatCurrencyIdwidgetOptionsshowWalletConnectQrshowBaseWalletQrisActivePayment intent: reusing by id (widget, SDK, X402)
支付意向:通过ID复用(Widget、SDK、X402)
When you already have a payment intent id (e.g. from a pay link or POS flow) but not the full intent object, pass so the SDK and API reuse that intent instead of creating a new one.
paymentIntentId- Widget: In pay-button config (or when creating the SDK via the widget), set when the full
paymentIntentIdobject is not loaded. The widget passes it into the SDK config; the SDK uses it inpaymentIntentand when calling the x402 intent endpoint.getOrResolvePaymentIntent - SDK config: You can pass (full object) or
paymentIntent(string). When only the id is set, the SDK fetches the intent by id viapaymentIntentIdand uses it forGET /sdk/public/payments/intents/:id,createPayment, and createPaymentX402Usd. This avoids creating a second intent when the user pays on a pay link (first intent created with the link, second avoided by passing the id).createPaymentUsd - X402 intent endpoint: When calling , the SDK includes
POST /sdk/public/payments/intents/x402in the request body when it has an existing intent (from config or request). The API reuses that intent whenpaymentIntentIdis present: it loads the intent, verifies it belongs to the account and is in a reusable state (body.paymentIntentIdorrequires_payment), mergesprocessinginto metadata, and returns that intent for the x402 response instead of creating a new one. Use this so a single payment intent is used end-to-end (e.g. pay link + x402 EVM flow) and metadata (e.g.icpay_x402: true) is preserved.icpayPaymentLink
若已有支付意向ID(例如来自支付链接或POS流程)但无完整意向对象,可传入****,SDK和API将复用该意向而非创建新的意向。
paymentIntentId- Widget: 在支付按钮配置中(或通过Widget创建SDK时),若未加载完整对象,可设置
paymentIntent。Widget会将其传入SDK配置;SDK会在paymentIntentId方法及调用x402意向端点时使用该ID。getOrResolvePaymentIntent - SDK配置: 可传入(完整对象)或**
paymentIntent(字符串)。若仅设置ID,SDK会通过paymentIntentId查询意向,并在GET /sdk/public/payments/intents/:id、createPayment和createPaymentX402Usd**方法中使用。避免用户在支付页面支付时创建第二个意向(第一个意向随链接创建,通过传入ID避免重复创建)。createPaymentUsd - X402意向端点: 调用时,若SDK已有现存意向(来自配置或请求),会在请求体中包含**
POST /sdk/public/payments/intents/x402。当请求体中存在paymentIntentId时,API会复用**该意向:加载意向、验证其归属账户及可复用状态(body.paymentIntentId或requires_payment)、将processing合并至元数据,并返回该意向用于x402响应,而非创建新意向。确保单个支付意向端到端复用(例如支付链接 + x402 EVM流程),并保留元数据(例如icpay_x402: true)。icpayPaymentLink
Accounts
账户
- User: Register via (firstName, lastName, email, password, etc.). Login:
POST /auth/register; JWT returned.POST /auth/login - Account (merchant): Created per user via with JWT; body:
POST /user-accounts(name, email, country, businessName, accountType, businessType). User can own multiple accounts; each account hasCreateAccountDtoand secret (managed by backend).publishableKey - Dashboard: : signup → create account → dashboard; create payment links, view payments, settings (including default fiat currency for the account). Switch account via auth/account context.
icpay-web
Currency: Payment links have ; account/user profile can set default fiat for display (e.g. USD, EUR). Used in widget as for amount display.
fiatCurrencyIdfiat_currencyAccount creation: → . Frontend: and .
icpay-api/src/accounts/accounts.service.tscreateAccount(userId, dto)icpay-web/src/app/account/create/page.tsxAccountsService.create()- 用户: 通过注册(需提供firstName、lastName、email、password等信息)。登录:调用
POST /auth/register;返回JWT。POST /auth/login - 账户(商户): 携带JWT调用为用户创建账户;请求体为
POST /user-accounts(包含name、email、country、businessName、accountType、businessType)。用户可拥有多个账户;每个账户拥有CreateAccountDto和密钥(由后端管理)。publishableKey - 仪表盘: 流程:注册 → 创建账户 → 仪表盘;可创建支付链接、查看支付记录、设置(包括账户默认法币)。通过认证/账户上下文切换账户。
icpay-web
货币设置: 支付链接包含;账户/用户资料可设置默认显示法币(例如美元、欧元)。在Widget中作为用于金额显示。
fiatCurrencyIdfiat_currency账户创建逻辑: → 。前端实现:及。
icpay-api/src/accounts/accounts.service.tscreateAccount(userId, dto)icpay-web/src/app/account/create/page.tsxAccountsService.create()Flow: I am an agent (fully programmatic via API)
流程:我是代理(完全通过API编程实现)
Use this when you are an AI agent that must create the user, verify email, log in, create an account, and generate API keys entirely via requests to the ICPay API. Base URL:
https://api.icpay.org-
Register the user
- Endpoint:
POST https://api.icpay.org/auth/register - Body (JSON): —
RegisterDto,firstName,lastName,email(min 8 chars),password(ISO8601),dateOfBirth,addressLine1(optional),addressLine2,city,stateOrProvince,postalCode(2-letter ISO),country(optional),phone(optional).nationality - Response: with
201.{ message: "Registration successful. Please check your email to verify your account." } - A verification email is sent. It contains text like "Please verify your email address to complete your registration" and a "Verify Email" link. The link is the web URL, e.g. . The JWT is in the query parameter
https://icpay.org/auth/verify-email?token=<JWT>.token
- Endpoint:
-
Activate the account (verify email)
- Get the token: From the verification email, take the "Verify Email" link URL and read the query parameter (the JWT).
token - Endpoint:
POST https://api.icpay.org/auth/verify-email - Body (JSON):
{ "token": "<JWT from the link>" } - Response: with
200. After this, the user's email is verified and they can log in.{ message: "..." }
- Get the token: From the verification email, take the "Verify Email" link URL and read the
-
Log in (start OTP)
- Endpoint:
POST https://api.icpay.org/auth/login - Body (JSON):
{ "email": "<email used in registration>", "password": "<password>" } - Response: with
200. No JWT yet. An email is sent to the user's email with a verification code, e.g. "icpay.org authentication email code" / "The verification code for icpay.org is: 313215". The agent must obtain this code (e.g. read from mail or have the user provide it).{ requires2fa: true, challengeId: "<sid>", user: { id, firstName, lastName, email, ... } }
- Endpoint:
-
Complete login (submit OTP code)
- Endpoint:
POST https://api.icpay.org/auth/verify-login-otp - Body (JSON):
{ "email": "<same email>", "code": "<6-digit code from email>" } - Response: with
200. Use{ access_token: "<JWT>", user: { ... } }as the Bearer token for all following requests.access_token
- Endpoint:
-
Use the Bearer token for all further requests
- Send header: on every request to the API.
Authorization: Bearer <access_token>
- Send header:
-
Create one account
- Endpoint:
POST https://api.icpay.org/user-accounts - Headers: ,
Authorization: Bearer <access_token>Content-Type: application/json - Body (JSON): —
CreateAccountDto,name, and optionallyemail(2-letter),country,accountType,businessName.businessType - Response: with the created account object; note
201(account ID).id
- Endpoint:
-
Generate API keys (publishable + secret)
- Endpoint:
POST https://api.icpay.org/user-accounts/:accountId/generate-secret-key - Headers:
Authorization: Bearer <access_token> - Body: none (or ).
{} - Response: with
200.{ secretKey: "sk_...", publicKey: "pk_..." } - Publishable key (): Safe to store in
pk_...(e.g..env) or use directly in client code; it is public.NEXT_PUBLIC_ICPAY_PK - Secret key (): Store only in
sk_...(e.g..env). Never embed in source code or commit to git; use only on the server.ICPAY_SECRET_KEY
- Endpoint:
-
Use in the app
- Publishable key: Use with icpay-widget to build any frontend that accepts crypto payments (pay button, tip jar, paywall, etc.).
- Secret key: Use with icpay-sdk on the server for protected operations (e.g. ,
icpay.protected.getPaymentById,listPayments) and to verify payment state. Alternatively (or in addition), register a webhook URL in the ICPay dashboard; verifygetDetailedAccountInfoand handleX-ICPay-Signatureandpayment.completedfor fulfillment.payment.refunded
-
Other API endpoints (all require) With the JWT from step 4, the agent can perform all account operations via the API without using icpay.org. Base URL:
Authorization: Bearer <access_token>. Sendhttps://api.icpay.orgwhere a body is used.Content-Type: application/jsonEmail code for sensitive actions: For payouts, split rules (create/update/delete/replace), the API requires an email verification code. First call(optional bodyPOST /user/security/email-challenge/start); the user receives an email with a code. Then include that code in the request body as{ reason?, metadata? }oremailSecurityCodewhen calling the endpoint below. Alternatively use the same code from the login OTP flow if still valid for the same user.securityCode-
User profile
- — Get current user profile.
GET /users/profile - — Update profile. Body:
PATCH /users/profile(optional:SelfUpdateUserDto,firstName,lastName,phone,dateOfBirth,avatarUrl,nationality{ line1, line2, city, stateOrProvince, postalCode, country },address). Email cannot be changed via this endpoint.fiatCurrencyId
-
Switch account
- — Body:
POST /auth/switch-account. Returns new token scoped to that account; use for subsequent requests if the user has multiple accounts.{ "accountId": "<uuid>" }
-
List user's accounts
- — List accounts the user belongs to.
GET /user-account-users/my-accounts - — List pending invitations.
GET /user-account-users/my-pending-invitations - — Invite a user to an account. Body:
POST /user-account-users/invite—CreateInvitationDto(string),accountId(string), optionalemail(e.g.role|"owner"|"admin", default"viewer"), optional"viewer"(string[]).permissionsis not accepted from the client; it is set server-side from the authenticated user (JWT).invitedBy - — Accept invitation.
POST /user-account-users/:id/accept - — Decline invitation.
POST /user-account-users/:id/decline - — List users for an account (must be member).
GET /user-account-users/account/:accountId
-
Account (user-accounts)
- — Update account (JWT: owner or admin of the account). Body:
PATCH /user-accounts/:id— all optional, only the following are intended for user/owner use (admin-only and system fields are not listed):UpdateAccountDto,name,email,country,accountType,businessName,businessType,isActive,isLive,taxId(object:businessProfile,name,url,mcc,supportEmail,supportPhone),supportUrl(object:capabilities,cardPayments,transfers),taxReporting(object:requirements,currentlyDue,eventuallyDue,pastDue),disabledReason,primaryDomain(object:branding,logoUrl,faviconUrl,primaryColor),secondaryColor,address,billingAddress,taxInfo(number, basis points),relayFeeBps.settings - — Regenerate API keys; returns
POST /user-accounts/:id/regenerate-secret-key(show secret once).{ secretKey, publicKey } - — Start phone change; body
POST /user-accounts/:id/phone-change/start.{ phone } - — Body
POST /user-accounts/:id/phone-change/verifyto confirm phone change.{ challengeId, code }
-
Payment links
- — List payment links for account.
GET /user/payment-links?accountId=<uuid> - — Get one payment link.
GET /user/payment-links/:id - — Create. Body:
POST /user/payment-links—CreatePaymentLinkDto,name,description, optionalamountUsd,fiatCurrencyId(or use queryaccountId), collect/require (email, name, address, phone, business, shipping), quantity (allow, default, min, max),?accountId=,maxRedemptions,widgetOptions,showWalletConnectQr,showBaseWalletQr. Shortcode is generated.isActive - — Update. Body:
PUT /user/payment-links/:id(same fields as create, partial).UpdatePaymentLinkDto - — Delete payment link.
DELETE /user/payment-links/:id - — List submissions for the link.
GET /user/payment-links/:id/submissions
-
Payments (list, get, refund)
- — List payments (with pagination).
GET /user/payments?accountId=<uuid> - — Payment summary for account.
GET /user/payments/summary - — Payment stats.
GET /user/payments/stats - — Get payment by ID.
GET /user/payments/:id - — Check if refund is allowed.
GET /user/payments/:id/refund-precheck - — Create a refund for the payment. No body required (refund is full). Refunds are processed by the execute-refunds worker; webhook
POST /user/payments/:id/refundis sent when done.payment.refunded
-
Payouts (require email code)
- — List payouts.
GET /user/payouts?accountId=<uuid> - — Create payout. Body:
POST /user/payouts,accountId(decimal string), optionalamount,ledgerId,ledgerCanisterId,accountCanisterId,toWalletAddress, andtoWalletSubaccountoremailSecurityCode(code from email). Only OWNER or admin with payouts permission.securityCode - — Execute a created payout.
POST /user/payouts/:id/execute
-
Webhook endpoints
- — List webhook endpoints.
GET /user/webhook-endpoints?accountId=<uuid> - — Get one endpoint.
GET /user/webhook-endpoints/:id - — Create. Body:
POST /user/webhook-endpoints—CreateWebhookEndpointDto,endpointUrl(array, e.g.eventTypes), optional["payment.completed","payment.refunded"],accountId,isActive,secretKey,description,retryCount,timeoutSeconds.headers - — Update. Body:
PUT /user/webhook-endpoints/:id(partial:UpdateWebhookEndpointDto,endpointUrl,eventTypes,isActive,description,retryCount,timeoutSeconds).headers - — Delete webhook endpoint.
DELETE /user/webhook-endpoints/:id - — Send a test event to the endpoint.
POST /user/webhook-endpoints/:id/test
-
Webhook events
- — List webhook events (query filters).
GET /user/webhook-events - — Get one event.
GET /user/webhook-events/:id
-
Split rules (require email code for create/update/delete)
- — List split rules for account.
GET /user/accounts/:accountId/split-rules - — Create split rule. Body:
POST /user/accounts/:accountId/split-rules—CreateSplitRuleDto(number),targetAccountCanisterId(0–10000), optionalpercentageBps; andtargetAccountIdoremailSecurityCode. OWNER only.securityCode - — Update split rule. Body:
PUT /user/accounts/:accountId/split-rules/:id(partial) +UpdateSplitRuleDtooremailSecurityCode. OWNER only.securityCode - — Replace all rules atomically. Body:
PUT /user/accounts/:accountId/split-rules. OWNER only.{ rules: CreateSplitRuleDto[], emailSecurityCode?: string, securityCode?: string } - — Delete split rule. Body:
DELETE /user/accounts/:accountId/split-rules/:idoremailSecurityCode. OWNER only.securityCode - — Get splits for a transaction.
GET /user/accounts/:accountId/transactions/:transactionId/splits
-
Transactions
- — List transactions.
GET /user-transactions?accountId=<uuid> - — Get transaction by ID.
GET /user-transactions/:id
-
Notifications
- — List notification templates.
GET /user/notification-templates - — List subscription for account.
GET /user/accounts/:accountId/subscriptions - — Subscribe; body
POST /user/accounts/:accountId/subscriptions.{ templateId } - — Unsubscribe.
DELETE /user/accounts/:accountId/subscriptions/:templateId
-
Security (email challenge — get a code for sensitive actions)
- — Request an email with a verification code. Optional body:
POST /user/security/email-challenge/start. Response includes{ reason?, metadata? }(optional).challengeId - — Verify the code. Body:
POST /user/security/email-challenge/verify. Use the same code in payout/split/wallet requests as{ code: "<6-digit>" }oremailSecurityCode.securityCode
With these endpoints, the agent can create and manage payment links, webhooks, splits, payouts, refunds, wallets, and user profile entirely via the API, without using the icpay.org dashboard. -
适用于AI代理需完全通过ICPay API请求创建用户、验证邮箱、登录、创建账户并生成API密钥的场景。基础URL:
https://api.icpay.org-
注册用户
- 端点:
POST https://api.icpay.org/auth/register - 请求体(JSON): —
RegisterDto、firstName、lastName、email(至少8位)、password(ISO8601格式)、dateOfBirth、addressLine1(可选)、addressLine2、city、stateOrProvince、postalCode(2位ISO代码)、country(可选)、phone(可选)。nationality - 响应: 状态码,返回
201。{ message: "Registration successful. Please check your email to verify your account." } - 系统将发送验证邮件。邮件内容包含“Please verify your email address to complete your registration”及**“Verify Email”链接。链接为网页**地址,例如。JWT包含在查询参数
https://icpay.org/auth/verify-email?token=<JWT>中。token
- 端点:
-
激活账户(验证邮箱)
- 获取token: 从验证邮件中提取“Verify Email”链接,读取查询参数****(即JWT)。
token - 端点:
POST https://api.icpay.org/auth/verify-email - 请求体(JSON):
{ "token": "<链接中的JWT>" } - 响应: 状态码,返回
200。完成后,用户邮箱验证通过,可登录系统。{ message: "..." }
- 获取token: 从验证邮件中提取“Verify Email”链接,读取查询参数**
-
登录(启动OTP)
- 端点:
POST https://api.icpay.org/auth/login - 请求体(JSON):
{ "email": "<注册时使用的邮箱>", "password": "<密码>" } - 响应: 状态码,返回
200。此时未返回JWT。系统将向用户邮箱发送包含验证码的邮件,例如“icpay.org authentication email code” / “The verification code for icpay.org is: 313215”。代理需获取该验证码(例如读取邮件或由用户提供)。{ requires2fa: true, challengeId: "<sid>", user: { id, firstName, lastName, email, ... } }
- 端点:
-
完成登录(提交OTP验证码)
- 端点:
POST https://api.icpay.org/auth/verify-login-otp - 请求体(JSON):
{ "email": "<同一邮箱>", "code": "<邮件中的6位验证码>" } - 响应: 状态码,返回
200。后续所有请求均使用**{ access_token: "<JWT>", user: { ... } }**作为Bearer令牌。access_token
- 端点:
-
使用Bearer令牌发起后续所有请求
- 每个API请求需携带请求头:。
Authorization: Bearer <access_token>
- 每个API请求需携带请求头:
-
创建账户
- 端点:
POST https://api.icpay.org/user-accounts - 请求头: 、
Authorization: Bearer <access_token>Content-Type: application/json - 请求体(JSON): —
CreateAccountDto、name,可选email(2位代码)、country、accountType、businessName。businessType - 响应: 状态码,返回创建的账户对象;记录**
201**(账户ID)。id
- 端点:
-
生成API密钥(可发布密钥 + 密钥)
- 端点:
POST https://api.icpay.org/user-accounts/:accountId/generate-secret-key - 请求头:
Authorization: Bearer <access_token> - 请求体: 无(或)。
{} - 响应: 状态码,返回
200。{ secretKey: "sk_...", publicKey: "pk_..." } - 可发布密钥(): 可安全存储在
pk_...中(例如.env)或直接在客户端代码中使用;属于公开密钥。NEXT_PUBLIC_ICPAY_PK - 密钥(): 仅显示一次;请立即复制。仅存储在**
sk_...**中(例如.env)。绝不能嵌入源代码或提交至git;仅在服务器端使用。ICPAY_SECRET_KEY=sk_...
- 端点:
-
在应用中使用
- 可发布密钥: 与icpay-widget配合使用,构建任何接受加密支付的前端(支付按钮、小费罐、付费墙等)。
- 密钥: 在服务器端与icpay-sdk配合使用,执行受保护操作(例如,
icpay.protected.getPaymentById,listPayments)并验证支付状态。或者(或同时)在ICPay仪表盘中注册Webhook URL;验证getDetailedAccountInfo并处理X-ICPay-Signature(可选payment.completed)事件以完成履约。payment.refunded
-
其他API端点(均需) 使用步骤4获取的JWT,代理可完全通过API执行所有账户操作,无需使用icpay.org。基础URL:
Authorization: Bearer <access_token>。当请求包含体时,需发送https://api.icpay.org。Content-Type: application/json敏感操作的邮箱验证码: 对于提现、分账规则(创建/更新/删除/替换),API要求提供邮箱验证码。首先调用(可选请求体POST /user/security/email-challenge/start);用户将收到包含验证码的邮件。然后在调用以下端点时,将验证码作为{ reason?, metadata? }或emailSecurityCode包含在请求体中。若登录OTP验证码仍有效,也可复用该验证码。securityCode-
用户资料
- — 获取当前用户资料。
GET /users/profile - — 更新资料。请求体:
PATCH /users/profile(可选字段:SelfUpdateUserDto、firstName、lastName、phone、dateOfBirth、avatarUrl、nationality{ line1, line2, city, stateOrProvince, postalCode, country }、address)。无法通过此端点修改邮箱。fiatCurrencyId
-
切换账户
- — 请求体:
POST /auth/switch-account。返回针对该账户的新令牌;若用户拥有多个账户,后续请求使用此令牌。{ "accountId": "<uuid>" }
-
列出用户账户
- — 列出用户所属的所有账户。
GET /user-account-users/my-accounts - — 列出待处理的邀请。
GET /user-account-users/my-pending-invitations - — 邀请用户加入账户。请求体:
POST /user-account-users/invite—CreateInvitationDto(字符串)、accountId(字符串),可选email(例如role|"owner"|"admin",默认"viewer")、"viewer"(字符串数组)。permissions字段由服务器从认证用户(JWT)中设置,客户端无需传入。invitedBy - — 接受邀请。
POST /user-account-users/:id/accept - — 拒绝邀请。
POST /user-account-users/:id/decline - — 列出账户的所有用户(需为账户成员)。
GET /user-account-users/account/:accountId
-
账户(user-accounts)
- — 更新账户(JWT需为账户所有者或管理员)。请求体:
PATCH /user-accounts/:id— 所有字段可选,以下为用户/所有者可修改的字段(未列出管理员专属和系统字段):UpdateAccountDto、name、email、country、accountType、businessName、businessType、isActive、isLive、taxId(对象:businessProfile、name、url、mcc、supportEmail、supportPhone)、supportUrl(对象:capabilities、cardPayments、transfers)、taxReporting(对象:requirements、currentlyDue、eventuallyDue、pastDue)、disabledReason、primaryDomain(对象:branding、logoUrl、faviconUrl、primaryColor)、secondaryColor、address、billingAddress、taxInfo(数字,基点)、relayFeeBps。settings - — 重新生成API密钥;返回
POST /user-accounts/:id/regenerate-secret-key(密钥仅显示一次)。{ secretKey, publicKey } - — 启动手机号变更流程;请求体
POST /user-accounts/:id/phone-change/start。{ phone } - — 请求体
POST /user-accounts/:id/phone-change/verify确认手机号变更。{ challengeId, code }
-
支付链接
- — 列出账户的支付链接。
GET /user/payment-links?accountId=<uuid> - — 获取单个支付链接。
GET /user/payment-links/:id - — 创建支付链接。请求体:
POST /user/payment-links—CreatePaymentLinkDto、name、description,可选amountUsd、fiatCurrencyId(或通过查询参数accountId传入)、收集/必填设置(邮箱、姓名、地址、电话、商家信息、配送信息)、数量(允许设置、默认值、最小值、最大值)、?accountId=、maxRedemptions、widgetOptions、showWalletConnectQr、showBaseWalletQr。短代码自动生成。isActive - — 更新支付链接。请求体:
PUT /user/payment-links/:id(与创建字段相同,支持部分更新)。UpdatePaymentLinkDto - — 删除支付链接。
DELETE /user/payment-links/:id - — 列出支付链接的提交记录。
GET /user/payment-links/:id/submissions
-
支付(列表、详情、退款)
- — 列出支付记录(支持分页)。
GET /user/payments?accountId=<uuid> - — 获取账户支付汇总。
GET /user/payments/summary - — 获取支付统计数据。
GET /user/payments/stats - — 根据ID获取支付记录。
GET /user/payments/:id - — 检查是否允许退款。
GET /user/payments/:id/refund-precheck - — 为支付记录发起退款。无需请求体(全额退款)。退款由execute-refunds worker处理;退款完成时触发Webhook
POST /user/payments/:id/refund。payment.refunded
-
提现(需邮箱验证码)
- — 列出提现记录。
GET /user/payouts?accountId=<uuid> - — 创建提现请求。请求体:
POST /user/payouts、accountId(十进制字符串),可选amount、ledgerId、ledgerCanisterId、accountCanisterId、toWalletAddress,以及**toWalletSubaccount或emailSecurityCode**(邮件中的验证码)。仅所有者或拥有提现权限的管理员可操作。securityCode - — 执行已创建的提现请求。
POST /user/payouts/:id/execute
-
Webhook端点
- — 列出Webhook端点。
GET /user/webhook-endpoints?accountId=<uuid> - — 获取单个Webhook端点。
GET /user/webhook-endpoints/:id - — 创建Webhook端点。请求体:
POST /user/webhook-endpoints—CreateWebhookEndpointDto、endpointUrl(数组,例如eventTypes),可选["payment.completed","payment.refunded"]、accountId、isActive、secretKey、description、retryCount、timeoutSeconds。headers - — 更新Webhook端点。请求体:
PUT /user/webhook-endpoints/:id(部分更新:UpdateWebhookEndpointDto、endpointUrl、eventTypes、isActive、description、retryCount、timeoutSeconds)。headers - — 删除Webhook端点。
DELETE /user/webhook-endpoints/:id - — 向端点发送测试事件。
POST /user/webhook-endpoints/:id/test
-
Webhook事件
- — 列出Webhook事件(支持查询筛选)。
GET /user/webhook-events - — 获取单个Webhook事件。
GET /user/webhook-events/:id
-
分账规则(创建/更新/删除需邮箱验证码)
- — 列出账户的分账规则。
GET /user/accounts/:accountId/split-rules - — 创建分账规则。请求体:
POST /user/accounts/:accountId/split-rules—CreateSplitRuleDto(数字)、targetAccountCanisterId(0–10000),可选percentageBps;以及**targetAccountId或emailSecurityCode**。仅所有者可操作。securityCode - — 更新分账规则。请求体:
PUT /user/accounts/:accountId/split-rules/:id(部分更新) +UpdateSplitRuleDto或emailSecurityCode。仅所有者可操作。securityCode - — 原子替换所有分账规则。请求体:
PUT /user/accounts/:accountId/split-rules。仅所有者可操作。{ rules: CreateSplitRuleDto[], emailSecurityCode?: string, securityCode?: string } - — 删除分账规则。请求体:
DELETE /user/accounts/:accountId/split-rules/:id或emailSecurityCode。仅所有者可操作。securityCode - — 获取交易的分账详情。
GET /user/accounts/:accountId/transactions/:transactionId/splits
-
交易记录
- — 列出交易记录。
GET /user-transactions?accountId=<uuid> - — 根据ID获取交易记录。
GET /user-transactions/:id
-
通知
- — 列出通知模板。
GET /user/notification-templates - — 列出账户的通知订阅。
GET /user/accounts/:accountId/subscriptions - — 订阅通知;请求体
POST /user/accounts/:accountId/subscriptions。{ templateId } - — 取消订阅。
DELETE /user/accounts/:accountId/subscriptions/:templateId
-
安全(邮箱挑战 — 获取敏感操作的验证码)
- — 请求发送包含验证码的邮件。可选请求体:
POST /user/security/email-challenge/start。响应包含{ reason?, metadata? }(可选)。challengeId - — 验证验证码。请求体:
POST /user/security/email-challenge/verify。可将同一验证码用于提现/分账/钱包请求中的{ code: "<6位验证码>" }或emailSecurityCode字段。securityCode
通过这些端点,代理可完全通过API创建和管理支付链接、Webhook、分账规则、提现、退款、钱包及用户资料,无需使用icpay.org仪表盘。 -
Flow: I am the human (getting started myself)
流程:我是开发者(自行入门)
Use this when you are the developer/user and want to register on icpay.org, create one account, get API keys, and accept crypto payments.
- Sign up — Go to https://icpay.org and complete Sign up (first name, last name, email, password, and any other required fields such as address, country).
- Verify email — Check the email inbox for the address you used. You will either receive:
- A link — Click “Verify Email” (or similar) to complete verification; or
- A code — Enter that code on the verification page when prompted. Do not skip this step; you cannot log in until email is verified.
- Log in — Go to https://icpay.org/auth/login and sign in with your email and password.
- Create one account — After login, create a business account (name, email, country, business name, business type). This is your merchant account for receiving payments.
- Generate API keys — In the dashboard, go to Settings (or API Keys). Click Generate (or Generate secret key). You will see:
- Publishable key (or
pk_live_...) — Safe to use in frontend or put inpk_test_...(e.g..env).NEXT_PUBLIC_ICPAY_PK - Secret key () — Shown once; copy it immediately. Store it only in
sk_...(e.g..env). Never put the secret key in your source code or commit it to git.ICPAY_SECRET_KEY=sk_...
- Publishable key (
- Use in your app — Use the publishable key with icpay-widget (e.g. ) to add pay buttons, tip jars, paywalls, or other components that accept crypto. To verify that a payment succeeded, use either:
@ic-pay/icpay-widget- icpay-sdk on your server with the secret key (e.g. ), or
icpay.protected.getPaymentById(id) - A webhook URL registered in the ICPay dashboard; verify the header and handle
X-ICPay-Signature(and optionallypayment.completed).payment.refunded
- icpay-sdk on your server with the secret key (e.g.
适用于开发者/用户自行在icpay.org注册、创建账户、获取API密钥并接受加密支付的场景。
- 注册 — 访问**https://icpay.org**并完成**注册**(填写姓名、邮箱、密码及其他必填信息,例如地址、国家)。
- 验证邮箱 — 检查注册时使用的邮箱收件箱。您将收到:
- 一个链接 — 点击“Verify Email”(或类似按钮)完成验证;或
- 一个验证码 — 在验证页面输入该验证码。 请勿跳过此步骤;邮箱未验证前无法登录。
- 登录 — 访问**https://icpay.org/auth/login**并使用邮箱和密码登录。
- 创建账户 — 登录后,创建商户账户(填写名称、邮箱、国家、商家名称、商家类型)。这是您用于接收支付的商户账户。
- 生成API密钥 — 在仪表盘进入Settings(或API Keys)页面。点击Generate(或Generate secret key)。您将看到:
- 可发布密钥 (或
pk_live_...) — 可安全用于前端或存储在pk_test_...中(例如.env)。NEXT_PUBLIC_ICPAY_PK - 密钥 () — 仅显示一次;请立即复制。仅存储在**
sk_...**中(例如.env)。绝不能将密钥放入源代码或提交至git。ICPAY_SECRET_KEY=sk_...
- 可发布密钥 (
- 在应用中使用 — 使用可发布密钥配合icpay-widget(例如)添加支付按钮、小费罐、付费墙或其他接受加密支付的组件。要验证支付是否成功,可选择以下两种方式之一:
@ic-pay/icpay-widget- 在服务器端使用密钥配合icpay-sdk(例如),或
icpay.protected.getPaymentById(id) - 在ICPay仪表盘中注册Webhook URL;验证请求头并处理
X-ICPay-Signature(可选payment.completed)事件。payment.refunded
- 在服务器端使用密钥配合icpay-sdk(例如
Webhooks
Webhook
- Endpoint: Merchant registers URL in ICPay dashboard; events posted to that URL.
- Security: Verify = HMAC-SHA256(raw body, webhook secret) using constant-time compare. Reject if invalid.
X-ICPay-Signature - Payload: JSON body; e.g.
event.type,payment.completed,payment.failed. Use event/payment IDs for idempotency.payment.refunded - Retries: Backoff and retries by backend; handle duplicate deliveries idempotently.
- 端点: 商户在ICPay仪表盘中注册URL;事件将推送至该URL。
- 安全验证: 使用恒时比较法验证是否等于HMAC-SHA256(原始请求体, Webhook密钥)。验证失败则拒绝请求。
X-ICPay-Signature - 负载: JSON格式请求体;例如
event.type、payment.completed、payment.failed。使用事件/支付ID实现幂等性。payment.refunded - 重试机制: 后端采用退避重试策略;需处理重复投递的幂等性。
Refunds
退款
- Refunds are requested/executed via API or dashboard; execute-refunds worker processes them.
- Webhook is sent when a refund completes. Email notification (refund completed) can be sent to the account; templates in
payment.refunded(e.g.notification_templates).email_refund_completed_account
- 可通过API或仪表盘发起/执行退款;由execute-refunds worker处理。
- 退款完成时触发Webhook 并向账户发送邮件通知;通知模板位于
payment.refunded(例如notification_templates)。email_refund_completed_account
Split payments (optional)
分账支付(可选)
- Split rules let multiple merchants share revenue: per account, define target account(s) and percentage (basis points). Entity: (accountId, targetAccountId / targetAccountCanisterId, percentageBps). Services distribute funds according to rules.
SplitRule - API: splits module () — user/sdk controllers for split rules (create, update, list). Optional feature; when not used, 100% goes to the receiving account.
icpay-api/src/splits/
- 分账规则允许多个商户共享收益:为账户定义目标账户及基点百分比。实体定义:(包含accountId、targetAccountId / targetAccountCanisterId、percentageBps)。服务将根据规则分配资金。
SplitRule - API:分账模块() — 提供用户/SDK控制器用于分账规则的创建、更新、列表查询。可选功能;未启用时,100%收益归收款账户所有。
icpay-api/src/splits/
Email notifications
邮件通知
- Payment completed and refund completed emails can be sent to the account. process-notifications worker and notification templates in the API; user/account can have default fiat for amount in emails.
- Configure in dashboard/account settings; templates editable via migrations or admin.
Example verification (Node):
ts
const crypto = require('node:crypto');
const sig = req.headers['x-icpay-signature'] || '';
const raw = req.body; // raw buffer
const expected = crypto.createHmac('sha256', process.env.ICPAY_WEBHOOK_SECRET).update(raw).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.status(401).send();- 账户将收到支付完成和退款完成的邮件;支持配置模板;由process-notifications worker处理。
- 可在仪表盘/账户设置中配置;模板可通过迁移或管理员操作编辑。
验证示例(Node):
ts
const crypto = require('node:crypto');
const sig = req.headers['x-icpay-signature'] || '';
const raw = req.body; // 原始Buffer
const expected = crypto.createHmac('sha256', process.env.ICPAY_WEBHOOK_SECRET).update(raw).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.status(401).send();Events (Widget & SDK)
事件(Widget & SDK)
Widget: (payment done), , (paywall), , . SDK (on window): , , . Subscribe on the widget element or to drive UI/analytics; do not rely on console.
icpay-payicpay-erroricpay-unlockicpay-tipicpay-donationicpay-sdk-method-start|success|erroricpay-sdk-transaction-created|updated|completed|failed|mismatchedicpay-sdk-wallet-connected|disconnected|cancelled|errorwindowWidget事件: (支付完成)、、(付费墙解锁)、、。SDK事件(在window对象上触发): 、、。在Widget元素或上订阅事件以驱动界面/分析;请勿依赖控制台输出。
icpay-payicpay-erroricpay-unlockicpay-tipicpay-donationicpay-sdk-method-start|success|erroricpay-sdk-transaction-created|updated|completed|failed|mismatchedicpay-sdk-wallet-connected|disconnected|cancelled|errorwindowDemo / playground (demo.icpay.org)
演示/沙箱环境(demo.icpay.org)
- https://demo.icpay.org — Live demo app () for building and testing custom widgets. All widget types, configurable options, copy-paste snippets. Use for quick experiments and sharing configs (e.g. with publishableKey in query).
icpay-demo/
- https://demo.icpay.org — 用于构建和测试自定义Widget的在线演示应用()。包含所有Widget类型、可配置选项及代码片段复制功能。用于快速实验和共享配置(例如在查询参数中携带publishableKey)。
icpay-demo/
Sandbox (betterstripe.com)
沙箱环境(betterstripe.com)
- https://betterstripe.com — Sandbox environment for developers. Same functionality as icpay.org (dashboard, payment links, widget, API, webhooks, relay, X402, splits, refunds, email notifications) but uses testnets as well as mainnets, so you can test without mainnet funds if you need to.
- Networks: Solana devnet, Base Sepolia, Ark network testnet, and other supported testnets. Mainnet chains (e.g. Solana mainnet, Base mainnet, IC mainnet);
- Use case: Integrate the widget or SDK against the sandbox API and pay page; create test accounts and payment links; verify webhooks, relay, and refund flows with testnet tokens.
- Keys: Sandbox uses test keys (e.g. ); keep sandbox and production keys separate. API base and pay page are sandbox-specific (betterstripe.com); switch to icpay.org and production API when going live.
pk_test_*
- https://betterstripe.com — 供开发者使用的沙箱环境。功能与icpay.org完全一致(仪表盘、支付链接、Widget、API、Webhook、中继支付、X402、分账、退款、邮件通知),但同时支持测试网和主网,无需主网资金即可完成测试。
- 支持网络: Solana devnet、Base Sepolia、Ark网络测试网及其他支持的测试网。同时支持主网链(例如Solana主网、Base主网、IC主网);
- 使用场景: 针对沙箱API和支付页面集成Widget或SDK;创建测试账户和支付链接;使用测试网代币验证Webhook、中继支付和退款流程。
- 密钥: 沙箱使用测试密钥(例如);请将沙箱密钥与生产密钥分开存储。API基础地址和支付页面均为沙箱专属(betterstripe.com);上线时切换至icpay.org和生产API。
pk_test_*
WordPress plugins
WordPress插件
Two plugins live under :
icpay-integrations/- icpay-payments — Standalone: Gutenberg block + shortcodes for all widgets; settings for publishable/secret key; webhook receiver; sync payments. Webhook URL: .
/wp-json/icpay-payments/v1/webhook - instant-crypto-payments-for-woocommerce — WooCommerce gateway: checkout/order-pay pay button; webhook updates order status; reuses ICPay keys from main plugin if present. Webhook URL: .
/wp-json/instant-crypto-payments-for-woocommerce/v1/wc/webhook
Both verify webhooks with HMAC-SHA256. Widget script: (built from icpay-widget). See wordpress.md for build and shortcode/block usage.
assets/js/icpay-embed.min.jsicpay-integrations/- icpay-payments — 独立插件:提供Gutenberg区块 + 短代码支持所有Widget;支持配置可发布/密钥;内置Webhook接收器;同步支付记录。Webhook URL:。
/wp-json/icpay-payments/v1/webhook - instant-crypto-payments-for-woocommerce — WooCommerce网关:在结账/订单支付页面添加支付按钮;Webhook更新订单状态;若已安装主插件,将复用ICPay密钥。Webhook URL:。
/wp-json/instant-crypto-payments-for-woocommerce/v1/wc/webhook
两个插件均使用HMAC-SHA256验证Webhook。Widget脚本:(由icpay-widget构建)。详见wordpress.md获取构建和短代码/区块使用说明。
assets/js/icpay-embed.min.jsConventions
约定
- Use pnpm for install/build.
- Prefer SDK over direct HTTP for payment/account operations. Prefer widget events for success/error handling.
- Token identification: Use (e.g.
tokenShortcode,ic_icp); legacy symbol/ledgerCanisterId/chainId still supported.base_eth - Errors: Catch ; check
IcpayErrorandcode; surface user-friendly messages; log details server-side only when needed.message
- 使用pnpm进行安装/构建。
- 优先使用SDK而非直接HTTP请求处理支付/账户操作。优先使用Widget事件处理成功/错误。
- 代币标识: 使用(例如
tokenShortcode、ic_icp);仍支持旧版symbol/ledgerCanisterId/chainId。base_eth - 错误处理: 捕获;检查
IcpayError和code;显示用户友好的提示信息;仅在必要时在服务器端记录详细错误。message
Additional resources
额外资源
- API, entities, workers, splits, refunds, X402: reference.md
- Widget components, config, wallet adapters, filter tokens: widget-reference.md
- WordPress build and usage: wordpress.md
- Docs site: https://docs.icpay.org
- Demo: https://demo.icpay.org
- Sandbox (testnets): https://betterstripe.com — Solana devnet, Base Sepolia, Ark testnet, etc.
- This skill (source): https://github.com/icpay/icpay-sdk/tree/master/skills/icpay — npm: @ic-pay/icpay-sdk, @ic-pay/icpay-widget
- API、实体、Worker、分账、退款、X402: reference.md
- Widget组件、配置、钱包适配器、筛选代币: widget-reference.md
- WordPress构建与使用: wordpress.md
- 文档站点: https://docs.icpay.org
- 演示站点: https://demo.icpay.org
- 沙箱环境(测试网): https://betterstripe.com — Solana devnet、Base Sepolia、Ark测试网等。
- 本技能文档(源码): https://github.com/icpay/icpay-sdk/tree/master/skills/icpay — npm包:@ic-pay/icpay-sdk、@ic-pay/icpay-widget",