Custom Payment Flow
PaymentIntentを使い、独自の決済UIと状態管理を構築する
Custom Payment Flowは、PaymentIntentを使って独自の決済UIを構築する統合方式です。支払い1件の状態と次の操作をbackendから制御できます。
Hosted Checkoutで要件を満たせる場合は、実装と運用が少ない Hosted Checkout を推奨します。
現行本番では、オンチェーン着金からPaymentIntentを自動で succeeded に進める配線が未完了です。本番/testnet決済にはHosted Checkoutを使い、PaymentIntentのE2E確認は simulate を利用してください。詳細は 互換性・既知の制約 を参照してください。
クライアントを作成
import { PaymentClient } from "@tradom/payment";
const TRADOM_PAYMENT_SECRET_KEY =
process.env.TRADOM_PAYMENT_SECRET_KEY;
if (!TRADOM_PAYMENT_SECRET_KEY) {
throw new Error("TRADOM_PAYMENT_SECRET_KEY is required");
}
const tradomPayment = new PaymentClient({
apiKey: TRADOM_PAYMENT_SECRET_KEY,
});1. 作成
PaymentIntentは、同じマーチャントに属する決済リンクのshare tokenから作成します。
const paymentIntent = await tradomPayment.paymentIntents.create({
paymentLinkToken: "<share_token>",
mode: "simulate",
metadata: { orderId: "order_42" },
idempotencyKey: "order-42",
});idempotencyKey はマーチャント単位で一意です。同じキーの再送は既存のPaymentIntentを返します。作成直後の状態は requires_payment_method です。
金額は法定通貨の主単位です。JPYは円、USDはドルであり、USDを100倍してセントへ変換しません。
2. 見積り(任意)
const quote = await tradomPayment.paymentIntents.cryptoQuote(
paymentIntent.id,
{ stablecoin: "usdc", network: "ethereum" },
);見積りID cq_… は表示用です。現行APIの confirm は見積りIDを受け取らず、確定時に同じレールの金額を再計算します。
3. 確定
const confirmed = await tradomPayment.paymentIntents.confirm(
paymentIntent.id,
{ stablecoin: "usdc", network: "ethereum" },
);
const deposit = confirmed.nextAction?.cryptoDeposit;確定後は requires_action になり、depositAddress、amount、eip681Uri、expiresAt などの入金指示が返ります。入金期限は15分です。期限切れ後は再度 confirm して、新しい入金セッションを開始します。
4. 取得・キャンセル
const latest = await tradomPayment.paymentIntents.retrieve(paymentIntent.id);
if (latest.status === "requires_action") {
await tradomPayment.paymentIntents.cancel(latest.id);
}cancel は未完了のPaymentIntentだけに使えます。succeeded またはすでに canceled の支払いはキャンセルできません。
ホスト型セッションについて
REST APIの POST /api/v1/checkout_sessions はAPIキーなしで client_secret を発行し、後続操作では X-Client-Secret またはJSON bodyの client_secret を受け付けます。
SDK 0.5.0では、API keyなしのclientでセッション作成とclient-secret scoped操作を実行できます。
const checkoutClient = new PaymentClient({});
const session = await checkoutClient.paymentIntents.createCheckoutSession({
paymentLinkToken: "<share_token>",
mode: "simulate",
});
const access = { clientSecret: session.clientSecret! };
const quote = await checkoutClient.paymentIntents.cryptoQuote(
session.id,
{ stablecoin: "usdc", network: "ethereum" },
access,
);
const confirmed = await checkoutClient.paymentIntents.confirm(
session.id,
{ stablecoin: "usdc", network: "ethereum" },
access,
);
const latest =
await checkoutClient.paymentIntents.retrieve(session.id, access);optionsへ clientSecret を渡すとSDKはBearer keyを送らず、X-Client-Secret を使用します。cancel、refund、simulateDeposit はマーチャントのsecret keyが必要です(simulateDeposit は sk_test_… で作成した simulate intentのみ)。
SDKはサーバ専用です。ブラウザへsecret keyを渡さず、この処理はbackend/BFFに置いてください。client secretもURL queryへ含めないでください。