mcpField
P
portaly-payment

portaly-payment

github.com/portaly-ai開発2325 回インストール6 日前に更新
リポジトリ

portaly-payment について

Portaly Payment の導入を支援する AI エージェント向けスキルです。API キーの準備からチェックアウト後のコールバック処理まで案内し、テスト・本番モード、サブスクリプション API、署名検証を扱います。

主な機能

  1. 01マーチャント設定とサブスクリプションプランの作成
  2. 02チェックアウトセッション作成とコールバック処理
  3. 03テストモードと本番モードの違い
  4. 04サブスクリプションのキャンセル、再開、ポータル API
  5. 05プロジェクトの技術スタックに応じた署名検証

活用シーン

  1. 01既存アプリへの Portaly チェックアウト導入
  2. 02決済コールバック処理のテスト
  3. 03サブスクリプションのキャンセルと再開の実装
  4. 04API キーモードやコールバック署名の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/portaly-ai/portaly-skills --skill portaly-payment

インストール後、Claude Code で/portaly-paymentを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
api-contract.md
callback-signature-v1-vectors.json
callback-signature-v1.md
checkout-and-renewal.md
conversion-tracking.md
discount-code-examples.md
scripts/
check_callback_vectors.mjs
go.mod
sign_callback.mjs
sign_callback.py
sign_callback.webcrypto.mjs
verify_callback_test.go
verify_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 つの条件がすべて満たされたら、ダッシュボードに戻って本番環境用の本番用キーを作成できます。
  1. 人間のユーザーが何を構築しようとしているか確認します。 次のような決済連携タスクに備えます。
    1. 加盟店設定を作成する
    2. サブスクリプションプランを作成する
    3. 加盟店またはプランの画像をアップロードする(必要に応じて、エージェントは人間のユーザーに画像素材の提供を依頼してください)
  2. セットアップ後、チェックアウトセッションの作成とコールバック処理を既存のシステムに組み込みます。
    1. 購入者が決済を開始する前にチェックアウトセッションを作成する
    2. 購入者を Portaly のチェックアウトにリダイレクトする
    3. チェックアウト完了後、Portaly からのコールバックを検証して処理する
    4. サブスクリプションのライフサイクル管理が必要な場合は、定期プランのキャンセル API と再開 API も組み込む
    5. 購読者向けセルフサービス(購読者が自分のサブスクリプションを管理できるようにすること)が必要な場合は、ポータルセッション API も組み込む
  3. references/api-contract.md から始めます。 エンドポイント一覧、認証、リクエスト本文、レスポンス本文、コールバックヘッダーの確認に使用します。
  4. コールバック受信側を新規作成または修正する前に、リポジトリの言語、フレームワーク、ランタイムを確認し、references/callback-signature-v1.md を読み込んでください。 対応する同梱アダプターを選び、本番環境由来のテストベクトルを実行します。一覧にないランタイムの場合は、文書化されたサーバー側ブリッジを使用するか、ネイティブ実装がテストベクトルに合格するまで連携を保留してください。Node の署名処理を記憶に頼って翻訳してはいけません。
  5. 必要な場合にのみ references/checkout-and-renewal.md を読み込みます。 人間のユーザーから、チェックアウト後の課金、更新、出金、請求書、またはブリッジ注文の動作について質問された場合に限り、補足資料として使用します。
  6. 実装にすぐ使える形式で出力します。 番号付きの手順、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 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 が設定されている場合、以下のうち先に発生したタイミングで、セッションごとに一度だけ送信してください。

  1. このスキルをインストールまたは更新した直後。環境にキーがすでに設定されている場合に限ります。
  2. それ以外の場合、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(メールアドレスごと)。
  • コードは ライブモードとテストモード で共通です(プランと同様)。
  • 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}/cancel
  • POST /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"
}

再開リクエストの本文:

{}

継続課金のライフサイクルで保存する項目:

  • subscriptionId
  • sessionId
  • planId
  • billingPeriod
  • status
  • cancelAtPeriodEnd
  • cancelEffectiveAt
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 の _fbc Cookie は加盟店のドメインを対象とするファーストパーティ Cookie であり、Portaly からは読み取れません。さらに、更新、返金、決済失敗はブラウザー上では発生しません。この点を伝え、機能不足と受け取られるのではなく、適切な方法を案内してください。
  • 加盟店は通常求めるデータポイント4つのうち、すでに3つを持っています。merchantOrderNumber と planId は加盟店自身が設定した値であり、amount/currency はコールバックで返されます。対応が必要なのはキャンペーンのアトリビューションだけで、これは加盟店側だけで処理できます。
  • 加盟店が見落としがちな必須設定: GA4 の除外する参照リストに portaly.ai を追加してください(管理 → データの収集と修正 → データ ストリーム → ウェブ → タグ設定を行う → すべて表示 → 除外する参照のリスト)。これを設定しないと、再開されたセッションは portaly.ai / referral にアトリビューションされ、キャンペーン情報が失われます。必ず、毎回最初に伝えてください。
  • 加盟店自身のサンクスページで purchase を発火させます。同一オリジンなので _ga Cookie とセッションのキャンペーン情報が保持され、追加作業なしで 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 を読み込んでください。

推奨する回答の形式

このスキルを使用する場合は、次の順序を優先してください。

  1. 目標の概要
  2. 人間が行うセットアップ手順
  3. API の一覧
  4. リクエストのフィールド
  5. レスポンスのフィールド
  6. コールバックの処理手順
  7. サンプルコード
  8. トラブルシューティングの注意事項

ガードレール

  • 開発では、デフォルトでテストモードを使用してください。 読み込まれたキーが pcs_live_ で始まる場合、API を呼び出す前に、ライブモードでの実行を意図しているか人間のユーザーに確認してください。本番環境の課金に対して、確認なしに実行してはいけません。
  • 金銭が動く操作には、ユーザーの明示的な確認が必要です。 次のいずれかを呼び出す前に、実行する操作、対象(subscriptionId / sessionId)、モード(ライブ/テスト)を明確に伝え、ユーザーの「はい」を待ってください。
    • POST /subscriptions/{id}/cancel
    • POST /subscriptions/{id}/resume
    • POST /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.md Discount 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.mjs Node.js、JavaScript、TypeScript、Express、または Next.js との統合では、こちらを優先してください。
  • scripts/sign_callback.webcrypto.mjs node:crypto をインポートできないエッジ / WebCrypto ランタイム(Cloudflare/Vercel Edge、Deno、InsForge のエッジ関数)で使用します。同じ方式とバイト単位で一致する stableJson を使用し、グローバルの crypto.subtle で検証します。
  • scripts/verify_callback.go と scripts/verify_callback_test.go Go アダプターと、本番環境に基づくテストおよびフェイルクローズのテストです。
  • ../portaly-affiliate/SKILL.md マーチャントが自社の購入者に他の人を紹介してもらい、コミッションを得てもらいたい場合に読んでください。ここで設定するプランとチェックアウトセッションを基盤として、セッション作成にフィールドを1つ追加します。

コメント