TRADOM PaymentDocs

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へ含めないでください。

このページの内容