ガイドと洞察

冪等パートナー API の自動化: 重複した副作用を発生させずに AI 顧客、キー、クレジットをプロビジョニング

パートナー API の自動化は、タイムアウト、Webhook イベントの重複、同時ワーカー、金額解析ミスなどにより、最初のリクエスト後に最も頻繁に失敗します。永続的な操作、安定した冪等性キー、正確な 10 進数の処理、および調整を中心としたプロビジョニングとクレジットのワークフローを構築します。

サインアップ ワーカーが顧客グループを作成すると、HTTP リクエストがタイムアウトになり、ジョブ ランナーが新しいリクエストで再試行します。同じ顧客が 2 つのグループ、2 つの API キー、または間違った上流オブジェクトを指すローカル データベース レコードを持っている可能性があります。 Webhook ハンドラーは各配信を新しいビジネス イベントとして扱うため、支払い Webhook は 1 分後に到着し、2 回配信され、顧客に 2 回クレジットされます。

これが パートナー API 自動化 における本当の障害モードです。最初の呼び出しが成功することが難しい部分であることはほとんどありません。難しいのは、ネットワークに障害が発生し、ワーカーがクラッシュし、ユーザーがダブルクリックし、決済プロバイダーが Webhook を再試行し、後で財務データを調整する必要がある場合でも、ビジネスの意図を維持することです。

実際のパターンはシンプルです。変化するすべてのパートナー API アクションを、ファイアアンドフォーゲット HTTP リクエストとしてではなく、永続的なビジネス操作として扱います。つまり、ローカル操作記録を保存し、冪等キーを意図的に使用し、資金を正確に解析し、Webhook を非同期に処理し、補償変更を発行する前に未知の結果を調整することを意味します。

個別の事実、推奨事項、予測

事実

Model Gate のパートナー API のドキュメントには、POST、PATCH、DELETE リクエストには Idempotency-Key が必要であること、タイムアウト後の再試行では同じキーを再利用する必要があること、べき等レコードは 7 日間保持されることが記載されています。

同じドキュメントには、金額と制限は JSON 10 進文字列であると記載されています。これらは、バイナリ浮動小数点型を通じて変換されるのではなく、正確な 10 進数値または文字列として処理される必要があります。

パートナー API は、残高、監査イベント、グループ、キー、リクエスト、トランザクションの管理およびレポート機能を公開します。監査イベントは、リクエスト ID、アクション、ターゲット、ソース IP、ステータス、安全なメタデータ、UTC タイムスタンプなどのフィールドを使用して、成功した管理変更を記録します。

Stripe では、作成操作と更新操作を安全に再試行する方法として冪等キーを文書化しています。 Webhook ガイダンスでは、エンドポイントが同じイベントを複数回受信する可能性があることも警告し、処理されたイベント ID をログに記録し、非同期で処理することを推奨しています。

AWS と Azure のガイダンスは、同じ分散システム ルールを強化しています。再試行は便利ですが、サーバーが呼び出し元の意図を保持できるように、変更操作には呼び出し元が提供するリクエスト ID または同等の反復性コントラクトが必要です。

推奨事項

プロビジョニング、キーの作成、支出制限の変更、クレジットの補充、ウォレットのチェック、Webhook 主導のフルフィルメントに 1 つのローカル運用台帳を使用します。台帳を、インテント、試行、アップストリーム リクエスト ID、結果のターゲット ID、および調整状態に関する統合の永続的な信頼できる情報源にします。

インテントが安定している安定したビジネス インテントから冪等キーを生成します。タイムアウトまたはサーバー結果が不明な場合は、同じキーを再利用します。ビジネス運営が意図的に新しい場合にのみ、新しいキーを生成します。

Webhook は 2 つのフェーズで処理されます。イベント ID を迅速に検証して永続化し、冪等ワーカーを通じてビジネス アクションを非同期に実行します。

予測

