# 決済を受け付けます MCP アプリで決済を安全に受け付けます。 # リダイレクト > This is a リダイレクト for when platform is web and ui is stripe-hosted. View the full page at https://docs.stripe.com/agentic-commerce/apps/accept-payment?platform=web&ui=stripe-hosted. Collect payments outside your app with a prebuilt Stripe-hosted Checkout page. This guide shows how to: - 商品表示および顧客による購入商品の選択を可能にするための Model Context Protocol (MCP) ツールを定義します。 - Stripe ホスト型の構築済みの[決済画面](https://docs.stripe.com/payments/checkout.md)で決済の詳細を収集する - 決済成功後の Webhook の監視 ## Stripe をセットアップする Add the Stripe API library to your back end. #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ## 商品および価格の設定 This example displays a group of products in the MCP app. [Create products and prices in the Dashboard or with the Stripe CLI](https://docs.stripe.com/products-prices/manage-prices.md). ## Checkout MCP ツールを登録する *価格* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) のセットに対して [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) を作成する MCP ツールを登録します。このツールは後のステップで MCP アプリから呼び出します。 ```javascript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, } from "@modelcontextprotocol/ext-apps/server"; import { readFileSync } from "node:fs"; import Stripe from "stripe"; import { z } from "zod"; // Follow https://docs.stripe.com/keys-best-practices to protect your Stripe API keys. const stripe = new Stripe(process.env.STRIPE_API_KEY); const server = new McpServer({ name: "my-mcp-server", version: "1.0.0" }); const resourceUri = "ui://list-products.html"; async function createCheckoutSession(priceIds) { const lineItems = priceIds.map((price) => ({ price, quantity: 1 })); const session = await stripe.checkout.sessions.create({ mode: "payment", line_items: lineItems, success_url: "https://example.com/checkout/success", }); return session; } // Register the tool that creates a checkout session server.registerTool( "buy-products", { title: "Buy products", description: "Create a checkout page link for purchasing the selected products", inputSchema: { priceIds: z.array(z.string()) }, }, async ({ priceIds }) => {const session = await createCheckoutSession(priceIds); return { content: [ { type: "text", text: `[Complete your purchase here](${session.url})`, }, ], structuredContent: { checkoutSessionId: session.id, checkoutSessionUrl: session.url, }, }; } ); ``` ## UI ツールとリソースの登録 MCP ツールとリソースを登録して、MCP アプリの UI を設定します。この UI は以下の機能を提供します。 1. 商品のリストを表示する 1. 購入する商品を顧客が選択できるようにする 1. Stripe Checkout にリダイレクトして決済を完了する ### Register a product list MCP tool Create a product list MCP tool. Its callback returns the price IDs for the products to display in the UI. ```javascript registerAppTool( server, "list-products", { title: "List products", description: "List the products available for purchase", _meta: { ui: { resourceUri } }, }, async () => { const suggestedProducts = [ // The price IDs from the earlier step { priceId: "{{PRICE_ID}}", name: "Test product 1" }, { priceId: "{{PRICE_ID}}", name: "Test product 2" }, ]; return { structuredContent: { products: suggestedProducts }, content: [], }; } ); ``` ### Register a product list UI resource 商品リストウィジェットの MCP リソースを作成します。商品を表示する UI コードを定義します。 ```javascript // Register the resource that serves the bundled HTML registerAppResource( server, "list-products-widget", resourceUri, { mimeType: RESOURCE_MIME_TYPE }, async () => { const html = readFileSync("dist/ui/list-products.html", "utf8"); return { contents: [ { uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html, }, ], }; } ); ``` This example uses minimal markup. In a production app, use a framework such as React. See the [MCP Apps documentation](https://modelcontextprotocol.github.io/ext-apps/) for additional examples. ```html
``` ```js import { App } from "@modelcontextprotocol/ext-apps"; const app = new App({ name: "ProductList", version: "1.0.0" }); // Establish communication with the host await app.connect(); /** * UI markup and event handlers */ const renderProduct = (product) => { return ` `; }; const handleSubmit = async (event) => { // We'll fill this in next } const renderApp = (products) => { const root = document.querySelector("#root"); root.innerHTML = `$${(product.amount / 100).toFixed(2)}
`; }; app.ontoolresult = (params) => { const { productName, amount, priceID } = params.structuredContent ?? {}; product = { name: productName ?? "", amount: amount ?? 0, priceID: priceID ?? "" }; render(); }; render(); ``` ### Stripe で配送先住所を収集して税金を回収する Stripe Tax API を使用して、次のステップで使用する税金を計算できます。詳細については、[スタンドアロン Tax API の使用](https://docs.stripe.com/tax/standalone-tax-api.md)を参照してください。 ### ChatGPT 即時決済モダールを開く これにより、決済手段を選択するよう促すメッセージが顧客に表示されます。前のステップの価格 ID に対応するよう、決済セッションを作成するロジックを追加します。以下のコードスニペットは価格 ID に UUID を付け加えて Checkout Session ID を作成します。 ```javascript const getTax = (priceID) => { // Add your tax integration }; const createCheckoutSession = (priceID) => { const uuid = crypto.randomUUID(); return `${priceID}::${uuid}`; }; const handleSubmit = (e) => { e.preventDefault(); const { name, amount, priceID } = product; const tax = getTax(priceID); window.openai.requestCheckout({// This is priceID passed in from the MCP buy product tool id: createCheckoutSession(priceID), // remove this when you are ready for live mode payment_mode: "test", payment_provider: { provider: "stripe",// Insert your Network ID from the Stripe dashboard merchant_id: networkID, supported_payment_methods: ["card"], }, status: "ready_for_payment", currency: "USD", line_items: [ { id: "line_items_123", item: { id: priceID, quantity: 1, }, base_amount: product.amount, subtotal: product.amount, tax: tax, total: product.amount + tax, }, ], totals: [ { type: "items_base_amount", display_text: product.name, amount: product.amount, }, { type: "subtotal", display_text: "Subtotal", amount: product.amount, }, { type: "tax", display_text: "Tax", amount: tax, }, { type: "total", display_text: "Total", amount: product.amount + tax, }, ], fulfillment_options: [], fulfillment_address: null, messages: [], links: [ { type: "terms_of_service", url: "https://example.com/terms", }, ], }); } ``` ## 決済を完了するための MCP ツールを登録する When the customer selects a payment method in the ChatGPT payment UI and clicks **Pay**, ChatGPT calls your `complete_checkout` tool and returns the SPT that you use to create a `PaymentIntent`. 入力として共有決済認証済みトークンを受け取り、[Payment Intents API](https://docs.stripe.com/api/payment_intents.md) に渡して処理する `complete_checkout` MCP ツールを登録します。 ```javascript const retrievePriceID = (checkout_session_id: string) => { const [priceID, uuid] = checkout_session_id.split('::'); return priceID; }; server.registerTool( "complete_checkout", { description: "Complete the checkout and process the payment", inputSchema: { checkout_session_id: z.string(), buyer: z .object({ name: z.string().nullable(), email: z.string().nullable(), phone_number: z.string().nullable(), }) .nullable(), payment_data: z.object({ token: z.string(), provider: z.string(), billing_address: z .object({ name: z.string(), line_one: z.string(), line_two: z.string().nullable(), city: z.string(), state: z.string(), country: z.string(), postal_code: z.string(), phone_number: z.string().nullable(), }) .nullable(), }), }, }, async ({checkout_session_id, buyer, payment_data}) => { const price = (await stripe.prices.retrieve(retrievePriceID(checkout_session_id as string))) // Add your tax logic const tax = getTax() // confirms the SPT stripe.paymentIntents.create({ amount: price.unit_amount + tax, currency: price.currency, shared_payment_granted_token: payment_data.token, confirm: true, }); return { content: [], structuredContent: { id: checkout_session_id, status: "completed", currency: price.currency, buyer, line_items: [], order: { id: "{{ORDER_ID}}", checkout_session_id, permalink_url: "", }, }, }; } ); ``` ## テスト 実際のお金を動かさずにアプリをテストするには、Stripe のテスト環境で ChatGPT の決済テストモードを使用します。 1. Stripe ダッシュボードで[サンドボックス](https://docs.stripe.com/sandboxes.md)に移動します。 1. テスト用 Stripe プロフィールを作成し、テスト環境内で ChatGPT に連結させ、テスト用のネットワーク ID をコピーします。 1. テストカードを想定してテスト用 SPT を生成するために、決済テスト環境を使用するように ChatGPT アプリの設定を更新してください。 1. 決済をリクエストする際は、テスト用プロファイル ID を指定し、`payment_mode` を `test` に設定してください。これにより、ChatGPT はテストカードを想定し、テスト用 SPT を生成します。 ```javascript window.openai.requestCheckout({ id: priceID,payment_mode: "test", payment_provider: { provider: "stripe",merchant_id: "profile_test", supported_payment_methods: ["card"], }, ``` 1. ChatGPT からのテスト用 SPT を処理するために、MCP ツールの実装では Stripe のテスト用 API キーを使用してください。キーを安全に使用するために[ベストプラクティス](https://docs.stripe.com/keys-best-practices.md)に従ってください。キーをコードに直接埋め込むことは避け、利用しているプラットフォームからキーが提供される場合にはシークレットマネージャーを使用してください。 1. 本番環境とテスト環境で同一の Webhook 構成を設定し、テスト用 Webhook ハンドラーが本番システムに影響を与えないことを確認してください。例えば、本番用の Webhook が出荷をトリガーした場合、本番環境ではテストエンドポイントは出荷されたことだけをログに記録します。 これらのステップを完了したら、実際の資金を動かさずにアプリ内の決済フローを評価してください。 ### アプリを本番環境に公開する アプリを本番環境に昇格する準備ができたとき: 1. **Payment Intents: Write** 権限を持つ本番環境用の[制限付き API キー](https://docs.stripe.com/keys-best-practices.md#limit-access) (`rk_live_...`) を作成してください。制限付きキーを使用することで、MCP ツールに必要な権限のみを正確に付与できます。 1. 本番環境用の制限付き API キーを使用できるように MCP ツールを更新してください。 1. アプリの決済リクエストを本番プロフィール ID で更新し、テスト `payment_mode` オプションを削除してください。 Your app is then ready to handle live payments. You must complete this step before submitting for ChatGPT app review. > ChatGPT アプリを提出後は、本番の顧客に公開されているため、テスト決済モードを使用しないでください。 ## See also - [Model Context Protocol](https://modelcontextprotocol.io/) - [ChatGPT Apps SDK](https://developers.openai.com/apps-sdk)