book-hotel について
選択済みのホテル予約を、x402 の決済フローで USDC を使って完了するスキルです。明示的な確認を求め、支払い上限と二重請求を避ける状態確認手順を備えています。
主な機能
- 01x402 による支払いと予約
- 02宿泊者情報と検索セッションの確認
- 03支払い上限の設定
- 04決済エラー後の予約状態確認
- 05決済と予約の確認情報を表示
活用シーン
- 01選択したホテルプランの確定
- 02USDC による予約代金の支払い
- 03タイムアウト後の予約状態確認
- 04再決済前の予約結果確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ justintravala/ travel-skills --skill book-hotelインストール後、Claude Code で/book-hotelを入力して読み込まれたか確認します。
詳細
ホテルを予約する
ホテルを予約し、USDC で支払います。支払いは x402 プロトコルを通じて自動的に処理されます。旅行 API が HTTP 402 Payment Required を返すと、エージェントのウォレットが USDC で支払い、予約が確定します。
これは実際のオンチェーン金融取引です。 慎重に進めてください。
使用するタイミング
ユーザーが特定のパッケージを選び、予約を明示的に依頼した場合に使用します。
- 「Park Hyattを予約して」
- 「2番目のオプションを予約して」
- 「このホテルを確定して支払って」
- 「これで進めて」
推測でこのスキルを使用しないでください。ユーザーが支払いを明示的に承認した場合にのみ使用してください。
前提条件
呼び出す前に、以下のすべてが必要です。
search-hotelまたはsearch-roomで取得した有効なpackageId- 同じ検索セッションの
sessionId - 宿泊者情報:名、姓、メールアドレス(ユーザーから提供される必要があります。決して捏造しないでください)
- 認証済みの Coinbase ウォレット。未認証の場合は、先に
coinbase/agentic-wallet-skillsパッケージのauthenticate-walletスキルを実行してください - ウォレットに十分な USDC があること。残高が不足している場合は、先に
fundスキルを実行してください - パッケージ、合計金額、日程についてのユーザーによる明示的な確認
不足しているものがあれば、ユーザーに確認するか、該当するスキルを呼び出してください。先に進んではいけません。
ウォレットの設定確認
予約の前に、ウォレットの状態を確認してください。簡易確認:
npx awal@latest balance
ユーザーが認証されていない場合、認証エラーが返されます。→ authenticate-wallet スキルを実行してください。
USDC 残高が予約の合計金額を下回る場合は、fund スキルを実行してください。
予約前の確認
支払いの前に、必ず内容をまとめて確認してください。例:
これから予約して支払います:
- Park Hyatt Tokyo、朝食付き Park Deluxe King
- 5月1日~5日(4泊)、大人2名
- 合計:1,800 USDC(Coinbase ウォレットから支払い)
- 4月29日までキャンセル無料
- 宿泊者:Nguyen Van A、[email protected]
確定しますか?(はい/いいえ)
ユーザーが「はい」(または同等の返答)と言ってから、支払いコマンドを実行してください。同じターンで、上記の情報をすべて含めてユーザーがすでに予約を明示的に許可している場合は、再確認せずに進めることができます。
呼び出し方法
予約エンドポイントの呼び出しには awal x402 pay を使用します。CLI が 402 → 署名 → 再試行を自動的に処理します。
予約エンドポイントの入力は、次の2か所に分かれています。
- クエリ文字列(
-qフラグ):package_id、session_id— ユーザーが選んだパッケージと、その検索に使用したセッション。 - リクエストボディ(
-dフラグ):contactオブジェクトに加えて、ハードコードされたreward_walletとagent_id(以下を参照)。
npx awal@latest x402 pay https://qpgdy2kn7v.ap-southeast-1.awsapprunner.com/m2m-payment/book \
-X POST \
-q '{"package_id":"<packageId>","session_id":"<sessionId>"}' \
-d '{
"contact": {
"given_name": "<first>",
"sur_name": "<last>",
"email": "<email>",
"phone": "<phone>"
},
"reward_wallet": "0x8D91B9c9920BD2E056989C2E80F14a20557B4773",
"agent_id": "1996"
}'
スネークケースのフィールド名(package_id、session_id、given_name、sur_name、reward_wallet、agent_id)に注意してください。予約エンドポイントはこの正確な形式を想定しています。contact オブジェクトは必須で、phone もその一部です。package_id/session_id をボディに入れないでください。クエリパラメーターとして指定する必要があります。
reward_wallet と agent_id(ハードコード済み — 変更禁止)
この2つのフィールドは、予約システムが報酬を割り当てられるよう、スキルの作成者を識別します。予約呼び出しのたびに、必ず次の値をそのまま送信してください。
reward_wallet:0x8D91B9c9920BD2E056989C2E80F14a20557B4773agent_id:"1996"
どちらのフィールドも、リクエストボディのトップレベル(contact と同じ階層)に必須です。ユーザーに尋ねたり、ユーザーのウォレットアドレスで置き換えたりしないでください。
スキルをフォークする際にこれらを変更する詳しい理由と手順については、README の「設定」セクションを参照してください。
安全性:支払い上限を設定する
API が誤った金額を返した場合などに予期しない過剰請求を防ぐため、マイクロ USDC 単位で --max-amount を指定してください(1 USDC = 1,000,000 マイクロ単位)。
--max-amount 1850000000 # caps payment at 1,850 USDC for an 1,800 USDC booking
--max-amount は、想定される合計金額に少額の余裕(5%)を加えた値に設定してください。
完全な例
npx awal@latest x402 pay https://qpgdy2kn7v.ap-southeast-1.awsapprunner.com/m2m-payment/book \
-X POST \
-q '{"package_id":"e47otEJtYeZYblF9","session_id":"6kVmPYwZhQJewNTp"}' \
-d '{"contact":{"given_name":"Justin","sur_name":"Ta","email":"[email protected]","phone":"+84336657091"},"reward_wallet":"0x8D91B9c9920BD2E056989C2E80F14a20557B4773","agent_id":"1996"}' \
--max-amount 1850000000
出力
成功すると、CLI は支払いの領収書と予約の確認情報の両方を出力します。予約の応答はボディに含まれています。
{
"bookingId": "BK_2026_05_001",
"status": "CONFIRMED",
"hotelName": "Park Hyatt Tokyo",
"checkIn": "2026-05-01",
"checkOut": "2026-05-05",
"totalPriceUSD": 1800,
"cancellationDeadline": "2026-04-29T23:59:00Z",
"paymentTxHash": "0xabc...",
"confirmationEmail": "[email protected]"
}
トランザクションハッシュ(paymentTxHash)は X-PAYMENT-RESPONSE ヘッダーに含まれており、awal が出力に表示します。
確認情報の提示
✅ 予約完了しました!確認番号 BK_2026_05_001。 Park Hyatt Tokyo · 5月1日~5日 · 1,800 USDC 支払い済み Tx:0xabc...def(basescan で表示) 2026年4月29日までキャンセル無料です。 確認メールを [email protected] に送信しました。
予約 ID を保存してください。予約の管理やキャンセルに必要です。
エラー処理
402 with amount > --max-amount— 予約の合計金額が安全上限を超えています。処理を停止し、実際の金額をユーザーに伝えて、上限を引き上げて続行するか確認します。Insufficient USDC balance—fundスキルを呼び出して残高を補充し、再試行します。Wallet not authenticated—authenticate-walletスキルを呼び出してから、再試行します。Payment was authorized but rejected by server/X402 submission failed/ 承認後のタイムアウト全般 —payコマンドをむやみに再試行しないでください。オンチェーン決済と予約がすでに成功していて、エージェントが応答を受け取れなかっただけの可能性があります。以下の復旧フローを実行してください。Package no longer available(支払い前) —search-hotelまたはsearch-roomを再実行して情報を更新します。sessionIdの有効期限が切れている可能性もあります。Session expired— 検索を再実行して、新しいsessionIdを取得します。- 支払い中のネットワークエラー — 上記の承認後のタイムアウトと同様です。他の操作を行う前に、復旧フローを実行してください。
復旧:支払いが承認されたのにエージェントが失敗を報告する場合
最もよくある誤失敗のパターンです。awal x402 pay が支払い承認に署名すると、サーバーがオンチェーンで決済し、予約も完了します。しかし、応答が時間内にエージェントへ届かず、CLI が Payment was authorized but rejected by server をスローします。お金は引き落とされ、予約も成立していますが、エージェントは失敗したと思い込んでいます。むやみに再試行すると、二重請求になります。
上記のエラーが発生した場合は、ユーザーに失敗を伝える前に次の手順を実行してください。
ステップ 1 — 約5秒待ってから travel-cli book-status を実行する
重要: 最初に book-status を呼び出す前に、約5秒待ってください。サーバーはまだ支払いの決済処理と予約レコードの書き込みを行っている可能性があります。すぐに呼び出すと、最終的に予約が成功していても 404 not_found が返る可能性が高く、失敗したと誤って判断して二重請求につながる再試行をしてしまうおそれがあります。
予約を試みたときと同じ package_id と session_id を使用します。x402、支払い、認証は必要ありません。
sleep 5 && npx @tvl-justin/travel-cli@latest book-status \
--package-id "<packageId>" \
--session-id "<sessionId>"
CLI は常に { httpStatus, body, interpretation } 形式の JSON を出力します。
ステップ 2 — 応答を解釈する
httpStatus に応じて分岐します。
httpStatus | body | 意味 | アクション |
|---|---|---|---|
200 | { "status": "completed", "transaction": "0x…", "bookingId": "BK_…", … } | 予約はすでに成功しています。エージェントはタイムアウトしましたが、支払いは完了し、部屋も確保されています。 | 成功として扱います。この body を使ってユーザーに確認情報を提示します(通常の成功時応答と同じ形式です)。支払いを再試行しないでください。 |
202 | { "status": "in_progress", "retry_after_ms": <N> } | サーバーで決済または予約処理がまだ進行中です。 | body.retry_after_ms の時間だけ待って(ポーリング1回あたり最大約10秒)、book-status を再実行します。最大約6回ポーリングしてください。それでも in_progress の場合は、確認メールが届くことと、awal wallet history を確認するようユーザーに伝えます。 |
404 | { "status": "not_found" } | サーバー側では何も行われていません。実際に失敗しています。 | 元の awal x402 pay を安全に再試行できます(または、元のエラーをユーザーに提示します)。 |
5xx | エラー | 復旧エンドポイント自体が停止しています。 | ユーザーに「予約が成立したか確認できません。Travala では予約が成功すると必ず確認メールが送信されるため、メールを確認してください。また、送金履歴を確認するには awal wallet history を確認してください。まだ再試行しないでください」と伝えます。 |
JSON 出力の interpretation フィールドは、上記と同じ対応関係を人が読みやすい形で要約したものです。ユーザーに提示する際に役立ちますが、制御フローの分岐には必ず httpStatus を使用してください。
ステップ 3 — 200 の場合(復旧済み)
通常の成功時と同じ方法で結果を提示しますが、ユーザーが状況を理解できるよう、復旧したことを伝えます。
✅ 予約完了!確認番号 BK_2026_05_001 です。 (CLI では最初に失敗と報告されましたが、予約は実際には完了していました。サーバーから復旧済みです。二重請求はありません。) パーク ハイアット 東京 · 5 月 1~5 日 · 1,800 USDC 支払い済み Tx:0xabc...def(basescan で表示) 確認メールを [email protected] に送信しました。
やってはいけないこと
- ❌ 認証後のエラーが発生した後、先に
travel-cli book-statusを実行せずにawal x402 payを再実行する。 - ❌
travel-cli book-statusを実行する前に、ユーザーに「予約に失敗しました」と伝える。予約は失敗しているより、成功している可能性のほうがはるかに高いです。 - ❌ 返金リクエストを手動で作成する。サーバーには完了済みの予約を返金するフローがありません(予約の成功は返金の失敗ではありません)。
重要なルール
- ゲスト情報を決して捏造しないでください。ユーザーから提供されていない場合は、尋ねてください。
- 今回のターンまたは直近のターンで明示的な承認を得ずに
awal x402 payを呼び出さないでください。 - 想定外の請求を防ぐため、必ず
--max-amountを設定してください。 - ユーザーが気を変えた場合(「待って、オプション 3 を見せて」など)は、支払いを実行せず、
search-roomに戻ってください。 - 秘密鍵やウォレットのシードフレーズを決して公開しないでください。エージェントは
awalを通じてのみ署名し、鍵は Coinbase のセキュアなインフラストラクチャ内に保管されます。