向Intuit/Quickbooks支付API提交令牌化的卡片数据时出错。

4

我正在将Intuit/Quickbooks Payments API集成到现有的电子商务网站中。由于PCI要求,我需要通过JavaScript对卡数据进行标记化处理,然后使用该令牌而不是实际的卡数据提交费用。

为什么会从支付API收到“令牌无效”的错误?

第一次尝试

我遵循了此页面上的说明,其中介绍了如何使用Inuit提供的JavaScript文件对卡片数据进行标记化处理。

<script src="https://js.appcenter.intuit.com/Content/IA/intuit.ipp.payments.sandbox-0.0.3.js"></script>

intuit.ipp.payments.tokenize(
  qbAppToken, {
    card: {
      number: $("#tokenize_cc-number").val(),
      expMonth: $("#tokenize_cc-expmonth").val(),
      expYear: $("#tokenize_cc-expyear").val(),
      cvc: $("#tokenize_cc-cvc").val(),
      address: {
        streetAddress: $("#tokenize_cc-address-street").val(),
        city: $("#tokenize_cc-address-city").val(),
        region: $("#tokenize_cc-address-region").val(),
        country: $("#tokenize_cc-address-country").val(),
        postalCode: $("#tokenize_cc-address-postalcode").val()
      }
    }
  },
  function(token, response) {
    console.log(response);
    if (token != null) {
      console.log(token);
      $cardToken.val(token);
      $paymentForm[0].submit();
    } else {
      console.log("Error during tokenization " + response.code + "; " + response.message + "; " + response.detail + "; " + response.moreinfo);
    }
  });

我得到一个看起来像是卡片令牌的东西:

f9e7a378-c3f2-4343-b0a8-ee376d4ed472

我将该令牌插入到我的表单中并提交表单到我的服务器,然后服务器会使用卡片令牌通过 CURL 向 Payments API 提交一笔收费。

我提交到的终端节点为:

https://sandbox.api.intuit.com/quickbooks/v4/payments/charges

Array
(
    [amount] => 6992.83
    [currency] => USD
    [capture] => true
    [token] => f9e7a378-c3f2-4343-b0a8-ee376d4ed472
    [context] => Array
        (
            [mobile] => false
            [isEcommerce] => true
        )

)

但是,我从支付 API 得到的响应却显示“令牌无效”:

{
  "errors": [{
    "code": "PMT-4000",
    "type": "invalid_request",
    "message": "token is invalid.",
    "detail": "token",
    "infoLink": "https://developer.intuit.com/v2/docs?redirectID=PayErrors"
  }]
}

以下是完整的响应:

HTTP/1.1 400 Bad Request
Server: nginx
Date: Wed, 05 Jun 2019 18:13:20 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 175
Connection: keep-alive
Keep-Alive: timeout=5
Strict-Transport-Security: max-age=15552000
intuit_tid: [redacted]
Set-Cookie: ADRUM_BT=R:0|clientRequestGUID:9ae895d4-44ee-4175-bb47-4e37e95162a819|btId:755|backendSnapshotType:f; Expires=Wed,  5-Jun-2019 18:13:49 GMT; Path=/

{"errors":[{"code":"PMT-4000","type":"invalid_request","message":"token is invalid.","detail":"token","infoLink":"https://developer.intuit.com/v2/docs?redirectID=PayErrors"}]}

我注意到JavaScript信用卡令牌化的说明中提到:“此部分仅适用于OAuth 1.0应用程序。”这可能是一个问题。但我没有看到如何为OAuth 2.0应用程序令牌化卡数据的提及。

解释该错误

我认为“令牌无效”错误指的是我的卡片令牌而不是我的应用程序身份验证令牌。我基于以下两点做出这个假设:
  1. When I change my app authentication token, I get a different error:

    {
      "code": "AuthenticationFailed",
      "type": "INPUT",
      "message": null,
      "detail": null,
      "moreInfo": null
    }
    
  2. Intuit developer relations said that the token endpoint in Intuit's JavaScript file is "incorrect", which indicates that there's a problem with the card token I'm receiving.

联系开发人员关系

Intuit开发人员关系表示:

你遇到错误的原因是,该javascript文件没有在正确的环境下正确创建令牌。

QuickBooks Payments API有两个不同的环境。一个称为沙盒环境,另一个称为生产环境。要为沙盒环境创建令牌,您需要使用此网址:https://sandbox.api.intuit.com/quickbooks/v4/payments/tokens

但是,在该javascript中,令牌的URL是:https://transaction-api-e2e.payments.intuit.net/v2/tokens,这是不正确的。这是我们使用的内部测试环境。在e2e中创建的令牌无法在沙盒中使用。这就是为什么您会得到“令牌无效”的错误。

另一种尝试

在查看API探索器和令牌端点之后,我尝试了不使用Intuit的JavaScript库生成卡片令牌。

这使用与由开发人员关系引用的API Explorer中相同的端点,尽管不存在sandbox.api.intuit.com/v4/payments/tokens,因此我认为这是一个错别字。

POST v4/payments/tokens
FOR IE8/IE9 - POST /quickbooks/v4/payments/tokens/ie
Content type: application/json
Production Base URL: https://api.intuit.com
Sandbox Base URL: https://sandbox.api.intuit.com

jQuery.ajax({
  url: "https://sandbox.api.intuit.com/quickbooks/v4/payments/tokens",
  type: "POST",
  contentType: 'application/json',
  dataType: "json",
  data: JSON.stringify(cardData)
}).done(function(msg) {

  ...

});

