portaly-payment について
Portaly Payment の導入を支援する AI エージェント向けスキルです。API キーの準備からチェックアウト後のコールバック処理まで案内し、テスト・本番モード、サブスクリプション API、署名検証を扱います。
主な機能
- 01マーチャント設定とサブスクリプションプランの作成
- 02チェックアウトセッション作成とコールバック処理
- 03テストモードと本番モードの違い
- 04サブスクリプションのキャンセル、再開、ポータル API
- 05プロジェクトの技術スタックに応じた署名検証
活用シーン
- 01既存アプリへの Portaly チェックアウト導入
- 02決済コールバック処理のテスト
- 03サブスクリプションのキャンセルと再開の実装
- 04API キーモードやコールバック署名の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ portaly-ai/ portaly-skills --skill portaly-paymentインストール後、Claude Code で/portaly-paymentを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api-contract.mdcallback-signature-v1-vectors.jsoncallback-signature-v1.mdcheckout-and-renewal.mdconversion-tracking.mddiscount-code-examples.mdscripts/check_callback_vectors.mjsgo.modsign_callback.mjssign_callback.pysign_callback.webcrypto.mjsverify_callback_test.goverify_callback.go詳細
Portaly Payment 統合
このスキルを使って、ユーザーによる Portaly Payment API の統合を迅速に完了できるよう支援してください。回答は実務に役立つ内容にしてください。長いアーキテクチャの説明よりも、手順のリスト、API リクエストとレスポンスの箇条書き、すぐにコピーできる例を優先してください。
Portaly Payment の環境
Portaly Payment は、API キーごとに live モードと test モードの 2 つをサポートしています。
API ホストと決済サイト
API ホストと決済サイト(購入者がチェックアウトのためにリダイレクトされるサイト)は、どちらのモードでも同じ統合ドメイン上にあります。
https://portaly.ai(デフォルト)
ホストは PORTALY_API_HOST 環境変数で上書きできます。Portaly API を呼び出すコードを生成する際は、URL をハードコーディングするのではなく、次のパターンを優先してください。
const PORTALY_API_HOST = process.env.PORTALY_API_HOST || 'https://portaly.ai'
バックエンドの互換性に関する契約については、リポジトリのルートにある PROVIDER.md を参照してください。
モードの動作
| 項目 | ライブモード | テストモード |
|---|---|---|
| API キーのプレフィックス | pcs_live_ | pcs_test_ |
| 決済プロバイダー | 91APP — 購入者は外部にリダイレクトされ、コールバック時に決済が完了します | TapPay サンドボックス — チェックアウトページ上で決済されます |
| 注文の保存先 | クリエイターのライブ注文台帳 | 独立したサンドボックス台帳 |
| コールバックペイロード | mode: "live" または省略 | mode: "test" |
- モードは API キーの作成時に設定され、作成後は変更できません。
- 1つのマーチャント(
profileId)で、ライブキーとテストキーの両方を同時に有効にできます。 - 注文の返金を除き、API エンドポイントはライブキーとテストキーの両方を受け付けます。
POST /orders/{orderId}/refundは現在、全スコープを持つライブキーを必要とします。モードはリクエストパラメーターではなく、キーから判定されます。 - テストモードは統合テストを目的としています。TapPay のサンドボックス認証情報を使用する場合、テストモードでは実際の決済は発生しません。
- カード番号を絶対に作り出さないでください。 テストモードのチェックアウトページには、使用するテストカードがカード入力欄のすぐ下の強調表示されたボックスに表示されます。ユーザーにはページ上で確認するよう伝えてください。このカードが使えるのは、この連携で作成した
checkoutUrl上のみです。実際の決済が行われる場所では拒否され、わかりやすいメッセージではなく、ゲートウェイからのエラーがそのまま返されます。 - テストモードとライブモードでは、決済プロバイダーが異なります。 テストのチェックアウトではチェックアウトページ上で TapPay を通じて決済されますが、ライブのチェックアウトでは購入者を 91APP に引き渡し、コールバック時に決済が完了します。そのため、テストが正常に完了しても、ライブのリダイレクトと復帰の経路はテストされていません。また、コールバックの
paymentMethodはテストではtappay、ライブでは91appとなるため、値をハードコードしないでください。この2つだけが値になり得ると考えるのも避けてください。POST /checkout-sessions/{sessionId}/completeで完了したセッションには、マーチャントが送信したpaymentMethodがそのまま含まれます(このセッションにはサブスクリプションが紐づきません。§6 を参照)。 - テストモードのサブスクリプションは更新されません。 更新ジョブはテストサブスクリプションを完全にスキップするため、どれだけ待っても2回目のサイクルの
creator_subscription.payment.succeededは届きません。時間が経つのを待つのではなく、ペイロードを再送して更新ハンドラーをテストしてください。 cancelEffectiveAtを待たずに、テストモードでcreator_subscription.canceledを確認するには、 Orders テーブルからテスト注文を返金してください(ツールバーの切り替えを Test にします)。サブスクリプションはすぐにキャンセルされ、canceledが送信されます。テストの返金ではpayment.refundedは送信されないため、このハンドラーのテストにはペイロードの再送が必要です。- サンドボックス台帳は精算フローに含まれません。 テストの前にクリエイターへ伝えてください。存在しないものを探し回ることがないようにするためです。テスト注文は収益、残高、支払いには反映されず、アフィリエイト手数料やプロモーション手数料も発生せず、請求書も発行されません。また、レビューの対象にならないため、レビュー依頼も送信されません。注文テーブルの Live/Test 切り替えを Test にすると、
https://portaly.cc/admin/creator-subscriptionに一覧表示されます。この画面から返金もできます。ここで確認するようクリエイターに伝えてください。「テストタブ」とは呼ばないでください。このページのタブは Subscriptions と Orders で、モード切り替えはテーブル専用のツールバーにあります。 - プランとマーチャント設定は、どちらのモードでも共有されます。 これらは API キーのモードではなく、マーチャント(
profileId)に紐づいています。ライブキーで作成したプランはテストキーでも表示され、利用できます。その逆も同様です。ライブキーとテストキーを切り替えるたびに、プランを重複して作成しないでください。まずGET /api/creator-subscription/plansで既存のプランを確認し、再利用してください。
クイックスタート
前提条件 — Portaly Payment アカウントが必要です。 この連携には Portaly Payment API キーが必要です。ユーザーがまだ Portaly Payment アカウントを持っていない場合は、まず登録してもらうまで作業を中断してください。ほかの作業に進む前に
https://portaly.cc/paymentで登録してもらいます — ページを開くことを提案し、ユーザーが同意したら開いてください:# Portaly Payment の登録ページを開く — ユーザーの OS に対応する行を選択 Start-Process "https://portaly.cc/payment" # Windows (PowerShell) open "https://portaly.cc/payment" # macOS xdg-open "https://portaly.cc/payment" # Linuxアカウントを作成し、キーを発行するまで作業を続けないでください。登録後、
https://portaly.cc/admin/creator-subscriptionのダッシュボードでキーを作成します。
- 作業を始める前に、AI エージェントは人間のユーザーに、
https://portaly.cc/admin/creator-subscriptionの Portaly Payment ダッシュボードで Portaly Payment API キー/CallbackSecret を取得または作成し、発行されたシークレット情報を安全に保管するよう依頼してください。 - 人間のユーザーに、本番用キーとテスト用キーのどちらを希望するか確認します。ただし、制約を明確に説明してください。本番用キーには、次の 3 つすべてが必要です。加盟店(本人)が Portaly の決済審査(金流審核 / KYC)に合格していること(未完了の場合は
403 PAYMENT_KYC_NOT_VERIFIED)、有料会員(Portaly premium または Portaly Vibe のサブスクリプション)であること(該当しない場合は403 PREMIUM_REQUIRED)、さらに、2 つ目以降の商品では、その商品自体の審査に合格していること(未完了の場合は403 PRODUCT_REVIEW_NOT_VERIFIED— 本人確認はすでに完了しているため、再提出してはいけません。審査待ちなのはこの商品だけです)。これら 3 つの条件は、ダッシュボードの UI 上で非表示になっているだけではなく、サーバー側でもすべて適用されます。初めて利用するユーザーは、ほとんどの場合、まだ審査に合格していないため、本番用キーを利用できません。まずテスト用キーで始めて、今すぐ連携全体を構築・テストすることを推奨してください。3 つの条件がすべて満たされたら、ダッシュボードに戻って本番環境用の本番用キーを作成できます。
- 人間のユーザーが何を構築しようとしているか確認します。
次のような決済連携タスクに備えます。
- 加盟店設定を作成する
- サブスクリプションプランを作成する
- 加盟店またはプランの画像をアップロードする(必要に応じて、エージェントは人間のユーザーに画像素材の提供を依頼してください)
- セットアップ後、チェックアウトセッションの作成とコールバック処理を既存のシステムに組み込みます。
- 購入者が決済を開始する前にチェックアウトセッションを作成する
- 購入者を Portaly のチェックアウトにリダイレクトする
- チェックアウト完了後、Portaly からのコールバックを検証して処理する
- サブスクリプションのライフサイクル管理が必要な場合は、定期プランのキャンセル API と再開 API も組み込む
- 購読者向けセルフサービス(購読者が自分のサブスクリプションを管理できるようにすること)が必要な場合は、ポータルセッション API も組み込む
references/api-contract.mdから始めます。 エンドポイント一覧、認証、リクエスト本文、レスポンス本文、コールバックヘッダーの確認に使用します。- コールバック受信側を新規作成または修正する前に、リポジトリの言語、フレームワーク、ランタイムを確認し、
references/callback-signature-v1.mdを読み込んでください。 対応する同梱アダプターを選び、本番環境由来のテストベクトルを実行します。一覧にないランタイムの場合は、文書化されたサーバー側ブリッジを使用するか、ネイティブ実装がテストベクトルに合格するまで連携を保留してください。Node の署名処理を記憶に頼って翻訳してはいけません。 - 必要な場合にのみ
references/checkout-and-renewal.mdを読み込みます。 人間のユーザーから、チェックアウト後の課金、更新、出金、請求書、またはブリッジ注文の動作について質問された場合に限り、補足資料として使用します。 - 実装にすぐ使える形式で出力します。 番号付きの手順、API エンドポイント一覧、リクエストとレスポンスの箇条書き、リポジトリの既存スタックに合った例を優先します。
出力スタイル
- ユーザーの連携作業を支援する AI エージェント向けに記述します。
- 人間が次に行うべき具体的な手順を最初に示します。
- Portaly Payment API キーを使用して、エージェントが API を直接呼び出せる場合は、そのことを明示します。
- ユーザーが有効な認証情報と必要な入力をすでに提供している場合は、マーチャント設定、プランの作成や更新、画像のアップロード、チェックアウトセッションの作成に、セットアップ API を直接使用することを優先します。
- 次の項目にはリストを使用します。
- セットアップ手順
- API エンドポイント
- 必須ヘッダー
- リクエストフィールド
- レスポンスフィールド
- コールバックの検証手順
- 一般的な API の例では、使用するスタックが指定されていない場合は、簡潔な JavaScript または TypeScript を優先します。コールバックの検証では、まずスタックを確認するか、ユーザーに尋ねたうえで、
references/callback-signature-v1.mdに従います。黙って JavaScript をデフォルトにしないでください。 - Portaly が担う動作とサードパーティが担う動作を明確に区別します。
ワークフロー
1. API キーを申請する
-
この連携には、Portaly Payment API キーと CallbackSecret が必要です。
-
人間のユーザーに、
https://portaly.cc/admin/creator-subscriptionの Portaly Payment ダッシュボードで Portaly Payment API キーを申請または作成するよう案内してください。 -
ユーザーが本番キー(
pcs_live_…)とテストキー(pcs_test_…)のどちらを希望するか尋ね、行き詰まらないよう、最初に必要条件を説明してください。- 本番キーを使用するには、まず Portaly の決済審査(KYC)に合格する必要があります。 マーチャントが審査を完了するまでは、ダッシュボードにはテストの選択肢のみが表示され、本番を利用できない理由が説明されます。マーチャントはこのページの「決済審査」から審査を開始します。サーバー側でもこの条件が適用されるため、ダッシュボードを迂回する方法はありません。キーの作成は
403 PAYMENT_KYC_NOT_VERIFIEDを返します。 - 本番キーには有料メンバーシップも必要です — Portaly プレミアムまたは Portaly Vibe のサブスクリプションが必要です(
403 PREMIUM_REQUIRED)。無料プランでは、審査に合格しただけでは不十分です。先にアップグレードしてください。 - マーチャントが2つ目以降の商品を登録する場合、商品ごとに個別の審査が必要です(商品ごとのサービス URL と事業内容)。ユーザーが本人確認を済ませていても、この商品が未審査の場合、キーの作成は
403 PRODUCT_REVIEW_NOT_VERIFIEDを返します。本人確認をやり直すよう案内しないでください。その手続きは完了しています。ユーザーには、ダッシュボード(Payment > 決済審査)でこの商品を審査に提出し、承認を待つよう案内してください。 - 初めてインストールするユーザーは、通常まだ審査に合格していないため、本番キーを利用できません。 これは想定どおりであり、エラーではないことを伝えてください。
- まずテストキー(
pcs_test_…)を使うことを推奨してください。実際の請求を発生させずに、TapPay のサンドボックスを使って、設定、プラン、チェックアウト、コールバックなど、連携のほとんどをすぐに構築して試すことができます。ただし、すべてを検証できるわけではありません。テストで問題がなくても未検証のまま残る項目(更新処理、本番環境での 91APP へのリダイレクトと復帰、請求書発行、精算)については、上記のテストモードの箇条書きを参照してください。決済審査に合格したら、ダッシュボードに戻って本番キーを作成し、PORTALY_API_KEYをpcs_live_…の値に切り替えて本番環境で使用します。モードはキーから判定されるため、コードの変更は不要です。
- 本番キーを使用するには、まず Portaly の決済審査(KYC)に合格する必要があります。 マーチャントが審査を完了するまでは、ダッシュボードにはテストの選択肢のみが表示され、本番を利用できない理由が説明されます。マーチャントはこのページの「決済審査」から審査を開始します。サーバー側でもこの条件が適用されるため、ダッシュボードを迂回する方法はありません。キーの作成は
-
この手順は Portaly Payment ダッシュボードで人間のオペレーターが実行するものであり、サードパーティ連携コードが実行するものではないことを明確に伝えてください。
-
発行されたシークレット情報は安全に保管するようユーザーに伝えてください。ユーザーに代わって保管する場合は、適切なシークレットマネージャーまたは安全な環境変数ストアのみを使用してください。
-
API キーは API 呼び出しのベアラー認証に使用され、
callbackSecretは Portaly からのコールバックの真正性を検証するために使用されることを説明してください(ユーザーから尋ねられた場合)。 -
API キーや
callbackSecretをチャットに貼り付けるよう、ユーザーに求めてはいけません。 チャットの履歴はログに記録、キャッシュされたり、要約、差分、ツール呼び出しの引数でモデルから再表示されたりすることがあります。シークレットは、エージェントが平文で確認する必要のない値として扱ってください。 -
代わりに、人間のユーザー自身がエディターまたはシェルを使って、次のテンプレートに従いシークレットを
.envに設定するよう案内してください。PORTALY_API_KEY=pcs_live_xxx # or pcs_test_xxx for test mode PORTALY_CALLBACK_SECRET=xxx -
エージェントは実行時に
process.env.PORTALY_API_KEY(Node)またはos.environ["PORTALY_API_KEY"](Python)を通じてこれらを読み取ります。コンテキストにシークレットの実際の値を含める必要はありません。 -
プロジェクトでシークレットマネージャー(1Password CLI、Doppler、AWS/GCP Secrets Manager、Vault など)を使用している場合は、
.envよりもそちらを優先してください。 -
作業を続ける前に、
.gitignoreに.envが含まれていることを確認してください。.gitignoreが存在しない場合、または.envが含まれていない場合は、ただちに作成または更新してください。認証情報をバージョン管理にコミットすることは絶対に避けてください。 -
ユーザーが誤ってチャットにシークレットを貼り付けた場合は、使用前に Portaly Payment ダッシュボードでキーをローテーションするよう案内してください。貼り付けられた値は漏えいしたものとして扱ってください。
1.5 インストール済みスキルのバージョンを報告する
インストール済みのスキルが古くなったときに加盟店のダッシュボードで通知できるよう、このスキルのバージョンを Portaly に報告してください。これはブロックされない単発のバージョンチェックです。リクエスト本文に含まれるのはスキル名とバージョンのみで、ユーザーのプロジェクトやデータに関する情報は含まれません。ユーザーには一度だけ伝えてください(例:「インストール済みの Portaly スキルのバージョンを報告し、古いスキルをダッシュボードで検出できるようにしています」)。承認を求めて処理を一時停止する必要はありませんが、隠してはいけません。
送信するタイミング — process.env.PORTALY_API_KEY が設定されている場合、以下のうち先に発生したタイミングで、セッションごとに一度だけ送信してください。
- このスキルをインストールまたは更新した直後。環境にキーがすでに設定されている場合に限ります。
- それ以外の場合、Portaly API を初めて呼び出すとき(加盟店の設定、プランの一覧表示、チェックアウトセッションの作成など)。バージョン報告は、最初の実際の API 利用と同時に送信されます。
PORTALY_API_KEYがまだ環境に設定されていない場合は、今は報告をスキップしてください(後でケース 2 に該当したときに対応します)。この報告のためだけに、ユーザーにキーを求めてはいけません。- リクエスト:
POST https://portaly.ai/api/creator-subscription/skill-version Authorization: Bearer {PORTALY_API_KEY} Content-Type: application/json { "skillName": "portaly-payment", "version": "0.18.2" } versionは、このファイルの先頭にある frontmatter のmetadata.versionです。実際にインストールされているバージョンが報告されるよう、現在実行中の SKILL.md に記載されている値をそのまま使用してください。- リクエスト本文に含めるのは
skillNameとversionのみです。呼び出しに失敗した場合は無視して続行してください。処理がブロックされることはありません。 - 成功した場合は、レスポンスの
data.available配列を確認してください。ここには、この加盟店アカウントからバージョン報告が一度も送信されていないスキルが、{ id, installPackage, latestVersion, description }の形式で含まれています。これは未インストールという意味ではありません。サーバーがスキルの存在を認識するのは、そのスキル自身がバージョン報告を送信したときだけで、これはnpx skills addの実行時ではなく、初めて実際に使用されたときに行われます。そのため、すでにこのプロジェクトにあるものの、まだ使用されていないスキルもこの一覧に表示されます。何かを伝える前に、実際のプロジェクトを確認して自分で絞り込んでください。スキルのディレクトリやファイルがローカルにすでに存在する項目は除外します。サーバーから見えるのはプロジェクトのファイル構成ではなく、その確認ができるのはあなただけです。絞り込み後に何も残らなければ、何も伝えないでください。残った項目があれば、このセッションで一度だけ、追加できるスキルとしてユーザーに伝えてください(npx skills add ...)。不足しているスキルとして伝えてはいけません。各スキルの名前と、1 行のdescriptionを伝えてください。これは発見を目的とするものです。ユーザーから依頼されない限り、自分でnpx skills addを実行してはいけません。 - このプロジェクトに Portaly スキルが複数インストールされている場合、各スキルはそれぞれバージョン報告を送信し、同じ
available一覧を受け取ります。一覧の提示は、スキルごとではなくセッション全体で一度だけにしてください。このセッション中に自分または別の Portaly スキルがすでにavailable一覧を提示している場合は、この手順をスキップしてください。 data.availableが存在しない、空である、またはレスポンスの形式が一致しない場合は、何もしないでください。呼び出しの失敗と同様に無視して続行します。これによって処理がブロックされることはありません。
2. 加盟店の設定を行う
- エージェントは、Portaly Payment API キーを使った API 呼び出しで、これらのセットアップ作業を直接実行してください。
- 商品を公開する前に人間のユーザーが加盟店のブランディングを設定する必要がある場合は、Config API を使用してください。
- AI エージェントは人間のユーザーに
merchantLogo画像アセットを提供するよう依頼し、設定用の画像アップロード API を使って画像を Portaly にアップロードしてください。加盟店のロゴは任意です。ユーザーがすぐに用意できない場合は、この手順をスキップしてプランの作成に進んでください。 - Portaly Payment API キーを使い、
PUT /api/creator-subscription/configとPOST /api/creator-subscription/config/imagesで加盟店のブランディングを設定してください。
3. 有効なサブスクリプションプランを作成する
- エージェントは、Portaly Payment API キーを使って、API 呼び出しによりプランの作成、更新、プラン画像のアップロードを直接行う必要があります。
- 新しいプランを作成する前に、必ず現在の API キーを使って
GET /api/creator-subscription/plansを呼び出し、既存のプランを確認してください。 プランはライブモードとテストモードで共有されます。適切なプランがすでに存在する場合は、重複して作成せず、既存のプランを再利用してください。 - チェックアウトセッションを作成する前に、Portaly に少なくとも 1 つの有効なプランが必要です。
statusがactiveのプランに対してのみ支払いボタンを表示してください。アーカイブ済み(inactive)のプランのチェックアウトセッションは422 PLAN_INACTIVEで拒否されます。この場合は一般的な支払いエラーではなく、「このプランはご利用いただけなくなりました」という状態として適切に処理してください。references/api-contract.mdの「Session Creation」内にある「Error responses」表を参照してください。 - Plan API を使って、ユーザーが Portaly に掲載したい商品の基本情報を作成または更新してください。
- プラン名、説明、金額、通貨、請求期間(
monthly、yearly、またはone-time)、価格設定タイプ(fixedまたはdynamic)、ステータスが、意図する商品と一致していることを確認してください。 - 新しいプランでは、チェックアウト時に購入者の携帯電話番号が求められます(
collectPhoneのデフォルトはtrue)。番号がないと支払いは完了しません。この番号は完了コールバックのcustomerPhoneとして返され、クリエイターの注文一覧とエクスポートにも表示されます。必要かどうかをユーザーに確認してください。不要な場合は、collectPhone: falseを指定してプランを作成するか、後からPUT /plans/{planId}で無効にしてください。2026-09 より前に作成されたプランでは、クリエイターが有効にしない限り番号は求められません。 - 年間プランでは、売上の支払いが 12 か月にわたって繰り延べられます。購入者は年額全額を前払いしますが、クリエイターへの売上金は 12 回に分けて毎月(純収益の 1/12 ずつ)支払われます。年間注文の返金は、最初の分割払いが支払われた後はできません。年間プランを作成する前に、この条件をユーザーに説明してください。これはクリエイターの返金リスクを抑えますが、その時点以降、購入者は一切返金を受けられなくなります。
- ダイナミックプライシングのプランでは、
pricingTypeをdynamic、billingPeriodをone-timeに設定してください。金額はプランに設定せず、各チェックアウトセッションの作成時に呼び出し元がamountを渡します。 - サードパーティに独自の商品カタログがある場合は、Portaly の
planIdを、販売事業者の内部商品 ID または権利 ID とともに保存してください。 - AI エージェントはユーザーにプラン画像の提供を依頼し、プラン画像アップロード API を使ってその画像を Portaly にアップロードしてください。
- Portaly から返される
checkoutUrlを正式な URL として扱ってください。推測したドメインから再構築しないでください。 - プランの作成または更新後、レスポンスの
nameとdescriptionに文字化けがないか確認してください。文字化けしている場合は、シェルのエンコーディングを修正し、PUT /api/creator-subscription/plans/{planId}を使って訂正してください。「Guardrails」の Windows エンコーディングに関する注記を参照してください。
3.5 割引コードを作成する(任意)
- 少なくとも1つのプランが存在してから、Discount Code API を使用します。
- コードには ルール の配列を設定します。各ルールでは、独自の割引と適用期間を指定して、それぞれ異なるプランを対象にできます。例:コード
EARLYBIRDに2つのルールを設定します。月額プランは3サイクル(=3か月)にわたって50%割引、買い切りプランは1サイクルにわたってNT$200割引です。年額コードについては、ANNUAL20を参照してください。年額プランが1サイクル(=1年)にわたって20%割引になります。 - ルールごとに、ユーザーに次の内容を確認します。
- 割引タイプ:
fixed(TWD の割引)/percent(%割引)/free(100%割引)。 - 適用期間:
repeating N cycles(デフォルトは1)またはforever(通常はfixedと組み合わせます)。1サイクルは1回の請求期間に相当します。月額プランでは1か月、年額プランでは1年です。 - 適用対象:
all(特定のルールでカバーされていないプランに適用されるフォールバック)またはspecificの planIds(例:年額プランのみ)。1つのコードにつきallルールは最大1つです。planIds は複数のルールに重複して含めることはできません。
- 割引タイプ:
- コードレベルのパラメーター:
- カスタムコード:3~40文字、
[A-Z0-9_-]。保存時および表示時は UPPERCASE になります。入力時の照合では大文字と小文字を区別しません。プロフィールごとに一意で、作成後は変更できません。 - 利用可能期間:
redeemFrom/redeemBy。 - 上限:
maxRedemptions(合計)/maxRedemptionsPerCustomer(メールアドレスごと)。
- カスタムコード:3~40文字、
- コードは ライブモードとテストモード で共通です(プランと同様)。
- Portaly が購入者に代わってコードを選ぶことはありません。チェックアウトセッションで
discountCodeを渡すか、購入者がホスト型チェックアウトページでコードを入力した場合にのみ、割引が適用されます。紹介リンクの場合は、コードを独自アプリ内でユーザーに紐付けて保持し、チェックアウト時に渡してください(references/discount-code-examples.mdを参照)。 - プロンプトの例とパラメーター早見表については、
references/discount-code-examples.mdを参照してください。 - 金銭に関わる操作のガード:ライブモードで割引コードを作成するには、ユーザーの明示的な確認が必要です(ライブモードでのプラン作成と同じルールです)。
4. チェックアウトセッションを作成する
- 購入者が決済を開始する前に、チェックアウトセッションを作成します。
Authorization: Bearer {api_key}を指定してPOST /api/creator-subscription/checkout-sessionsを呼び出します。planIdと、任意のsuccessRedirectUrl、cancelRedirectUrl、callbackUrl、subscriptionCallbackUrl、merchantOrderNumber、および文字列キーのmetadataを送信します。- 購入者がすでに販売者独自の製品にサインインしている場合は、情報を再入力させないでください。
customerEmailとcustomerNameを送信してチェックアウトフォームに事前入力し、emailVerified: trueを指定して、販売者がそのメールアドレスをすでに確認済みであることを宣言します。これにより、メールで送信される確認コードが省略されます。emailVerifiedが受け付けられるのは、この API キー認証済みの呼び出しに限られます。購入者のブラウザーから送信してはいけません。また、空白以外の文字を含むcustomerEmailがない場合は無視されます。チェックアウトではメールアドレス欄が読み取り専用になります。フィールドの詳細なルールについては、references/api-contract.mdを参照してください。- カスタム
metadataキーは署名付きコールバック本文にエコーされます。独自のデータは、単一のtrackingキーの下に JSON 文字列として格納してください —metadata: { tracking: JSON.stringify({ … }) }— この形式はすべてのアダプターで検証されます。Python と Go の v1 アダプターは、コミット済みスキーマにない他のキーが含まれている場合、フェイルクローズします(v1 はキーを JavaScript のlocaleCompareでソートしますが、これらのアダプターでは任意のキーに対して同じ処理を再現できません)。また、trackingの値がオブジェクトの場合もフェイルクローズします。内部のキーも同様に検証されるため、文字列化してください。その他のカスタムキーには、Node/WebCrypto のレシーバーを使用してください。
- カスタム
callbackUrlにはcheckout.completedコールバックが送信されます。また、subscriptionCallbackUrlが設定されていない場合は、定期更新(payment.succeeded/payment.failed)とライフサイクルのコールバックも送信されます。更新やライフサイクルのイベントを専用エンドポイントに送信するには、subscriptionCallbackUrlを設定してください。- 任意の
discountCode:指定すると、Portaly が割引コードを事前に検証して適用します。無効なコードの場合は400 INVALID_DISCOUNT_CODEが返されます。 - 任意の
profitSharingId:製品で購入者向けプロモーションが有効になっている場合に、購入者が経由した紹介コードを指定します。独自の Cookie からサーバー側で読み取り、ここに渡してください。ブラウザーのリクエスト本文から受け付けてはいけません。そうしないと、誰でも他人の売上を自分のものとして申告できてしまいます。不明なコードや一致しないコードは無視され、チェックアウトはそのまま完了します。ただし、Cookie に値がない場合はこのフィールドを省略してください。このフィールドは 1〜64 文字である必要があるため、空文字列を指定すると無視されず400が返されます。プロモーション自体の設定にはportaly-affiliateスキルを使用してください。 sessionId、checkoutToken、checkoutUrl、expiresAtをサードパーティー側に保存します。- 販売者がコンバージョントラッキング(ステップ 10)を行う場合は、今のうちに独自の注文 ID を
successRedirectUrlに設定します。すべてのリダイレクト経路で維持される唯一のキーであり、後から追加する場合はセッションを再発行する必要があります。 - セッションのレスポンスには、指定した
discountCodeが適用された場合にappliedDiscountが含まれます。session.amountは常に、購入者への請求額である割引適用後の金額です。 - 購入者を
checkoutUrlにリダイレクトします。
5. Portaly にホスト型チェックアウトを実行させる
- サードパーティー側では、Portaly のホスト型チェックアウトをブラックボックスとして扱ってください。
- サードパーティーにカードトークンの収集や、Portaly が提供する決済手順の実装を求めてはいけません。
6. 結果を受け取る
- 外部での確認手段として主に使用するのは、
callbackUrlへの署名付きコールバックです。 - チェックアウト時のコールバックは2種類あります:初回の課金が成功したときの
creator_subscription.checkout.completedと、失敗したときのcreator_subscription.checkout.failedです(決済が拒否された場合、または購入者が91APPのページでキャンセルした場合)。両方を処理してください。.completedだけをリッスンするマーチャントは、支払いに失敗した購入者を把握できません。 - ホスト型チェックアウトの場合、
checkout.completedは Portaly がサブスクリプションと初回の注文を記録した後にのみ送信されるため、ハンドラーはコールバックのsessionIdを使ってすぐにGET /subscriptions/{sessionId}を呼び出したり、キャンセルや再開を行ったりできます。購入者への課金後に記録が失敗するまれなケースでも、マーチャントが支払いを把握できるようコールバックは送信されます。checkout.completedの直後にGET /subscriptions/{sessionId}が404を返す場合は、「表示されるまで再試行」するのではなく、「Portaly サポートに連絡」してください。 creator_subscription.checkout.failedには、sessionId、profileId、planId、planName、mode、amount、currency、customerEmail、failureReason、failedAt、metadataが含まれます。意図的にsubscriptionIdは含まれていません。初回課金に失敗するとサブスクリプションは作成されないため、識別子と冪等性キーの両方にsessionIdを使用してください。testモードのセッションでも送信されます(どのモードかはペイロードのmodeに示されます)。そのため、ハンドラーをデプロイすると、サンドボックスのエンドポイントにもcheckout.failedが届くようになります。checkout.failedは、完了しなかったチェックアウトに対する唯一のコールバックです。支払いの試行が失敗したときに送信されます。これには、購入者が91APPのページでキャンセルした場合も含まれます(一覧エンドポイントではpaymentCanceled: trueとして示されます)。購入者がタブを閉じた場合や、セッションを期限切れにした場合は何も送信されません。未完了のチェックアウトをまとめて取得するには、GET /api/creator-subscription/checkout-sessions?outcome=abandoned,failedを使用してください。ダッシュボードの「未完成結帳」はoutcome=abandonedです(outcome、startDate/endDateで絞り込み、pagination.hasMoreがtrueの間はページングを続けてください。ページの件数が少ない場合や、空の場合もあります)。単一セッションのGET /api/creator-subscription/checkout-sessions/{sessionId}は、確認するsessionIdがすでに分かっている場合にのみ使用してください。outcome: "abandoned"かつpaymentSubmitted: trueの一覧行は、購入者は支払いを送信したものの Portaly がコールバックを失ったことを意味します。そのレコードを照合し、再度マーケティングの対象にしないでください。- エンドポイントが受信できなかったチェックアウトのコールバックを再送するには、
POST /api/creator-subscription/checkout-sessions/{sessionId}/retry-callbackを使用します。初回課金に失敗した場合はセッションをキーとするルートを使用してください。サブスクリプションが存在しないため、/subscriptions/{id}/retry-callbackでは該当のセッションを見つけられません。 - 継続課金と返金でも署名付きコールバックが送信されます(署名と検証の方法はチェックアウトのコールバックと同じです)。
creator_subscription.payment.succeeded/.failedは更新時の課金を示し、creator_subscription.payment.refunded/.refund_failedは個々の支払い注文の最終的な結果を示します。返金イベントの重複排除にはsubscriptionIdではなくorderIdを使用します。ライフサイクルイベント(creator_subscription.active/.cancel_requested/.canceled)も同じ方法で配信されます。x-portaly-eventヘッダーを使って処理を切り替えてください。すべてのイベントとペイロードについてはreferences/api-contract.md→ Signed Callback を、継続課金の動作についてはreferences/checkout-and-renewal.mdを参照してください。 - 手動の
POST /api/creator-subscription/checkout-sessions/{sessionId}/completeは、ユーザーがホスト型ではないフローや復旧フローを構築している場合の例外的なフローとしてのみ使用してください。この操作で行われるのは、セッションをcompleted/failedとしてマークし、割引コードの利用を記録し、checkout.completed/checkout.failedを送信することだけです。サブスクリプション、支払い記録、注文、請求書は作成されません。GET /subscriptions/{sessionId}は404を返し、継続課金も行われず、マーチャントの Portaly 売上や支払いには反映されず、電子請求書も発行されません。停止しているように見えるホスト型チェックアウトを「完了」させるために、決して使用しないでください。代わりにセッションの状態を確認してください。 - 現在の実装契約:
subscriptionId === checkoutSessionId === sessionId。 - 継続課金のチェックアウトが成功した場合、人間のユーザーのシステムでは、後続のキャンセルまたは再開 API 呼び出しに、コールバックの
sessionIdをそのままsubscriptionIdとして使用できます。 - これは現在の Portaly の実装契約であることを人間のユーザーにはっきり伝え、チェックアウト完了後にそのユーザー側で永続化する必要があることも明示してください。
7. 検証して永続化する
- コードを生成する前に、リポジトリの言語、フレームワーク、サーバー/エッジのランタイム、ボディーパーサー、および既存の検証方法を確認してください。
references/callback-signature-v1.mdを読み込み、該当するNode、WebCrypto、Python、またはGoのアダプターを選択してください。 - リリース前に、そのランタイムで
scripts/check_callback_vectors.mjsを実行してください。自分で生成した署名の検証に成功するだけでは不十分です。期待値は、コミット済みのPortaly本番署名ツールに基づいています。 - 3つすべてのコールバックヘッダーを必須にしてください。
x-portaly-timestampのISO文字列をそのまま使用し、無効な場合、または現在時刻との差が前後いずれかに5分を超える場合は拒否してください。この対称的な許容範囲によって、通常のクロックずれに対応できます。「未来のタイムスタンプはすべて拒否する」という厳格なルールでは、正当なコールバックが断続的に失敗する可能性があります。 - APIキーの
callbackSecretでx-portaly-signatureを検証した後、認証済みボディーのeventがx-portaly-eventと一致することを必須にしてください。 - V1では、生のHTTPボディーではなく
stableJson(JSON.parse(wireBody))に署名します。JavaScriptのlocaleCompareの仕様を、コードポイントによるキーソートで代用しないでください。 - 検証後、アプリケーションのデータポリシーで許可される最小限の監査フィールドを永続化してください。対象は、
sessionId、存在する場合はsubscriptionId、merchantOrderNumber、決済の識別情報、イベント、ステータスです。シークレットや署名ベース全体はログに記録しないでください。 - コールバックペイロードに
subscriptionIdが含まれない場合は、現在の実装ではsessionIdをsubscriptionIdとして使用しているため、定期購入の識別子としてsessionIdを永続化してください。 - イベントごとに冪等性を設定してください。チェックアウト完了には
event + sessionId、更新成功にはevent + subscriptionId + chargedAt、更新失敗にはevent + subscriptionId + failedAt、返金の成功/失敗にはevent + orderIdを使用します。更新のキーにpaymentIdやpaymentReferenceを使用しないでください。payment.failedにはpaymentId自体が含まれず、また91APPのほぼすべての失敗ではpaymentReferenceが空文字列です。そのため、どちらを使用しても、すべての加入者における更新失敗が1つのキーにまとめられてしまいます。chargedAt/failedAtは試行ごとのタイムスタンプであり、再配信時にもバイト単位で同一の値が維持されます。すべてのライフサイクルイベントをsessionId/subscriptionIdで恒久的に重複排除しないでください。現在のライフサイクルペイロードには、文書化された配信識別子がありません。状態の割り当てを冪等にし、より強力な重複排除の要件は製品仕様上の課題として明示してください。 - **
callbackUrlにはHTTPSを使用してください。**平文HTTPで配信すると、通信中にcallbackSecretの署名とペイロードが漏えいします。
8. 定期購入を管理する
- キャンセルまたは再開に対応するのは、
billingPeriod = monthly | yearlyの定期購入プランのみです。 - キャンセルとは、次回以降の定期決済を停止することです。返金ではありません。システムでは、関連する権利やコンテンツを、定期購入レコードの
cancelEffectiveAtで示される現在の支払い期間終了まで有効にしておく必要があります。 - 年間定期購入をキャンセルしても、まだ支払われていない残額分は返金されません。クリエイターは、当初の12か月のスケジュールに従って残りの月次分割払いを受け取り、購入者は
cancelEffectiveAtまでアクセスできます。つまり、次回の年間更新日以降は課金されません。 - Portalyでは現在、APIキー認証エンドポイントを通じた、販売者システムから開始する定期購入のライフサイクル操作に対応しています。
- これらの呼び出しには、同じPortaly Payment APIキーを使用してください。
定期購入管理API:
GET /api/creator-subscription/subscriptions— ページネーションとフィルタリングを使用して、すべての定期購入を一覧表示しますGET /api/creator-subscription/subscriptions/{subscriptionId}POST /api/creator-subscription/subscriptions/{subscriptionId}/cancelPOST /api/creator-subscription/subscriptions/{subscriptionId}/resume
注文照会API:
GET /api/creator-subscription/orders— 支払い/注文記録を一覧表示します。startDate/endDate、status(複数指定の場合はカンマ区切り)、planIdで絞り込めます。また、カーソルによるページネーションに対応しています。日付フィルターの対象はcreatedAtです。これらの注文ではcreatedAt === paidAtのため、支払い期間の照合にはこのエンドポイントを使用しますGET /api/creator-subscription/orders/{orderId}— リスト全体を調べることなく、1件の注文のrefundRequestedAt、refundedAt、refundFailedAt、refundFailureReasonをポーリングしますPOST /api/creator-subscription/orders/{orderId}/refund— ライブ環境用のフルスコープキーで全額返金をリクエストします。本文:{ "reason": "customer_requested", "reasonNote": "optional", "amount": 400 }。API キーを使用する場合、reasonは必須で、amountには注文の全額のみ指定できます。新規リクエストは202を返し、すでに完了している、または処理中のリクエストは200を返します。テストキーでは409 TEST_MODE_REFUND_UNSUPPORTED、インテグレーションスコープのキーでは403 KEY_SCOPE_FORBIDDENが返されます。
202の後は、creator_subscription.payment.refundedまたは.refund_failedを処理し、照合時のフォールバックとしてGET /orders/{orderId}を使用してください。TapPayの返金が遅延すると、最大3回の日次スケジュール実行まで保留状態になる場合があるため、202から最終結果が判明するまで約3日かかることがあります。最終結果を示すタイムスタンプが両方ともnullの間はポーリングを続けてください。refundFailedAtが設定された場合、または再試行期間を過ぎてもどちらの最終結果も確認できない場合は、Portaly サポートにお問い合わせください。返金とは別にcreator_subscription.canceledが発生する場合があります。イベントの順序は保証されないため、ペイロードのタイムスタンプで並べ替え、キャンセルイベントはsubscriptionId、返金結果はorderIdで重複を除去してください。
継続課金の管理ルール:
- これらの API では
Authorization: Bearer {api_key}のみ使用できます - マーチャントシステムとのインテグレーションでは Firebase 認証を使用しないでください
billingPeriod = one-timeではキャンセルと再開はサポートされません- サブスクリプションの
amountは基本価格であり、支払い記録ではありません。 チェックアウト時に固定され、その金額に基づいて更新時の請求が行われます。割引が適用されたサブスクリプションには、discountのスナップショット(code、appliedRule、startedAt、endsAt—nullは無期限、source、およびこれらが記録されるようになった後に作成されたサブスクリプションではoriginalAmount/finalAmount)が含まれます。割引が有効な間は、amountより低い金額が請求されます。更新分との照合には、サブスクリプションのamountではなく、更新コールバックのamountまたは注文記録を使用してください。 cancelはサブスクリプションをcancelAtPeriodEnd = trueに設定しますresumeは、サブスクリプションが完全にcanceledになる前にのみ機能します
キャンセルリクエストの本文:
{
"reason": "customer_requested",
"reasonNote": "optional note"
}
再開リクエストの本文:
{}
継続課金のライフサイクルで保存する項目:
subscriptionIdsessionIdplanIdbillingPeriodstatuscancelAtPeriodEndcancelEffectiveAt
9. 購読者向けセルフサービスポータルを有効にする(任意)
- 購読者自身がサブスクリプションを直接管理できるようにする場合に使用します。
- マーチャントのバックエンドが
https://portaly.ai上のPOST /api/creator-subscription/portal-sessionsを使ってポータルセッションを作成し、返されたportalUrlに購読者をリダイレクトします。 - これはサーバー間の呼び出しです。API キーをクライアントに公開してはいけません。
- 購読者は、セッショントークンによってすでに認証された状態で、Portaly がホストするポータルページに移動します。追加のログインは不要です。
- ポータルでは、購読者はサブスクリプションの表示、キャンセル、再開、および支払い履歴の確認ができます。
- ポータルセッションの有効期限は30分です。
- 購読者がサブスクリプションの管理後に戻れるよう、マーチャントは
returnUrlを指定する必要があります。 - エンドポイントの詳細とコード例は、
references/api-contract.mdのPortal Session (Subscriber Self-Service)を参照してください。
10. コンバージョン計測を接続する(任意)
- 加盟店から GA4、Google Ads、Meta Pixel、UTM アトリビューション、または「決済ページに自分のアナリティクスを設置できますか」と尋ねられた場合に使います。
- Portaly は、加盟店から提供された GA4、GTM、Meta Pixel のタグをホスト型チェックアウトに挿入しません。また、仮にタグを設置できたとしても、加盟店が求める情報は得られません。
utm_*パラメーターは加盟店自身のサイトで取得済みであり、portaly.aiには渡されません。Meta の_fbcCookie は加盟店のドメインを対象とするファーストパーティ Cookie であり、Portaly からは読み取れません。さらに、更新、返金、決済失敗はブラウザー上では発生しません。この点を伝え、機能不足と受け取られるのではなく、適切な方法を案内してください。 - 加盟店は通常求めるデータポイント4つのうち、すでに3つを持っています。
merchantOrderNumberとplanIdは加盟店自身が設定した値であり、amount/currencyはコールバックで返されます。対応が必要なのはキャンペーンのアトリビューションだけで、これは加盟店側だけで処理できます。 - 加盟店が見落としがちな必須設定: GA4 の除外する参照リストに
portaly.aiを追加してください(管理 → データの収集と修正 → データ ストリーム → ウェブ → タグ設定を行う → すべて表示 → 除外する参照のリスト)。これを設定しないと、再開されたセッションはportaly.ai / referralにアトリビューションされ、キャンペーン情報が失われます。必ず、毎回最初に伝えてください。 - 加盟店自身のサンクスページで
purchaseを発火させます。同一オリジンなので_gaCookie とセッションのキャンペーン情報が保持され、追加作業なしで GA4 に正しくアトリビューションされます。クロスドメインリンカーは不要です。これは決済ページに加盟店のタグがないからこそ成り立ちます。これが正確な方法ではありますが、完全ではありません。購入者は支払い後に Portaly から遷移してサンクスページを表示する必要があるため、タブを閉じた購入者については発火しません。必ずコールバックと併用してください。セッション作成時に独自の注文 ID をsuccessRedirectUrlに設定し、ここでその ID を使って注文を検索し、ほかの値はすべてそのレコードから取得します。Portaly は独自のパラメーターを追加しますが、表示されるパラメーターは決済経路によって異なるため、どれも仕様として依存できません。 - サンクスページに戻らない購入者、ならびにクライアント側タグでは取得できない更新や返金については、署名済みコールバックからサーバー側で発火させます。コールバックの
customerEmailを使えば、追加の設定なしで Meta の Conversions API に照合キーを渡せます。ただし、ハッシュ化してください。emフィールドには、トリミングして小文字に変換したアドレスの SHA-256 を設定し、平文は絶対に使わないでください。 - 2種類の ID を混同しないでください。 独自の冪等性キーにはステップ7のキーを使います。再配信をまたいで安定し、発生ごとに異なるキーです。Meta の
event_idは、サーバーイベントとブラウザーイベントを同一の購入として Meta に認識させるためのものです。ブラウザーイベントが存在するのは初回のチェックアウトだけなので、加盟店自身の注文レコードから読み取ったsessionIdを使います。請求ごとに異なるevent_idを割り当ててください(payment.succeededではpaymentId)。Meta はイベントの発生ごとに一意の ID を求めます。また、subscriptionId === sessionIdであるため、sessionIdを再利用すると、すべての更新で同じ値になってしまいます。 - 更新の冪等性キーには、試行ごとのタイムスタンプを使ってください。
payment.failedにはpaymentIdがなく、91APP の失敗ではほぼ毎回paymentReferenceが空文字列です。どちらを使っても、すべての購読者にわたる失敗した更新が同じキーにまとめられ、督促処理が気付かれないまま停止します。failureCountは成功時にリセットされるため使わず、payment.failedにはevent + subscriptionId + failedAtを、payment.succeededにはchargedAtを使ってください(payment.succeededには使用可能なpaymentIdが含まれます。ID がないのは失敗側だけです)。 - 更新時の
merchantOrderNumberには注意が必要です。 値は含まれていますが、チェックアウト時の値のまま変わりません。そのため、GA4 のtransaction_idに使うと、最初の更新以降はすべて重複として処理されます。請求ごとに異なる ID を生成してください。また、空のtransaction_idは絶対に送らないでください。すべての購入が1件にまとめられてしまいます。 - 広告識別子は加盟店自身のストアに保存するか、
metadataのtrackingの下に格納してください。独立したmetadataキーとしては使わないでください。 最初のランディング時にutm_*/gclid/fbclidを取得し、GA4 の ID は_ga_*Cookie を解析するのではなく、gtag('get', …)で読み取ってください(Google は Cookie の形式をドキュメント化しておらず、2025 年に変更しています)。その後、create-session から返されたsessionIdに紐づけてレコードを保存し、コールバックで照合するか(merchantOrderNumberは任意であり、checkout.failedには含まれないため、信頼できる照合キーではありません)、metadata: { tracking: JSON.stringify({ utm_source, gclid, … }) }を送信します。trackingは独自データ用に予約されたキーで、コールバックのベクトルに含まれているため、値が文字列であればすべてのアダプターで検証に通ります(オブジェクトを設定すると、その内部キーも検査され、拒否されます)。このリストが規定するのはキーであって値ではないため、JSON 文字列を設定すれば、リストを拡張することなく任意の構造を保持できます。サブスクリプションでは、ストアに保存して照合する方法を優先してください。metadataはサブスクリプションの期間中、更新やライフサイクルイベントのたびに再送されるためです。サンクスページでは、URL に含めた独自の注文 ID でレコードを取得してください。 - 広告識別子を独立した
metadataキーとして絶対に設定しないでください。clientId、client_id、fbp、fbc、session_id、utm_source、gclid、fbclidは、いずれも署名検証用に確定したホワイトリストに含まれていません。そのため、これらのいずれかを設定すると、Python または Go の受信側でそのサブスクリプションのコールバックが 401 になります。また、metadataは更新や返金のたびに再送されるため、サブスクリプションの期間中ずっと照合できなくなります。campaignやsourceのような大まかなタグはリストに含まれており、安全に使えます。 - セッション維持の条件とその Google の参照元、サンクスページのスニペット、イベントごとの ID の表、および実際に安全に使える
metadataキーについては、references/conversion-tracking.mdを読み込んでください。
推奨する回答の形式
このスキルを使用する場合は、次の順序を優先してください。
- 目標の概要
- 人間が行うセットアップ手順
- API の一覧
- リクエストのフィールド
- レスポンスのフィールド
- コールバックの処理手順
- サンプルコード
- トラブルシューティングの注意事項
ガードレール
- 開発では、デフォルトでテストモードを使用してください。 読み込まれたキーが
pcs_live_で始まる場合、API を呼び出す前に、ライブモードでの実行を意図しているか人間のユーザーに確認してください。本番環境の課金に対して、確認なしに実行してはいけません。 - 金銭が動く操作には、ユーザーの明示的な確認が必要です。 次のいずれかを呼び出す前に、実行する操作、対象(
subscriptionId/sessionId)、モード(ライブ/テスト)を明確に伝え、ユーザーの「はい」を待ってください。POST /subscriptions/{id}/cancelPOST /subscriptions/{id}/resumePOST /checkout-sessions/{id}/complete(手動完了)- ライブモードでのプラン作成/更新
- ユーザーごとの確認を行わず、これらの操作を複数のサブスクリプションに対してまとめて実行したり、ループで実行したりしないでください。
- 可能な限り、ホステッドチェックアウトフローを優先してください。このフローでは、メールアドレスの確認、支払い方法の永続化、コールバックのディスパッチ、サブスクリプションの作成、支払いの作成、請求書タスクの作成、注文ブリッジへの書き込みがすでに処理されます。
- 次の項目は明確に区別してください。
- エージェントが Portaly Payment API キーを使って直接呼び出せるセットアップ API
- プロバイダーの動作をでっち上げないでください。TapPay と 91APP では、動作に実質的な違いがあります。
statusと検証済みの署名を確認せずに、コールバックが配信されたことだけを成功と判断しないでください。- リダイレクト先の成功ページだけを根拠に、サブスクリプションの状態を判断しないでください。リダイレクトは UX 上のものであり、正しい状態はコールバックまたはステータスクエリで確認してください。
references/checkout-and-renewal.mdは API 以外の参考資料として扱ってください。定期課金、出金、請求書のフォローアップ、注文ブリッジの動作にタスクが明示的に関係する場合に限り、読み込んでください。- Windows の文字エンコーディング: Windows では、非 ASCII 文字を含む API 呼び出しの前に
chcp 65001(cmd)または$OutputEncoding = [System.Text.Encoding]::UTF8(PowerShell)を実行してください。プランのnameまたはdescriptionが文字化けして返された場合は、文字エンコーディングを修正し、正しい値をPUTしてください。 - レート制限:
POST /checkout-sessionsを除く、すべてのクリエイターサブスクリプション API エンドポイントにはレート制限があります。読み取りエンドポイントは 1 分あたり 120 リクエスト、書き込みエンドポイントは 1 分あたり 20 リクエストが上限です。429レスポンスを受け取った場合は、Retry-Afterヘッダーに従って再試行をスケジュールしてください。大量の結果をページネーションで取得する場合は、レート制限の枠に注意してください。
成果物
このスキルを使用する場合は、次のうち 1 つ以上を返すようにしてください。
- 人間のユーザー向けの、最小限のステップごとの統合計画
- 関連 API の一覧
- リクエストおよびレスポンスのフィールドの説明
- ユーザーの技術スタックに合わせたコールバック検証コード
curl、fetch、または TypeScript のサンプルスニペット- セッションのステータス別に整理したトラブルシューティング項目
リソース
references/api-contract.mdベアラー認証、エンドポイントの契約、コールバックヘッダー、ペイロードのフィールド、サードパーティ実装の構成に使用します。references/checkout-and-renewal.md高レベルなチェックアウトのライフサイクルと更新の動作に関する任意の背景情報としてのみ使用します。references/discount-code-examples.mdDiscount Code API のプロンプト例、パラメーターの早見表、紹介リンクの処理について説明します。references/callback-signature-v1.mdランタイムのルーティング、正確な v1 契約、安全なハンドラーの順序、フェイルクローズの境界、診断のガイダンスについて説明します。references/conversion-tracking.mdチェックアウトのリダイレクトをまたいだ GA4 / Meta のコンバージョントラッキングについて説明します。決済ページにマーチャントタグがない理由、必須の不要な参照元の設定、サクセスページとコールバック側のイベント、Measurement Protocol / Conversions API に関する注意事項が含まれます。references/callback-signature-v1-vectors.jsonコミット済みの本番契約で生成された合成ペイロードと署名です。自分で署名・検証するフィクスチャの代わりに使用してください。scripts/check_callback_vectors.mjs選択した Node、WebCrypto、Python、または Go のアダプターを、コミット済みの成功、失敗、フェイルクローズのケースに対して実行します。scripts/sign_callback.pyコミット済みのコールバックキーのドメインに対応する Python アダプターです。任意のメタデータキーやサポートされていない数値に対しては、フェイルクローズします。scripts/sign_callback.mjsNode.js、JavaScript、TypeScript、Express、または Next.js との統合では、こちらを優先してください。scripts/sign_callback.webcrypto.mjsnode:cryptoをインポートできないエッジ / WebCrypto ランタイム(Cloudflare/Vercel Edge、Deno、InsForge のエッジ関数)で使用します。同じ方式とバイト単位で一致するstableJsonを使用し、グローバルのcrypto.subtleで検証します。scripts/verify_callback.goとscripts/verify_callback_test.goGo アダプターと、本番環境に基づくテストおよびフェイルクローズのテストです。../portaly-affiliate/SKILL.mdマーチャントが自社の購入者に他の人を紹介してもらい、コミッションを得てもらいたい場合に読んでください。ここで設定するプランとチェックアウトセッションを基盤として、セッション作成にフィールドを1つ追加します。