개요
플러그인의 수익화 방식은 개발자가 결정합니다. 현재 권장 방식이자 일반적으로 이용할 수 있는 방식은 외부 결제입니다. 사용자는 개발자의 도메인에서 구매를 완료합니다. 현재는 실물 상품 구매용 플러그인만 승인하고 있으며, 더 다양한 상거래 용도를 지원하기 위해 노력하고 있습니다.
일부 마켓플레이스 파트너에게는 ChatGPT 결제 시트를 이용한 임베디드 결제도 베타로 제공하고 있습니다. 앞으로 더 많은 마켓플레이스와 실물 상품 판매업체로 지원 대상을 확대할 계획입니다. 그전까지는 사용자가 구매할 때 판매자가 운영하는 기존 외부 결제 플로우로 안내하는 방식을 권장합니다.
권장 수익화 방식
✅ 외부 결제(권장)
외부 결제는 사용자를 ChatGPT에서 판매자가 자체 웹사이트나 애플리케이션에서 직접 호스팅하는 결제 플로우로 안내하는 방식입니다. 판매자는 이곳에서 구매 가능한 실물 상품의 가격 책정, 결제, 배송, 주문 이행을 담당합니다.
대부분의 플러그인 개발자에게 이 방식을 권장합니다.
작동 방식
- 사용자가 ChatGPT에서 플러그인 UI를 사용합니다.
- 플러그인 UI에 구매 가능한 실물 상품을 표시합니다. 예를 들어 “지금 구매” 버튼을 함께 표시할 수 있습니다.
- 사용자가 구매를 결정하면 플러그인 UI가 링크나 리디렉션을 통해 사용자를 ChatGPT 밖의 외부 결제 플로우로 안내합니다.
- 판매자의 도메인에서 결제, 청구, 세금, 환불, 규정 준수에 관한 사항을 모두 처리합니다.
- 구매 후 사용자는 주문 확인 정보나 배송 추적 정보를 가지고 ChatGPT로 돌아올 수 있습니다.
저장된 결제 수단으로 결제
플러그인 개발자는 선택적으로 제공하는 UI에 결제 플로우를 구현해 고객이 판매자에게 이미 저장해 둔 결제 수단으로 결제하도록 할 수 있습니다. 이 플로우에서는 저장된 결제 수단만 표시할 수 있으며, 고객에게서 새 결제 수단의 인증 정보를 수집할 수 없습니다.
이 방식을 사용하면 고객은 ChatGPT 외부 화면으로 이동할 필요 없이 구매를 완료할 수 있습니다.
작동 방식
- 사용자가 ChatGPT에서 플러그인 UI를 사용합니다.
- 플러그인 UI에 구매 가능한 실물 상품과 해당 결제 금액을 표시합니다.
- 플러그인 UI에 고객이 판매자에게 이미 저장해 둔 결제 수단 중 이번 구매에 사용할 수 있는 수단을 표시합니다.
- 고객이 ChatGPT에서 저장된 결제 수단을 선택하고 구매를 확정합니다.
- 판매자의 서버가 저장된 결제 수단으로 구매를 처리하고 플러그인에 주문 확인 정보를 반환합니다.
ChatGPT 결제 시트로 결제(비공개 베타)
현재 ChatGPT 결제 시트를 이용한 결제는 일부 마켓플레이스에서만 지원하며, 모든 사용자가 이용할 수 있는 것은 아닙니다.
플러그인 개발자가 결제 플로우 안에서 새 결제 수단 정보를 수집하려면 ChatGPT 결제 시트를 사용해야 합니다. requestCheckout을 호출할 때 결제 세션 데이터(주문 항목, 합계 금액, 저장된 결제 수단)를 전달하면 시트가 열립니다. 사용자가 구매를 선택하면 ChatGPT가 선택된 결제 수단을 나타내는 토큰을 complete_checkout 도구 호출을 통해 MCP 서버로 보냅니다. 연동한 결제 서비스 제공업체(PSP)를 통해 이 토큰으로 대금을 청구한 다음, complete_checkout에서 확정된 주문 정보를 반환하세요.
결제 플로우 한눈에 보기
- 서버에서 세션 준비: MCP 도구가
structuredContent에 결제 세션 데이터(세션 ID, 주문 항목, 합계 금액, 결제 서비스 제공업체)를 담아 반환합니다. - 위젯에 장바구니 미리보기 표시: 위젯이 주문 항목과 합계 금액을 표시해 사용자가 내용을 확인할 수 있도록 합니다.
- 위젯에서
requestCheckout호출: 위젯이requestCheckout(session_data)를 호출합니다. ChatGPT가 결제 시트를 열고 청구할 금액과 여러 결제 수단을 표시합니다. - 서버에서 주문 확정: 사용자가 결제 버튼을 클릭하면 위젯이
complete_checkout도구를 호출해 MCP 서버에 처리를 요청합니다. MCP 도구가 완료된 주문을 반환하면 위젯은 이를requestCheckout의 응답으로 받습니다.
결제 세션
호스트가 렌더링할 결제 세션 페이로드는 개발자가 구성해야 합니다. id, payment_provider 등 일부 필드의 값은 결제 서비스 제공업체와 판매 시스템에 따라 달라집니다. MCP 도구는 다음 정보를 반환해야 합니다.
- 사용자가 구매하는 주문 항목과 수량
- 서버에서 계산한 값과 일치하는 금액 내역(소계, 세금, 할인, 수수료, 총액)
- PSP 연동에 필요한 제공업체 메타데이터
- 약관, 환불 정책 등 법적 고지 및 정책 링크
위젯에서 requestCheckout 호출하기
호스트는 window.openai.requestCheckout을 제공합니다. 사용자가 구매를 시작하면 이 메서드를 호출해 ChatGPT 결제 시트를 여세요.
예시:
async function handleCheckout(sessionJson: string) {
const session = JSON.parse(sessionJson);
if (!window.openai?.requestCheckout) {
throw new Error("requestCheckout is not available in this host");
}
// Host opens the ChatGPT payment sheet.
const order = await window.openai.requestCheckout({
...session,
id: String(session.id), // Use a unique ID for every checkout session.
});
return order; // Host returns the order payload.
}컴포넌트에서는 사용자가 버튼을 클릭할 때 다음과 같이 결제를 시작할 수 있습니다.
import { useState } from "react";
function CheckoutButton({
checkoutSessionJson,
}: {
checkoutSessionJson: string;
}) {
const [isLoading, setIsLoading] = useState(false);
const [order, setOrder] = useState<Record<string, unknown> | null>(null);
const checkoutButton = (
<button
onClick={async () => {
setIsLoading(true);
try {
const orderResponse = await handleCheckout(checkoutSessionJson);
setOrder(orderResponse);
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
}}
>
{isLoading ? "Loading..." : "Checkout"}
</button>
);
return (
<>
{checkoutButton}
<pre>{JSON.stringify(order, null, 2)}</pre>
</>
);
}다음은 위젯이 호스트에 전달할 수 있는 전체 결제 세션의 예시입니다. 아래 결제 세션 필드는 플러그인이 제공합니다. ChatGPT는 merchant, logo_url, conversation_id, connector_id, ecosystem_app_uri 등 호스트가 관리하는 필드를 추가합니다. merchant_id 필드에는 PSP가 지정한 값을 입력하세요.
const checkoutRequest = {
id: "checkout_session_123",
payment_provider: {
provider: "stripe",
merchant_id: "merchant_123",
supported_payment_methods: [
{
type: "card",
allowed_card_brands: ["visa", "mastercard"],
},
{ type: "apple_pay" },
{ type: "google_pay" },
],
managed_payment_methods: [
{
type: "card",
id: "pm_123",
display_name: "Visa ending in 4242",
display_last4: "4242",
display_brand: "visa",
},
],
},
payment_mode: "live",
status: "ready_for_payment",
currency: "USD",
metadata: {
cart_id: "cart_123",
merchant_order_reference: "order_ref_123",
},
line_items: [
{
id: "line_item_123",
item: {
id: "item_123",
quantity: 1,
},
name: "Canvas backpack",
description: "A weather-resistant everyday backpack.",
images: ["https://merchant.example.com/images/canvas-backpack.png"],
base_amount: 3000,
discount: 0,
subtotal: 3000,
tax: 300,
total: 3300,
},
],
totals: [
{
type: "items_base_amount",
display_text: "Items subtotal",
amount: 3000,
},
{
type: "subtotal",
display_text: "Subtotal",
amount: 3000,
},
{
type: "fulfillment",
display_text: "Shipping",
amount: 550,
},
{
type: "tax",
display_text: "Tax",
amount: 300,
},
{
type: "total",
display_text: "Total",
amount: 3850,
},
],
fulfillment_options: [
{
id: "standard_shipping",
type: "shipping",
title: "Standard shipping",
subtitle: "Arrives in 3-5 business days",
carrier: "USPS",
earliest_delivery_time: "2027-01-15T15:00:00Z",
latest_delivery_time: "2027-01-19T18:00:00Z",
subtotal: 500,
tax: 50,
total: 550,
},
],
fulfillment_option_id: "standard_shipping",
fulfillment_address: {
name: "Jane Customer",
line_one: "123 Main St",
line_two: "Apt 4B",
city: "San Francisco",
state: "CA",
country: "US",
postal_code: "94107",
phone_number: "+14155550123",
},
messages: [
{
type: "info",
param: "fulfillment_address",
content_type: "plain",
content: "Free returns within 30 days.",
},
],
links: [
{ type: "terms_of_use", url: "https://merchant.example.com/terms" },
{ type: "privacy_policy", url: "https://merchant.example.com/privacy" },
{ type: "support_url", url: "https://merchant.example.com/support" },
],
};
const response = await window.openai.requestCheckout(checkoutRequest);주요 사항:
window.openai.requestCheckout(session)은 호스트의 결제 UI를 엽니다.- 결제가 성공하면 프로미스가 주문 결과로 이행되고, 오류가 발생하거나 결제가 취소되면 거부됩니다.
- 사용자가 결제 내용을 검토할 수 있도록 세션 JSON을 렌더링하세요.
- 모든 금액 필드에는 해당 통화의 최소 단위로 환산한 정수를 사용하세요.
payment_provider.managed_payment_methods에는 고객이 판매자에게 이미 저장해 둔 결제 수단을 지정하세요.metadata의 값은 문자열로 유지하세요.provider에는 연동에 필요한 PSP 슬러그를 사용하고,merchant_id값은 PSP에 문의하세요.
MCP 서버에서 complete_checkout 도구 제공하기
다음 패턴을 바탕으로 결제 처리 로직을 구현할 수 있습니다.
이 Python 예시를 실행하려면 fastmcp와 pydantic을 설치하세요. 도구의 output_schema는 MCP의 outputSchema를 선언합니다. ToolResult.structured_content는 structuredContent를 제공하고 meta는 _meta를 제공합니다. 로컬 테스트 픽스처는 example-session과 example-payment-token을 입력으로 받아 예시 응답을 반환합니다. 결제 수단에 대금을 청구하거나 주문을 생성하지 않습니다.
from typing import Any, Literal
from fastmcp import FastMCP
from fastmcp.tools.tool import ToolResult
from pydantic import BaseModel
server = FastMCP("Checkout response fixture")
META_SESSION_ID = "openai/checkoutSessionId"
class Buyer(BaseModel):
email: str
class PaymentData(BaseModel):
# Deliberately accepts only a local fixture token, never real payment credentials.
token: Literal["example-payment-token"]
class CompleteCheckoutOutput(BaseModel):
id: str
status: str
currency: str
line_items: list[dict[str, Any]]
fulfillment_address: dict[str, Any]
fulfillment_options: list[dict[str, Any]]
fulfillment_option_id: str
totals: list[dict[str, Any]]
order: dict[str, Any]
@server.tool(
description="Return the local checkout response fixture; does not charge a payment method or create a real order.",
output_schema=CompleteCheckoutOutput.model_json_schema(),
)
async def complete_checkout(
checkout_session_id: str,
buyer: Buyer,
payment_data: PaymentData,
) -> ToolResult:
if checkout_session_id != "example-session":
raise ValueError("This response fixture only accepts example-session")
return ToolResult(
content=[],
structured_content={
"id": checkout_session_id,
"status": "completed",
"currency": "USD",
"line_items": [
{
"id": "line_item_1",
"item": {
"id": "item_1",
"quantity": 1,
},
"base_amount": 3000,
"discount": 0,
"subtotal": 3000,
"tax": 300,
"total": 3300,
},
],
"fulfillment_address": {
"name": "Jane Customer",
"line_one": "123 Main St",
"line_two": "Apt 4B",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94107",
"phone_number": "+1 (555) 555-5555",
},
"fulfillment_options": [
{
"id": "fulfillment_option_1",
"type": "shipping",
"title": "Standard shipping",
"subtitle": "3-5 business days",
"carrier": "USPS",
"earliest_delivery_time": "2026-02-24T15:00:00Z",
"latest_delivery_time": "2026-02-28T18:00:00Z",
"subtotal": 0,
"tax": 0,
"total": 0,
},
],
"fulfillment_option_id": "fulfillment_option_1",
"totals": [
{
"type": "items_base_amount",
"display_text": "Items subtotal",
"amount": 3000,
},
{
"type": "subtotal",
"display_text": "Subtotal",
"amount": 3000,
},
{
"type": "tax",
"display_text": "Tax",
"amount": 300,
},
{
"type": "total",
"display_text": "Total",
"amount": 3300,
},
],
"order": {
"id": "order_id_123",
"checkout_session_id": checkout_session_id,
"permalink_url": "",
},
},
meta={META_SESSION_ID: "checkout-flow"},
is_error=False,
)다음 작업을 수행하도록 예시 코드를 수정하세요.
- 결제 서비스 제공업체와 연동해
payment_data에 담긴 결제 수단으로 대금을 청구하세요. - 주문을 자체 시스템에 영구 저장하세요.
- 자체 시스템에서 확정한 주문 및 영수증 데이터를 반환하세요.
- 주문 확인 위젯을 렌더링하려면
_meta.ui.resourceUri를 포함하세요. ChatGPT는 호환성을 위해_meta["openai/outputTemplate"]도 선택적으로 사용할 수 있는 별칭으로 지원합니다.
다음 결제 서비스 제공업체는 ChatGPT 결제 시트를 통한 결제 처리를 지원합니다.
- Adyen
- Checkout.com
- Fiserv
- PayPal
- Stripe
- Worldpay
선택 사항: 결제 수단 원본 정보 수신
PCI DSS 레벨 1 인증을 보유한 판매자는 Agentic Commerce Protocol의 Delegate Payment 엔드포인트를 구현해 결제 수단의 원본 정보를 직접 받을 수 있습니다. 위임 결제 요청에는 결제 플로우에 필요한 결제 수단 정보가 모두 포함됩니다. 실제 카드 번호, 만료일, CVC, 청구지 주소, 결제 허용 조건, 위험 신호, 메타데이터 등이 여기에 해당합니다.
카드 결제 수단의 원본 정보가 포함된 요청 예시는 다음과 같습니다.
{
"payment_method": {
"type": "card",
"card_number_type": "fpan",
"number": "4242424242424242",
"exp_month": "11",
"exp_year": "2026",
"name": "Jane Doe",
"cvc": "223",
"checks_performed": ["avs", "cvv"],
"iin": "424242",
"display_card_funding_type": "credit",
"display_brand": "visa",
"display_last4": "4242",
"metadata": {}
},
"allowance": {
"reason": "one_time",
"max_amount": 5000,
"currency": "usd",
"checkout_session_id": "cs_01HV3P3ABC123",
"merchant_id": "acme_corp",
"expires_at": "2026-02-13T12:00:00Z"
},
"billing_address": {
"name": "Jane Doe",
"line_one": "185 Berry Street",
"line_two": "Suite 550",
"city": "San Francisco",
"state": "CA",
"country": "US",
"postal_code": "94107"
},
"risk_signals": [
{
"type": "card_testing",
"score": 5,
"action": "authorized"
}
],
"metadata": {
"session_id": "sess_abc123",
"user_agent": "ChatGPT/2.0"
}
}
이 요청에 대한 응답으로 결제 수단을 식별하는 ID를 반환해야 합니다. complete_checkout에는 이 ID가 payment_data의 일부로 전달됩니다.
{
"id": "vt_01J8Z3WXYZ9ABC123",
"created": "2026-02-12T14:30:00Z",
"metadata": {
"source": "agent_checkout",
"merchant_id": "acme_corp",
"idempotency_key": "idem_xyz789"
}
}
오류 처리
complete_checkout 도구 호출은 error 타입의 메시지를 반환할 수 있습니다. code 값이 payment_declined 또는 requires_3ds인 오류 메시지는 ChatGPT 결제 시트에 표시됩니다. 그 밖의 오류 메시지는 requestCheckout의 응답으로 위젯에 전달됩니다. 위젯에서는 원하는 방식으로 오류를 표시할 수 있습니다.
테스트 결제 모드
payment_mode 필드의 값을 test로 설정해 requestCheckout을 호출하면 4242 테스트 카드와 같은 테스트 카드로 결제할 수 있는 ChatGPT 결제 시트가 열립니다. 이때 생성된 token은 payment_data에 포함되어 complete_checkout 도구에 전달되며, PSP의 스테이징 환경에서 처리할 수 있습니다. 이를 통해 실제 자금 이체 없이 전체 결제 플로우를 테스트할 수 있습니다.
테스트 결제 모드에서는 merchant_id에 다른 값을 설정해야 할 수 있습니다. 자세한 내용은 결제 서비스 제공업체의 수익화 가이드를 참고하세요.
구현 체크리스트
- 결제 세션 모델을 정의하세요. ID, 결제 서비스 제공업체 객체, 주문 항목, 합계 금액, 법적 고지 링크를 포함하세요.
- MCP 도구에서 세션을 반환하세요.
structuredContent에 세션을 담아 위젯 템플릿과 함께 반환하세요. - 위젯에서 세션을 렌더링하세요. 사용자가 주문 항목, 합계 금액, 약관을 검토할 수 있도록 하세요.
requestCheckout(session_data)를 호출하세요. 사용자가 결제를 시작할 때 호출하고 반환된 주문이나 오류를 처리하세요.- 사용자에게 대금을 청구하세요.
complete_checkoutMCP 도구를 구현하고 결제 명세에 맞는 응답을 반환하세요. - 전체 결제 플로우를 테스트하세요. 실제 거래에 가까운 금액, 세금, 할인액을 사용해 호스트에 예상한 합계 금액이 표시되는지 확인하세요.