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

Référence de l’API de paiement

Implémentez le paiement depuis l’interface facultative du plugin.

Vue d’ensemble

Les développeurs de plugins choisissent comment monétiser l’expérience qu’ils proposent. Aujourd’hui, l’approche recommandée et accessible à tous consiste à utiliser un paiement externe : les utilisateurs finalisent leurs achats sur le propre domaine du développeur. Si seuls les plugins permettant l’achat de biens physiques sont actuellement approuvés, nous travaillons activement à la prise en charge d’un éventail plus large de cas d’utilisation commerciaux.

Nous proposons également le paiement intégré avec la fenêtre de paiement ChatGPT à certaines marketplaces partenaires (bêta), et prévoyons d’en étendre progressivement l’accès à d’autres marketplaces et vendeurs de biens physiques. En attendant, nous recommandons de rediriger les parcours d’achat vers votre parcours de paiement externe habituel.

Le paiement externe consiste à rediriger les utilisateurs de ChatGPT vers un parcours de paiement hébergé par le marchand sur votre propre site web ou application, où vous gérez les prix, les paiements, l’expédition et le traitement des commandes de biens physiques éligibles.

Cette approche est recommandée pour la plupart des développeurs de plugins.

Fonctionnement

  1. Un utilisateur interagit avec l’interface de votre plugin dans ChatGPT.
  2. L’interface de votre plugin présente des biens physiques éligibles (par exemple, avec une action « Acheter maintenant »).
  3. Lorsque l’utilisateur décide d’acheter, l’interface de votre plugin lui propose un lien ou le redirige hors de ChatGPT vers votre parcours de paiement externe.
  4. Le paiement, la facturation, les taxes, les remboursements et la conformité sont entièrement gérés sur votre domaine.
  5. Après l’achat, l’utilisateur peut revenir dans ChatGPT avec une confirmation de commande ou des informations de suivi.

Paiement avec des moyens de paiement enregistrés

Les développeurs de plugins peuvent créer, dans une interface facultative, un parcours de paiement qui permet aux clients d’utiliser des moyens de paiement déjà enregistrés auprès du marchand. Ce parcours ne peut afficher que des moyens de paiement enregistrés et ne peut pas recueillir les données de nouveaux moyens de paiement auprès des clients.

Avec cette approche, le client n’a pas besoin d’être redirigé vers une autre interface en dehors de ChatGPT pour finaliser l’achat.

Fonctionnement

  1. Un utilisateur interagit avec l’interface de votre plugin dans ChatGPT.
  2. L’interface de votre plugin présente des biens physiques éligibles avec les totaux correspondants.
  3. L’interface de votre plugin affiche les moyens de paiement éligibles que le client a déjà enregistrés auprès de vous.
  4. Le client sélectionne un moyen de paiement enregistré et confirme l’achat dans ChatGPT.
  5. Votre serveur traite l’achat avec le moyen de paiement enregistré et renvoie une confirmation au plugin.

Paiement avec la fenêtre de paiement ChatGPT (bêta privée)

Le paiement avec la fenêtre de paiement ChatGPT est actuellement réservé à certaines marketplaces et n’est pas disponible pour tous les utilisateurs.

Pour recueillir de nouveaux moyens de paiement dans le parcours de paiement, les développeurs de plugins doivent utiliser la fenêtre de paiement ChatGPT. Appelez requestCheckout avec les données de la session de paiement (articles, totaux, moyens de paiement enregistrés) pour ouvrir la fenêtre. Lorsque l’utilisateur sélectionne l’action d’achat, ChatGPT envoie un token représentant le moyen de paiement sélectionné à votre serveur MCP via l’appel à l’outil complete_checkout. Utilisez votre intégration PSP pour encaisser le paiement avec ce token, puis renvoyez les détails de la commande finalisée depuis complete_checkout.

Le parcours en bref

  1. Le serveur prépare la session : un outil MCP renvoie les données de la session de paiement (identifiant de session, articles, totaux, prestataire de paiement) dans structuredContent.
  2. Le widget affiche un aperçu du panier : le widget affiche les articles et les totaux pour permettre à l’utilisateur de les confirmer.
  3. Le widget appelle requestCheckout : le widget invoque requestCheckout(session_data). ChatGPT ouvre la fenêtre de paiement et affiche le montant à débiter ainsi que différents moyens de paiement.
  4. Le serveur finalise la commande : lorsque l’utilisateur clique sur le bouton de paiement, le widget rappelle votre serveur MCP via l’appel à l’outil complete_checkout. L’outil MCP renvoie la commande finalisée, qui est transmise au widget en réponse à requestCheckout.

Session de paiement

Vous devez construire les données de la session de paiement que l’hôte affichera. Les valeurs exactes de certains champs, tels que id et payment_provider, dépendent de votre prestataire de services de paiement et de votre système de commerce. En pratique, votre outil MCP doit renvoyer :

  • Les articles et les quantités achetés par l’utilisateur.
  • Les totaux (sous-total, taxes, remises, frais, total) correspondant aux calculs de votre serveur.
  • Les métadonnées du prestataire requises par votre intégration PSP.
  • Les liens vers les documents juridiques et les politiques (conditions, politique de remboursement, etc.).

Widget : appelez requestCheckout

