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

在YII2中集成BitPay时创建发票遇Token无效/禁用问题求助

YII2集成BitPay时Token无效/禁用问题排查与解决

问题背景

在YII2框架中使用PHP集成BitPay作为支付方式,已参照官方文档完成私钥生成、Token获取步骤,但创建发票时抛出异常:

"BITPAY-INVOICE-CREATE: Failed to create invoice-> failed to serialize Invoice object : failed to retrieve HTTP response body : Token is disabled"

偶尔也会提示Token无效,更换facade或客户端创建方法后问题仍存在。

已执行的操作步骤

  1. 生成并存储密钥对
$privateKey = PrivateKey::create(<FILENAME>)->generate();
$storageEngine = new EncryptedFilesystemStorage(<PASS>);
$storageEngine->persist($privateKey);
$privateKey = $storageEngine->load(<FILENAME>);

$publicKey = $privateKey->getPublicKey();
$sin = $publicKey->getSin()->__toString();
  1. 请求POS Token并创建发票
$resourceUrl = 'https://test.bitpay.com/tokens';
$facade = 'pos';

$postData = json_encode([
    'id'     => $sin,
    'label'  => 'Token',
    'facade' => $facade
]);

$curlCli = curl_init($resourceUrl);
curl_setopt($curlCli, CURLOPT_HTTPHEADER, [
    'x-accept-version: 2.0.0',
    'Content-Type: application/json',
    'x-identity' => $publicKey->__toString(),
    'x-signature' => $privateKey->sign($resourceUrl . $postData),
]);
curl_setopt($curlCli, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curlCli, CURLOPT_POSTFIELDS, stripslashes($postData));
curl_setopt($curlCli, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($curlCli);
$resultData = json_decode($result, TRUE);
curl_close($curlCli);

$token = $resultData['data'][0]['token'];

// 创建发票代码
$bitpay = new PosClient($token, 'test');
$invoice = new Invoice(<AMOUNT>, Currency::USD);
$invoice->setToken($token);
$invoice->setToken($token); // 重复设置Token
$invoice->setFullNotifications(true);
$invoice->setExtendedNotifications(true);

$client = new Buyer();
$client->setName(<NAME>);
$client->setEmail(<MAIL>);
$client->setAddress1(<ADDRESS>);
$client->setCountry(<COUNTRY>);
$client->setLocality(<CITY>);
$client->setNotify(true);
$invoice->setBuyer($client);

try {
    $new_invoice = $bitpay->createInvoice($invoice, Facade::POS, false);
} catch (\Exception $e) {
    print_r($e->getMessage());
}
  1. Token获取响应
{"data": 
 [{"policies": 
 [{"policy":"id", 
 "method":"inactive", 
 "params":["Tf3wXWuwfT1TmenHF21P1nYZ7BeyrYNdiwo"] 
 }], 
 "token":"<TOKEN>", 
 "facade":"pos", 
 "label":"Token", 
 "dateCreated":1696926578101, 
 "pairingExpiration":1697012978101, 
 "pairingCode":"<CODE>" 
 }] 
}

核心问题与解决步骤

1. 激活未配对的Token

从响应的policies字段可见,当前Token处于**inactive(未激活)**状态,这是报错的直接原因:

  • 登录BitPay测试后台
  • 进入Settings > API Tokens页面
  • 找到响应中返回的pairingCode,点击激活该Token
  • 确认Token状态变为active后再发起发票创建请求

2. 修正Token与客户端的Facade匹配

  • 使用PosClient时,必须确保获取的Token是pos facade类型,且后台已为该Token分配POS权限
  • 若切换为merchant或payout facade,需重新生成对应类型的Token并完成激活,避免跨facade使用Token

3. 规范请求签名与参数格式

  • 手动生成签名时,严格按照BitPay要求拼接内容:资源URL + 原始POST JSON字符串,不要对JSON做stripslashes等额外处理,否则会导致签名验证失败
  • 确保请求头x-accept-version与API版本兼容,建议使用SDK默认版本,避免手动设置不匹配的版本号

4. 使用SDK内置流程管理Token

手动用curl请求Token易出现格式错误,建议改用SDK标准方法创建客户端:

// 初始化加密存储引擎
$storageEngine = new EncryptedFilesystemStorage(<PASSWORD>);
// 自动处理Token生成、配对与存储
$bitpay = PosClient::create()
    ->withStorageEngine($storageEngine)
    ->withEnvironment('test')
    ->build();

// 首次运行生成配对码,在后台激活后SDK会自动保存有效Token
$pairingCode = $bitpay->getPairingCode('pos', 'My Store POS Token');

5. 清理冗余发票参数

  • 移除重复的$invoice->setToken($token)调用,SDK会自动从客户端实例中读取有效Token
  • 检查发票金额、买家信息等参数格式,确保符合BitPay API的字段要求(如金额为正数、邮箱格式正确)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:39:53