AI アクセスを再販する代理店や SaaS プラットフォームが増えるにつれ、サポートの問題は基本的な API 接続から調整へと移行していきます。つまり、顧客プロビジョニングの重複、クレジットの紛争、ウォレット残高の不一致、不明確な監査証跡などです。永続的なローカル操作記録を保持する統合は、HTTP の応答とログのみに依存する統合よりもサポートが容易になります。

ローカル パートナー業務台帳を作成する

オペレーション台帳は、最初のパートナー API リクエストが送信される前にビジネス オペレーションを記録します。これは、追加しやすく、顧客によるクエリが可能であり、2 人のワーカーが同じ操作を同時に実行できないように十分厳密である必要があります。

便利なスキーマは次のようになります:

partner_operations
- operation_id              // internal UUID
- external_customer_id      // your customer, tenant, or account ID
- action                    // create_group, create_key, set_limit, top_up_credit
- idempotency_key           // sent to Partner API for mutating requests
- request_fingerprint       // canonical hash of method, path, and meaningful body
- model_gate_request_id     // X-Request-ID or equivalent response identifier when available
- target_public_id          // group ID, key ID, transaction ID, or other resulting object
- status                    // pending, succeeded, failed_retryable, failed_final, reconciling
- attempt_count
- last_error_code
- last_error_message
- created_at
- updated_at
- locked_until

重要な制約は、ビジネス目的による一意性です。たとえば、external_customer_id + action + signup_version は初期プロビジョニングでは一意にすることができます。 2 回目の意図的な補充は、最初の補充と衝突してはなりません。異なるオペレーション ID と冪等キーを持つ必要があります。

サインアップ フローの場合は、provision_customer などの単一の親オペレーションを作成してから、create_group、create_key、set_initial_limit の子オペレーションを追跡します。これにより、バックエンドがどの外部ミューテーションがスタックしているかを正確に把握しながら、UI は顧客向けの 1 つのステータスを表示できるようになります。

ビジネス目的から冪等キーを構築する

冪等性キーは、再試行に耐えられるほど安定しており、2 つの異なる操作が 1 つに集約されるのを避けるのに十分な具体性を持っている必要があります。決定論的な形式は、サポート チームと調整チームがシステムについて推論するのに役立ちます。

create-group-for-customer:{customer_id}:{signup_version}
create-key-for-customer:{customer_id}:{group_id}:{key_purpose}:{version}
set-spend-limit:{customer_id}:{group_id}:{limit_policy_version}
top-up:{customer_id}:{payment_event_id}:{ledger_entry_id}

操作が同じで前の結果が不明な場合は、同じ冪等キーを使用します。例には、クライアントのタイムアウト、リクエスト本文の送信後の接続のリセット、レスポンスを保存する前のワーカーのクラッシュ、サーバーがすでにミューテーションを完了している可能性がある 5xx などがあります。

ビジネスの意図が変化した場合は、新しい冪等キーを使用します。顧客が 2 つ目のクレジット パッケージを購入する場合は、新たなチャージとなります。管理者が個別の承認後に支出制限を 100.00 から 250.00 に引き上げるのは、新しい操作です。リクエスト本文が大幅に変更された場合は、修正されたサインアップ テンプレートのキーに新しいバージョンが必要になる場合もあります。

キーの横にリクエストのフィンガープリントを保存します。コードが別のペイロードで同じ冪等キーを再利用しようとすると、パートナー API を呼び出す前にローカルで失敗します。このチェックにより、テンプレートの移行および部分的な再試行中に微妙なバグが検出されます。

顧客をステート マシンとしてプロビジョニングする

プロビジョニング ワーカーは、1 つのトランザクションでデータベース、パートナー API、および下流の請求システムをカバーできると想定するのではなく、明示的な状態を通過する必要があります。

pending_create_group
  - create local operation record
  - send create group request with Idempotency-Key
  - store request ID and group public ID