L’hôte fournit window.openai.requestCheckout. Utilisez cette fonction pour ouvrir la fenêtre de paiement ChatGPT lorsque l’utilisateur lance un achat :

Exemple :

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

Dans votre composant, vous pouvez déclencher cet appel lors d’un clic sur un bouton :

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

Voici un exemple complet de session de paiement que votre widget peut transmettre à l’hôte. Votre plugin fournit les champs de session de paiement ci-dessous. ChatGPT ajoute les champs gérés par l’hôte, tels que merchant, logo_url, conversation_id, connector_id et ecosystem_app_uri. Renseignez le champ merchant_id avec la valeur indiquée par votre 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);

Points clés :

  • window.openai.requestCheckout(session) ouvre l’interface de paiement de l’hôte.
  • La promesse est résolue avec le résultat de la commande ou rejetée en cas d’erreur ou d’annulation.
  • Affichez les données JSON de la session pour que les utilisateurs puissent vérifier ce qu’ils paient.
  • Pour tous les champs de montant, utilisez des nombres entiers exprimés dans la plus petite unité de la devise.
  • Utilisez payment_provider.managed_payment_methods pour les moyens de paiement que le client a déjà enregistrés auprès de votre marchand.
  • Conservez les valeurs de metadata sous forme de chaînes de caractères.
  • Pour provider, utilisez le slug du PSP requis par votre intégration, et contactez votre PSP pour obtenir sa valeur merchant_id.

Serveur MCP : exposez l’outil complete_checkout

Vous pouvez reprendre ce modèle et y substituer votre propre logique :

Pour les retours directs de CallToolResult, le SDK MCP pour Python utilise le type de retour Annotated ci-dessous pour déclarer le outputSchema de l’outil pour structuredContent.

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

Adaptez cet exemple aux besoins suivants :

  • Intégrez votre prestataire de services de paiement pour débiter le moyen de paiement contenu dans payment_data.
  • Enregistrez durablement la commande dans votre système.
  • Renvoyez les données de commande et de reçu faisant autorité.
  • Incluez _meta.ui.resourceUri si vous souhaitez afficher un widget de confirmation (ChatGPT reconnaît _meta["openai/outputTemplate"] comme alias de compatibilité facultatif).

Les prestataires de services de paiement suivants prennent en charge le traitement des paiements depuis la fenêtre de paiement ChatGPT :

Facultatif : recevoir les données brutes des moyens de paiement

Si vous êtes un marchand disposant d’une certification PCI DSS de niveau 1, vous pouvez recevoir directement les données brutes des moyens de paiement en implémentant le point de terminaison Delegate Payment du protocole Agentic Commerce Protocol. La requête de paiement délégué inclura toutes les informations sur le moyen de paiement nécessaires à votre parcours de paiement, notamment le numéro de carte brut, la date d’expiration, le CVC, l’adresse de facturation, les contraintes d’autorisation de dépense, les signaux de risque et les métadonnées.

Voici, par exemple, une requête contenant les données brutes d’un moyen de paiement par carte :

{
  "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"
  }
}

La réponse correspondante doit renvoyer un identifiant représentant le moyen de paiement. Cet identifiant sera transmis à complete_checkout dans payment_data.

{
  "id": "vt_01J8Z3WXYZ9ABC123",
  "created": "2026-02-12T14:30:00Z",
  "metadata": {
    "source": "agent_checkout",
    "merchant_id": "acme_corp",
    "idempotency_key": "idem_xyz789"
  }
}

Gestion des erreurs

L’appel à l’outil complete_checkout peut renvoyer des messages de type error. Les messages d’erreur dont le champ code vaut payment_declined ou requires_3ds seront affichés dans la fenêtre de paiement ChatGPT. Tous les autres messages d’erreur seront renvoyés au widget en réponse à requestCheckout. Le widget peut afficher l’erreur de la manière souhaitée.

Mode de paiement test

Vous pouvez définir le champ payment_mode sur test dans l’appel à requestCheckout. Une fenêtre de paiement ChatGPT acceptant les cartes de test (comme la carte de test 4242) s’affichera alors. Le token obtenu, inclus dans payment_data et transmis à l’outil complete_checkout, peut être traité dans l’environnement de préproduction de votre PSP. Vous pouvez ainsi tester les parcours de bout en bout sans transférer de fonds réels.

Notez qu’en mode de paiement test, vous devrez peut-être définir une valeur différente pour merchant_id. Consultez le guide de monétisation de votre prestataire de paiement pour plus de détails.

Liste de vérification de l’implémentation

  1. Définissez votre modèle de session de paiement : incluez les identifiants, l’objet représentant le prestataire de paiement, les lignes de commande, les totaux et les liens vers les informations juridiques.
  2. Renvoyez la session depuis votre outil MCP dans structuredContent, avec votre modèle de widget.
  3. Affichez la session dans le widget pour que les utilisateurs puissent vérifier les articles, les totaux et les conditions.
  4. Appelez requestCheckout(session_data) à la suite d’une action de l’utilisateur ; gérez la commande ou l’erreur renvoyée.
  5. Débitez l’utilisateur en implémentant l’outil MCP complete_checkout, qui renvoie une réponse conforme à la spécification de paiement.
  6. Effectuez des tests de bout en bout avec des montants, des taxes et des remises réalistes pour vérifier que l’hôte affiche les totaux attendus.