For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主导航

结账 API 参考

在可选的插件 UI 中实现结账。

概览

插件开发者需自行选择如何通过其产品体验获利。目前, 推荐普遍可用 的方式是使用 外部结账,让用户在开发者自己的域名下完成购买。虽然目前仅批准用于购买实物商品的插件,但我们正积极努力,支持更广泛的商业使用场景。

我们也在向部分电商平台合作伙伴开放 使用 ChatGPT 支付面板的嵌入式结账 (测试版),并计划逐步向更多 电商平台和实物商品零售商开放。在此之前,我们建议 将购买流程引导至您常规的外部结账流程。

外部结账 是指将用户从 ChatGPT 引导至您自己的网站或应用中的 商家托管结账流程 ,由您负责处理符合条件的实物商品的定价、支付、配送和履约。

我们建议大多数插件开发者采用这种方式。

运作方式

  1. 用户在 ChatGPT 中与您的插件 UI 交互。
  2. 您的插件 UI 展示符合条件的实物商品(例如提供“立即购买”操作)。
  3. 当用户决定购买时,您的插件 UI 通过链接或重定向将用户从 ChatGPT 引导至您的外部结账流程。
  4. 支付、账单、税费、退款和合规事务均完全在您的域名下处理。
  5. 购买后,用户可以携带订单确认或物流跟踪信息返回 ChatGPT。

使用已保存的支付方式结账

插件开发者可以在可选 UI 中构建结账流程,让客户使用已在商家处保存的支付方式。此流程只能显示已保存的支付方式,不能向客户收集新的支付方式凭据。

采用这种方式时,客户无需重定向到 ChatGPT 以外的其他界面即可完成购买。

运作方式

  1. 用户在 ChatGPT 中与您的插件 UI 交互。
  2. 您的插件 UI 展示符合条件的实物商品及相关合计金额。
  3. 您的插件 UI 显示客户已在您这里保存且符合条件的支付方式。
  4. 客户在 ChatGPT 中选择已保存的支付方式并确认购买。
  5. 您的服务器使用已保存的支付方式处理购买,并向插件返回确认信息。

使用 ChatGPT 支付面板结账(私测版)

目前,使用 ChatGPT 支付面板结账仅限于部分电商平台, 并未向所有用户开放。

要在结账流程中收集新的支付方式,插件开发者必须 使用 ChatGPT 支付面板。调用 requestCheckout 并传入结账会话数据 (商品明细、合计金额、已保存的支付方式)即可打开该面板。当用户 选择购买时,ChatGPT 会通过 complete_checkout 工具调用,将代表所选支付方式的 Token 发送至您的 MCP 服务器。使用您与 PSP 的 集成,通过此 Token 收款,然后通过 complete_checkout 返回最终的订单 详情。

流程概览

  1. 服务器准备会话:MCP 工具在 structuredContent 中返回结账会话数据(会话 ID、商品明细、合计金额、支付服务提供商)。
  2. 小组件预览购物车:小组件渲染商品明细和合计金额,供用户确认。
  3. 小组件调用 requestCheckout:小组件调用 requestCheckout(session_data)。ChatGPT 打开支付面板,显示应扣款金额和各种支付方式。
  4. 服务器完成处理:用户点击支付按钮后,小组件通过 complete_checkout 工具调用回调您的 MCP。MCP 工具返回已完成的订单,该订单将作为 requestCheckout 的响应返回给小组件。

结账会话

您负责构建供主机渲染的结账会话载荷。某些字段(如 idpayment_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(checkout_session_id), // Use a unique ID for every checkout session.
  });

  return order; // Host returns the order payload.
}

在您的组件中,可以通过按钮点击来发起此操作:

<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>

以下是一个完整的结账会话示例,您的小组件可以将其传递给 主机。您的插件提供下面的结账会话字段。ChatGPT 会添加 由主机管理的字段,例如 merchantlogo_urlconversation_idconnector_idecosystem_app_uri。请使用您的 PSP 指定的值 填充 merchant_id 字段:

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。
  • Promise 成功时返回订单结果,发生错误或取消时则被拒绝。
  • 渲染会话 JSON,让用户能够核对付款购买的内容。
  • 所有金额字段均使用以最小货币单位表示的整数。
  • 对于客户已在您的商家处保存的支付方式,请使用 payment_provider.managed_payment_methods
  • metadata 的值保持为字符串。
  • provider 设为您的集成所要求的 PSP Slug,并咨询您的 PSP 以获取其 merchant_id 值。

MCP 服务器:提供 complete_checkout 工具

您可以参照此模式,将其中的逻辑替换为您自己的逻辑:

对于直接返回 CallToolResult 的情况,Python MCP SDK 使用下面的 Annotated 返回类型,为 structuredContent 声明工具的 outputSchema

from typing import Annotated, Any

from pydantic import BaseModel


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]


@tool(description="")
async def complete_checkout(
    self,
    checkout_session_id: str,
    buyer: Buyer,
    payment_data: PaymentData,
) -> Annotated[types.CallToolResult, CompleteCheckoutOutput]:
    return types.CallToolResult(
        content=[],
        structuredContent={
            "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"},
        isError=False,
    )

请调整此示例,以实现以下功能:

  • 与您的支付服务提供商集成,使用 payment_data 中的支付方式扣款。
  • 将订单持久化存储到您的系统中。
  • 返回权威的订单或收据数据。
  • 如果您希望渲染确认小组件,请包含 _meta.ui.resourceUri(ChatGPT 也支持将 _meta["openai/outputTemplate"] 用作可选的兼容别名)。

以下支付服务提供商支持处理 ChatGPT 支付面板的支付请求:

可选:接收原始支付方式

如果您是持有 PCI DSS Level 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。此 ID 将作为 payment_data 的一部分传递给 complete_checkout

{
  "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_declinedrequires_3ds 的错误消息将显示在 ChatGPT 支付面板上。所有其他错误消息都将作为 requestCheckout 的响应返回给小组件。小组件可以按需显示错误。

测试支付模式

您可以在调用 requestCheckout 时,将 payment_mode 字段的值设置为 test。这将显示一个接受测试卡(例如 4242 测试卡)的 ChatGPT 支付面板。生成的 token 会包含在传递给 complete_checkout 工具的 payment_data 中,可在您的 PSP 的预发布环境中处理。这样,您就可以在不发生实际资金转移的情况下测试端到端流程。

请注意,在测试支付模式下,您可能需要为 merchant_id 设置不同的值。有关更多详情, 请参阅您的支付服务提供商的变现指南。

实现检查清单

  1. 定义结账会话模型:包含 ID、支付服务提供商对象、 明细项、各项合计金额和法律条款链接。
  2. 通过您的 MCP 工具返回会话 ,将其放在 structuredContent 中,与小组件模板一同返回。
  3. 在小组件中渲染会话 ,以便用户核对商品、各项合计金额和条款。
  4. 在用户执行操作时调用 requestCheckout(session_data) ;处理返回的订单结果或错误。
  5. 通过实现 complete_checkout MCP 工具向用户收款 , 该工具需返回符合结账规范的响应。
  6. 使用贴近实际的金额、税费和折扣进行端到端测试 ,确保主机渲染的各项合计金额符合您的预期。