group_created_key_pending
  - create key operation record
  - send create key request with Idempotency-Key
  - store key metadata and secret according to your security policy

key_created_limit_pending
  - create spend-limit operation record
  - send limit update with Idempotency-Key
  - store resulting policy version or target ID

provisioned
  - mark customer ready
  - emit internal audit event
  - notify product systems

このステート マシンにより、クラッシュが発生しても存続可能になります。グループの作成後、キーを保存する前に作業者が死亡した場合、代わりの作業者が操作台帳を検査し、同じ冪等キーを再利用して作業を続行できます。グループが上流に存在するが、ローカル保存が失敗した場合、リコンシリエーションでは、別のオブジェクトをやみくもに作成するのではなく、グループ、キー、トランザクション、および監査サーフェスを通じてターゲットを見つけることができます。

お金を 10 進数データとして扱う

クレジット、ウォレット残高、使用制限、使用量合計、および取引金額は、バイナリ浮動小数点型を通過しないでください。 0.10 などの値は財務値であり、測定値ではありません。元の JSON 10 進数文字列を取り込み境界に格納し、算術演算用に正確な 10 進数型にのみ変換します。

JavaScript では、Number の周囲に課金ロジックを記述しないでください。 10 進数ライブラリを使用するか、専用の通貨モジュールに到達するまで値を文字列として保持します。 Python では、浮動小数点数ではなく文字列の Decimal を使用します。データベースでは、算術演算が必要な場合は固定スケールの数値列を使用し、正確な上流表現を保持することが監査に役立つ場合はテキスト列を使用します。

// Bad: binary floating-point conversion
const limit = Number(apiResponse.spend_limit);

// Better: exact decimal boundary
const limit = new Decimal(apiResponse.spend_limit);

同じルールを比較に適用します。一方をセントに丸め、もう一方をプロバイダーの精度に丸める支出制限チェックでは、リクエストが誤ってブロックまたは許可される可能性があります。 1 つの内部精度ポリシーを定義して文書化し、ゼロ付近の境界値、最小補充額、および移行の制限をテストします。

Webhook 取り込みを退屈にする

Webhook ハンドラーは、複雑なプロビジョニングをインラインで実行しないでください。ハンドラーの仕事は、イベントを認証し、その ID を保持し、すぐに返すことです。フルフィルメントは安全に再試行できるワーカーに属します。

payment_webhook_events
- provider
- event_id
- event_type
- received_at
- payload_hash
- processing_status
- related_customer_id
- related_operation_id
- last_error

provider + event_id に一意制約を設定します。同じイベントが 2 回到着した場合は、既に保存または処理されていることを確認した後、成功を返します。配達が 2 回行われたため、ウォレットに 2 回入金しないでください。

フルフィルメント ワーカーは、一致する top_up_credit オペレーションを作成または検索する必要があります。その冪等キーには、支払いイベント ID と内部台帳エントリ ID を含めることができます。パートナー API のトップアップが成功した後、ローカル状態が更新される前にワーカーがクラッシュした場合、次の試行では同じキーが再利用され、結果のトランザクションがリコンサイルされます。

変更中のパートナー API コールの再試行ルール

再試行にはルールが必要です。これらがないと、再試行コードは重複した副作用を生成するものになります。

ネットワーク タイムアウト、接続のリセット、および不明な 5xx 結果の場合は、文書化された保持期間内に同じ Idempotency-Key で同じリクエストを再試行してください。すべての試行を操作台帳に記録します。

429 応答の場合、Retry-After が指定された場合はそれを尊重し、同じ操作に対して同じ冪等性キーを維持します。レート制限によってビジネスの意図が変更されることはありません。

検証エラーの場合は、自動的に再試行しません。操作に失敗のマークを付け、特定のエラーを明らかにし、意図したペイロードが変更された場合は新しいリクエストのフィンガープリントを使用して修正された操作を要求します。

