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

PayPal REST API创建发票失败:invalid_token错误求助

解决PayPal发票机器人的invalid_token错误

你的核心问题出在异步函数的调用方式,以及几个细节上的疏漏,以下是分步修复方案:

1. 修复AccessToken的获取与使用

你更新后的getAccessToken是异步函数,但在createInvoice里直接调用getAccessToken()会返回一个Promise对象,而非实际的token值,这会导致Authorization头变成Bearer [object Promise],直接触发invalid_token错误。

同时,获取token的请求需要指定Content-Type为application/x-www-form-urlencoded,否则PayPal服务器无法正确解析请求体。

修改后的getAccessToken:

async function getAccessToken(){
    const response = await fetch('https://api-m.sandbox.paypal.com/v1/oauth2/token', {
        method: "post",
        body: "grant_type=client_credentials",
        headers:{
            "Content-Type": "application/x-www-form-urlencoded",
            Authorization: "Basic " + Buffer.from(config.clientId + ":" + config.clientSecret).toString("base64")
        },
    });
    
    const data = await response.json();
    // 如果获取token失败,直接抛出错误便于排查
    if (data.error) throw new Error(`获取Token失败: ${data.error_description}`);
    console.log('获取到的Token:', data.access_token);
    return data.access_token;
}

2. 修复createInvoice的异步逻辑

createInvoice需要改为异步函数,等待token获取完成后再发起发票创建请求,同时要确保发票创建成功后再调用sendInvoice,避免因异步时序问题导致发票还未生成就尝试发送。

修改后的createInvoice:

async function createInvoice(item_name, item_description, quantity, cost, payer_email){ 
    try {
        const accessToken = await getAccessToken();
        const invoiceNumber = generateInvoiceNumber();

        const response = await fetch('https://api-m.sandbox.paypal.com/v2/invoicing/invoices', {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${accessToken}`,
                'Content-Type': 'application/json',
                'Prefer': 'return=representation'
            },
            body: JSON.stringify({
                "detail": {
                  "invoice_number": invoiceNumber, // 复用同一个编号,避免重复生成
                  "currency_code": "USD", 
                },
                "invoicer": {
                   "email_address": config.emailAddress, 
                },
                "primary_recipients": [
                  {
                    "billing_info": {
                      "email_address": payer_email,
                    }, 
                  }
                ],
                "items": [
                  {
                    "name": item_name,
                    "description": item_description,
                    "quantity": quantity,
                    "unit_amount": {
                      "currency_code": "USD",
                      "value": cost, 
                    },
                    "unit_of_measure": "QUANTITY"
                  }, 
                ], 
              })
        }); 

        if (!response.ok) {
            const errorData = await response.json();
            console.error('创建发票失败:', errorData);
            return;
        }

        const invoiceData = await response.json();
        console.log('发票创建成功:', invoiceData);
        // 等待发票创建完成后再发送
        await sendInvoice(invoiceNumber);
    } catch (err) {
        console.error('流程出错:', err.message);
    }
}

3. 额外排查点

  • 确认config.clientId和config.clientSecret是沙箱环境的凭证,不要混用生产环境的密钥。
  • 检查沙箱商家账号的权限,确保该账号拥有创建发票的权限(需为已验证的商家账号)。
  • 验证generateInvoiceNumber生成的编号是否唯一,重复的发票编号会导致创建失败。
  • 调用createInvoice时,也要使用await或者.then()处理异步逻辑,避免调用后直接退出导致请求中断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:06:12