结果一样。
我似乎得到了一个卡令牌,但当我通过CURL提交付款时,仍然会收到以下信息:

{
  "errors": [{
    "code": "PMT-4000",
    "type": "invalid_request",
    "message": "token is invalid.",
    "detail": "token",
    "infoLink": "https://developer.intuit.com/v2/docs?redirectID=PayErrors"
  }]
}

出了什么问题?

我向Intuit提交了一个未解决的工单,并在开发者社区论坛发布了一篇帖子。如果我从他们那里收到任何进一步的信息,我将更新此帖子。


加密中使用的公钥可能特定于您的帐户。您可以远程获取其内容或将其复制到您的环境中。我不认为这会破坏目的。另外一点,不要假设当您看到一个好看的值时,您已经加密了预期的数据。您可能会加密空格并获得类似该值的东西。这就是它的工作原理。 - ficuscr
我看了一下,认为这是端到端加密,以便将卡数据中继到 Intuit。然后他们会存储该数据并向您返回一个“令牌”。在未来需要收费时,您可以通过该令牌引用存储的卡数据。 - ficuscr
我认为我的假设也是这样,除了我自己不加密任何东西。我把信用卡信息发送给Inuit,他们会发送一个令牌给我,然后我使用该令牌向信用卡提交费用。问题是我从Inuit那里得到的令牌似乎无效。 - showdev
1
那个“看起来”像令牌的东西确实看起来像UUID...你是从一个看起来像{value: '...'}的JSON对象中提取出来的吗?如果不是,那么我认为有问题。他们文档中的示例令牌看起来并不像UUID。可悲的是,在他们的文档中,该属性仅被描述为字符串。他们甚至没有指定最大长度! - ficuscr
1
@ficuscr 我想那就是了。在测试时,我一直使用相同的“RequestID”发送请求。现在我明白了:“如果服务收到另一个具有相同“RequestID”的请求,则服务将发送与原始请求相同的响应,而不是再次执行操作或返回错误。” 发送不同的“RequestID”似乎可以解决问题。如果您愿意发布这样的答案,我很乐意给您提供奖励! - showdev
显示剩余8条评论
2个回答

1
如果您正在按照此处的说明使用位于https://js.appcenter.intuit.com/Content/IA/intuit.ipp.payments-0.0.3.js的JavaScript文件对信用卡信息进行令牌化,请注意来自开发人员关系的响应:

……在该JavaScript中,令牌的URL为:https://transaction-api-e2e.payments.intuit.net/v2/tokens,这是不正确的。这是我们使用的内部测试环境。在e2e中创建的令牌将无法用于沙盒。这就是为什么您会收到令牌无效错误的原因。

要为沙盒环境创建令牌,您需要使用此URL:https://sandbox.api.intuit.com/quickbooks/v4/payments/tokens

我成功通过AJAX从该Tokens端点请求了一个卡令牌。

此外,在使用卡令牌提交费用时,请务必在标头中发送唯一的RequestID

如果服务接收到具有相同RequestID的另一个请求,它不会再次执行操作或返回错误,而是发送与原始请求相同的响应。(什么是RequestId及其用途)
这就是为什么我在切换到正确的端点后仍然收到“无效令牌”错误的原因。

0

我一直在使用Postman 进行测试(我知道JS不是问题),但API可能有问题。也许这可以帮助解决问题。

卡令牌化:

  • 端点:https://sandbox.api.intuit.com/quickbooks/v4/payments/tokens
  • 头部:Content-Type: application/json
  • 正文(原始)JSON(application / json):

    { "card": { "name": "emulate = 0", "number": "4111111111111111", "expMonth": "02", "address": { "postalCode": "94086", "country": "US", "region": "CA", "streetAddress": "Road Street", "city": "Sunnyvale" }, "expYear": "2020", "cvc": "123" } }

响应:

{
 "value": "7e92f015-820b-4e70-81b9-8ce840c76389"
}

费用(Charge):

  • 端点(Endpoint): https://sandbox.api.intuit.com/quickbooks/v4/payments/charges
  • 标头(Header):Content-Type: application/json
  • 请求 ID(request-id): 随机数
  • 授权(Authorization): OAuth 2.0 访问令牌(59 分钟)
  • 请求正文(Body):JSON(application/json):

    { "currency": "USD", "amount": "10.55", "context": { "mobile": "false", "isEcommerce": "true" }, "token": "7e92f015-820b-4e70-81b9-8ce840c76389" }

响应(Response):

{
"created": "2019-06-17T16:18:43Z",
"status": "CAPTURED",
"amount": "10.55",
"currency": "USD",
"token": "7e92f015-820b-4e70-81b9-8ce840c76389",
"card": {
    "number": "xxxxxxxxxxxx1111",
    "name": "emulate=0",
    "address": {
        "city": "Sunnyvale",
        "region": "CA",
        "country": "US",
        "streetAddress": "Road Street",
        "postalCode": "94086"
    },
    "cardType": "Visa",
    "expMonth": "02",
    "expYear": "2020",
    "cvc": "xxx"
},
"avsStreet": "Pass",
"avsZip": "Pass",
"cardSecurityCodeMatch": "NotAvailable",
"id": "E4JTLAV2QAFF",
"context": {
    "mobile": false,
    "deviceInfo": {},
    "recurring": false,
    "isEcommerce": true
},
"authCode": "546816"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接