ペイロードの変更によって冪等性キーの競合が発生した場合は、停止します。それはローカルのバグまたは安全でない再試行です。ビジネス オペレーションが明示的に新規であり、ワークフローによって承認されていない限り、新しいキーを自動的に生成しないでください。

補償する前に未知の結果を調整する

未知の結果が得られた後の最も安全な次のステップは、通常、補償変異ではありません。まず、何が起こったのか聞いてください。

オペレーション レジャーを使用して、冪等キー、リクエスト フィンガープリント、および最後に確認されたリクエスト ID を見つけます。次に、関連するパートナー API のサーフェス、つまりプロビジョニングのグループとキーのリスト、クレジット チャージのトランザクション、ウォレットの状態の残高、使用状況のリクエスト レコード、管理の変更の監査イベントを確認します。

実際の調整シーケンスは次のとおりです:

  1. ロックを使用してローカル操作レコードをリロードします。
  2. まだ保持期間内であり、リクエストのフィンガープリントが一致する場合は、同じ冪等キーを使用して元のミューテーションを再試行します。
  3. 再試行しても状態が解決しない場合は、関連するリストをクエリするか、顧客のメタデータ、グループ ID、キー ID、トランザクション ID、またはタイムスタンプを使用してエンドポイントを取得します。
  4. リクエスト ID、アクション、ターゲット、UTC タイムスタンプに関連付けられた成功した管理変更の監査イベントを確認します。
  5. 証拠を含めて、ローカル操作を succeeded、failed_final、または reconciliation_needed に更新します。
  6. 上流の状態を確認し、補償のための新しい操作を記録した後でのみ、補償ミューテーションを発行します。

7 日間の冪等性保持期間は、通常の再試行期間には便利ですが、アカウンティング アーカイブではありません。サポート、資金調達、紛争の遅延について、永続的なローカル記録を保管します。

行き詰まった状態のためのランブック

pending_create_group

操作レコードが存在するかどうか、および冪等性キーが送信されたかどうかを確認します。リクエストがパートナー API に到達した可能性がある場合は、同じキーを使用して再試行します。リクエストが送信された証拠がない場合は、元のリクエストを送信し、結果のリクエスト ID を保存します。

group_created_key_pending

グループ ターゲット ID をローカルおよびアップストリームで確認します。 2 番目のグループを作成しないでください。独自の冪等キーを使用してキー操作を作成するか再試行してください。

key_created_local_save_failed

API キーシークレットは 1 回しか表示されないことが多いため、これはセキュリティ上重要です。シークレットがポリシーに従って保存されていない場合は、ローカルでキーを使用不可としてマークし、明示的な操作によってキーを取り消すかローテーションし、新しいビジネス目的で置換キーを作成します。

topup_requested_unknown

可能であれば、同じ冪等キーを使用してトップアップを再試行します。次に、取引とウォレットの残高を調整します。最初の応答が失われたからといって、2 回目の補充を発行しないでください。

webhook_received_processing_failed

Webhook イベントを受信済みかつ未履行としてマークしたままにします。原因を解決した後、ワーカー経由で再実行します。固有のイベント レコードにより、重複したフルフィルメントが防止されます。

reconciliation_needed

リクエスト ID、べき等キー、顧客 ID、ターゲット ID、タイムスタンプ、最後のエラーを使用して、オペレーションを内部サポート キューに割り当てます。手動レビューでは、別のプライベート証跡を作成するのではなく、同じ操作記録を更新する必要があります。

