You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React集成Paddle内联结账遇400错误:缺少参数问题排查

React集成Paddle内联结账时400 Bad Request错误

问题描述

在React应用中集成Paddle内联结账功能,已完成初始化和结账函数配置,但触发结账时收到400 Bad Request错误,提示:One or more parameters (product id or seller) are missing.

详情

  • Vendor ID和Product ID均通过环境变量正确配置
  • Product ID根据用户所选方案动态获取,但请求仍失败
  • 错误提示product或seller参数缺失

已尝试操作

  • 验证process.env.NEXT_PUBLIC_PADDLE_VENDOR_ID和paddleProductId值正确
  • 确认NEXT_PUBLIC_PADDLE_VENDOR_ID已针对沙箱环境正确设置
  • 确保productIds[selectedPlan.name]和priceIds[selectedPlan.name]已正确定义

疑问

  1. 请求中缺少哪些内容导致了“400 Bad Request”错误?
  2. 如何确保所有必填参数都正确发送?
  3. 我的Paddle结账配置是否存在问题?

浏览器控制台错误请求信息

GET https://sandbox-checkout-service.paddle.com/create/v2/checkout/product/pro_01jd1w5q6dvfbj2c7r7dyydvry/?product=pro_01jd1w5q6dvfbj2c7r7dyydvry&parentURL=http%3A%2F%2Flocalhost%3A3000%2Fcheckout&parent_url=http%3A%2F%2Flocalhost%3A3000%2Fcheckout&referring_domain=localhost%3A3000%20%2F%20localhost%3A3000&locale=en&guest_email=xivo%40mailinator.com&guest_country=us&guest_postcode=14269&vendor=24755&passthrough=%7B%7D&disable_logout=true&display_mode=overlay&apple_pay_enabled=false&paddlejs-version=1.2.1&checkout_initiated=1732270263614&popup=true&paddle_js=true&is_popup=true 400 (Bad Request)

代码片段

useEffect(() => {
    const initializePaddle = () => {
      if (typeof window.Paddle !== 'undefined') {
        const vendorId = parseInt(process.env.NEXT_PUBLIC_PADDLE_VENDOR_ID);
        if (isNaN(vendorId)) {
          console.error("Invalid Vendor ID.");
          return;
        }
        const environment = process.env.NEXT_PUBLIC_PADDLE_ENVIRONMENT || "sandbox";
        Paddle.Environment.set(environment);
        Paddle.Setup({
          vendor: vendorId,
        });
        console.log(`Paddle initialized with vendor ${vendorId} in ${environment} mode.`);
      } else {
        console.error("Paddle is not loaded properly.");
      }
    };

    if (isPaddleLoaded) {
      initializePaddle();
    }
  }, [isPaddleLoaded]);

const handleCheckout = async (e) => {
    e.preventDefault();
    const paddlePriceId = priceIds[selectedPlan.name]?.[selectedPlan.planTime];
    const paddleProductId = productIds[selectedPlan.name]?.[selectedPlan.planTime];

    if (!paddlePriceId || !paddleProductId) {
      alert('Invalid plan or plan time selected.');
      return;
    }

    if (!formData.email || !formData.country || !formData.zipCode) {
      alert('Please complete all required fields.');
      return;
    }

    try {
      Paddle.Checkout.open({
        email: formData.email,
        country: formData.country,
        postcode: formData.zipCode,
        product: paddleProductId, // This should be a valid product ID from your system
        vendor: process.env.NEXT_PUBLIC_PADDLE_VENDOR_ID,
        settings: {
          displayMode: "inline",
          frameTarget: "checkout-container",
          frameInitialHeight: "450",
          frameStyle: "width: 100%; min-width: 312px; background-color: transparent; border: none;",
        },
        items: [
          {
            price_id: paddlePriceId,
            quantity: 1,
          },
        ],
        customer: [
          {
            name: selectedPlan.name,
            amount: parseFloat(selectedPlan.currentPrice),
          },
        ],
        passthrough: JSON.stringify({
          userId: formData.userId,
          planId: selectedPlan.planId,
        }),
        currency: selectedPlan.selectedCurrency.code,
        locale: "en",
        method: "card",
        disableLogout: true,
        successCallback: (data) => {
          console.log("Checkout complete:", data);
          router.push("/thank-you");
        },
        closeCallback: () => console.log("Checkout closed"),
        errorCallback: (error) => {
          console.error("Paddle checkout error:", error);
          alert(`Error: ${error.message}`);
        },
      });
    } catch (error) {
      console.error('Error during checkout:', error);
    }
};

解答

1. 错误原因分析

从请求URL和代码来看,问题出在参数冲突和类型不匹配:

  • 同时传递了product参数和items数组,Paddle V2 API中这两个参数互斥:使用items(通过price_id指定)时,不能再传product参数,否则会导致参数解析混乱,触发缺失提示。
  • vendor参数在结账时传递的是字符串类型的环境变量,但Paddle要求该参数为整数,初始化时已转成整数,但结账时又直接传了字符串,可能导致识别失败。

2. 确保必填参数正确发送的方法

  • 参数互斥检查:Paddle V2结账API中,product(指定产品ID)和items(指定价格ID数组)二选一,不能同时使用。
  • 类型校验:确保vendor参数是整数类型,可复用初始化时的parseInt转换逻辑。
  • 日志验证:在handleCheckout中打印paddleProductId、paddlePriceId、vendor的实际值,确认参数和类型完全符合要求。
  • 环境变量确认:确保NEXT_PUBLIC_PADDLE_VENDOR_ID在构建时已正确注入,可在组件中打印该变量验证。

3. 结账配置修正方案

修改handleCheckout中的Paddle.Checkout.open配置,移除冲突的product参数,同时将vendor转为整数,另外修正不符合API要求的customer参数:

try {
  const vendorId = parseInt(process.env.NEXT_PUBLIC_PADDLE_VENDOR_ID);
  Paddle.Checkout.open({
    email: formData.email,
    country: formData.country,
    postcode: formData.zipCode,
    vendor: vendorId, // 转为整数类型
    settings: {
      displayMode: "inline",
      frameTarget: "checkout-container",
      frameInitialHeight: "450",
      frameStyle: "width: 100%; min-width: 312px; background-color: transparent; border: none;",
    },
    items: [
      {
        price_id: paddlePriceId,
        quantity: 1,
      },
    ],
    // 移除冲突的product参数
    passthrough: JSON.stringify({
      userId: formData.userId,
      planId: selectedPlan.planId,
    }),
    currency: selectedPlan.selectedCurrency.code,
    locale: "en",
    method: "card",
    disableLogout: true,
    successCallback: (data) => {
      console.log("Checkout complete:", data);
      router.push("/thank-you");
    },
    closeCallback: () => console.log("Checkout closed"),
    errorCallback: (error) => {
      console.error("Paddle checkout error:", error);
      alert(`Error: ${error.message}`);
    },
  });
} catch (error) {
  console.error('Error during checkout:', error);
}

注:原代码中的customer参数格式不符合Paddle API要求(应为包含email/name的对象,而非数组),且已传递email参数,建议直接移除该字段,避免额外参数错误。


内容的提问来源于stack exchange,提问作者Rushabh Dhamne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:59:51