テストチェックリスト

  • 同じ顧客に対して登録ボタンが重複してクリックされると、1 つのグループと 1 つの目的のキーが作成されます。
  • アップストリームが成功した後、ローカル保存が再開される前に、ワーカーがクラッシュします。重複した副作用はありません。
  • 同じ冪等キーを再試行することで応答本文が処理されるまでの HTTP タイムアウト。
  • 支払い Webhook が重複しても、クレジット チャージは重複して作成されません。
  • 順序が崩れた支払い Webhook とプロビジョニング ジョブは、正しい顧客状態に収束します。
  • Retry-After を含む 429 応答は、オペレーション ID を変更せずに再試行を遅らせます。
  • ペイロードを変更した冪等キーの再利用はローカルで失敗します。
  • 0.01、0.10、100.00 および支出制限の境界付近の小数値は、予期せず丸められません。
  • 監査イベントの調整により、グループ、キー、または制限を誰がいつ変更したかを説明できます。
  • 冪等保持期間より古いオペレーションは、ブラインド リプレイではなく、ローカル レコードとパートナー API レポート サーフェスを通じて調整されます。

トレードオフ

決定論的冪等性キーにより再試行と調査が容易になりますが、真に新しいインテントにキーを再利用することを避けるために十分なビジネス コンテキストを含める必要があります。

ローカル操作台帳により、スキーマとワークフローが複雑になりますが、ネットワーク呼び出し、Webhook、データベース書き込みがさまざまなタイミングで失敗した場合に、統合に永続的な信頼できる情報源が提供されます。

Webhook の取り込みからすぐに戻るとプロバイダーの再試行が減りますが、信頼性の高いキュー、リプレイ ツール、処理エラーを可視化するためのモニタリングが必要です。

厳密なリクエスト フィンガープリント チェックにより、異なるペイロードでのキーの誤った再利用は防止されますが、サインアップのデフォルトや制限テンプレートが変更されると、明示的なバージョン管理が強制されます。

残高、トランザクション、グループ、キー、監査エンドポイントを介した調整は、元の応答を信頼するよりも時間がかかります。これは、未知の結果が生じた場合のより安全な方法でもあります。

実用的な結論

信頼できるパートナー API 自動化は、HTTP 統合の問題と同じくらい会計と運用の問題でもあります。まず、永続的なビジネス オペレーションを定義します。顧客グループの作成、キーの作成、制限の変更、クレジットの補充、ウォレットの調整、Webhook の処理などです。各オペレーションに安定した冪等性キー、リクエストのフィンガープリント、ステータス マシン、および永続的なローカル レコードを与えます。

そして、すべてのワーカーを退屈にします。操作を取得し、意図したリクエストを正確に送信し、未知の結果の後に同じ冪等キーを再利用し、10 進文字列を正確に解析し、補正する前に調整します。この設計によってすべての障害が除去されるわけではありませんが、顧客に副作用が重複することなく、障害の説明、再試行、監査が可能になります。

関連資料

FAQ

よくある質問

すべてのパートナー API リクエストでべき等キーを使用する必要がありますか?
POST、PATCH、DELETE などの変更パートナー API リクエストでは、文書化された契約に従って冪等キーを使用する必要があります。読み取り専用リクエストは通常​​、同じ処理を必要としませんが、その結果は調整中に使用できます。
1 つの冪等キーを複数の顧客のチャージに再利用できますか?
いいえ。同じキーを再利用するのは、同じビジネス操作を再試行する場合のみです。 2 番目の意図的なトップアップは新しいビジネス操作であり、新しい操作レコードと冪等性キーを受け取る必要があります。
グループ作成中にタイムアウトが発生した後はどうすればよいですか?
タイムアウトを記録し、元の操作を保留中または再試行可能な状態に保ち、保持期間内に同じ冪等キーを使用して同じグループ作成リクエストを再試行します。結果が不明瞭な場合は、何かを作成する前に、グループの記録と監査イベントを通じて調整してください。
なぜお金を 10 進数の文字列または正確な 10 進数として保存するのでしょうか?
ウォレットの残高、クレジット金額、合計使用量、および使用限度額は財務データです。バイナリ浮動小数点変換では丸め誤差が生じる可能性があるため、取り込みでは 10 進数文字列を保持するか、正確な 10 進数型に変換する必要があります。