cybersource Payment Gateway not able to decrypt paymenttoken

Cybersource production support has clarified issue as below

"On the BAD Case, it seems that the Apple Payload did not contain the "onlinePaymentCryptogram" object within the JSON. The Cryptogram is critical and mandatory. Since the merchant cannot really control this, and since CYBS is just decrypting the payload and uses it, we cannot comment as to why it was missing. The merchant would need to reach out to Apple and/or decrypt the payment themselves locally to check if and why this data was not present, for troubleshooting purposes."

Answered by DTS Engineer in 893921022

Hi @ranjaniOS,

CyberSource's diagnoses is accurate—they are correctly decrypting the payload but the cryptogram simply isn't there.

When Apple Pay generates a payment token, the decrypted paymentData payload has a nested structure that is critical to understand:

{
  "applicationPrimaryAccountNumber": "4111111111111111",
  "applicationExpirationDate": "251231",
  "currencyCode": "840",
  "transactionAmount": 1000,
  "deviceManufacturerIdentifier": "040010030273",
  "paymentDataType": "3DSecure",
  "paymentData": {
    "onlinePaymentCryptogram": "BASE64==",
    "eciIndicator": "07"
  }
}

The onlinePaymentCryptogram lives inside the nested paymentData object`, not at the top level. This is the most common parsing mistake. See my answer on the following post for more details:

Apple Pay Gateway - paymentDataType=EMV - emvData

https://developer.apple.com/forums/thread/814939?answerId=893888022#893888022

Another common cause is the paymentDataType being EMV instead of 3DSecure. Apple Pay returns two distinct payload types depending on the card network and device:

  • 3DSecure: onlinePaymentCryptogram + eciIndicator for remote/online payments
  • EMV: emvData + encrytedPINData for in-store contactless payments only

If your integration receives an EMV type token in an online context, onlinePaymentCryptogram won't exist—it is replaced by emvData. This would explain the scenario you describe above. You can confirm this is the case by logging the raw paymentDataType field on every transaction.

Another thing to verify is if your decryption logic stops at the outer payload and doesn't fully deserialize the inner nested paymentData object. In that case, the cryptogram will appear missing even though it exists in the raw bytes.

A common bug is serializing/passing the outer JSON string to CyberSource without deserializing and re-serializing the inner paymentData object, causing it to arrive as an escalated string rather than a JSON object.

Lastly, you may have invalid token handling in your client-side logic. Confirm your client-side code processes the PKPaymentToken object correctly:

// ❌ WRONG - paymentData is raw Data, not yet a parsed JSON object
let tokenString = String(data: token.paymentData, encoding: .utf8)
// Sending raw paymentData bytes directly without proper base64/JSON handling

// ✅ CORRECT
let paymentData = token.paymentData
let jsonObject = try JSONSerialization.jsonObject(with: paymentData)
// Serialize the full structure including nested paymentData

Passing the raw Data object as a string, or re-encoding it incorrectly before sending to your backend, can corrupt the nested structure.

Cheers,

Paris X Pinkney |  WWDR | DTS Engineer

Hi @ranjaniOS,

CyberSource's diagnoses is accurate—they are correctly decrypting the payload but the cryptogram simply isn't there.

When Apple Pay generates a payment token, the decrypted paymentData payload has a nested structure that is critical to understand:

{
  "applicationPrimaryAccountNumber": "4111111111111111",
  "applicationExpirationDate": "251231",
  "currencyCode": "840",
  "transactionAmount": 1000,
  "deviceManufacturerIdentifier": "040010030273",
  "paymentDataType": "3DSecure",
  "paymentData": {
    "onlinePaymentCryptogram": "BASE64==",
    "eciIndicator": "07"
  }
}

The onlinePaymentCryptogram lives inside the nested paymentData object`, not at the top level. This is the most common parsing mistake. See my answer on the following post for more details:

Apple Pay Gateway - paymentDataType=EMV - emvData

https://developer.apple.com/forums/thread/814939?answerId=893888022#893888022

Another common cause is the paymentDataType being EMV instead of 3DSecure. Apple Pay returns two distinct payload types depending on the card network and device:

  • 3DSecure: onlinePaymentCryptogram + eciIndicator for remote/online payments
  • EMV: emvData + encrytedPINData for in-store contactless payments only

If your integration receives an EMV type token in an online context, onlinePaymentCryptogram won't exist—it is replaced by emvData. This would explain the scenario you describe above. You can confirm this is the case by logging the raw paymentDataType field on every transaction.

Another thing to verify is if your decryption logic stops at the outer payload and doesn't fully deserialize the inner nested paymentData object. In that case, the cryptogram will appear missing even though it exists in the raw bytes.

A common bug is serializing/passing the outer JSON string to CyberSource without deserializing and re-serializing the inner paymentData object, causing it to arrive as an escalated string rather than a JSON object.

Lastly, you may have invalid token handling in your client-side logic. Confirm your client-side code processes the PKPaymentToken object correctly:

// ❌ WRONG - paymentData is raw Data, not yet a parsed JSON object
let tokenString = String(data: token.paymentData, encoding: .utf8)
// Sending raw paymentData bytes directly without proper base64/JSON handling

// ✅ CORRECT
let paymentData = token.paymentData
let jsonObject = try JSONSerialization.jsonObject(with: paymentData)
// Serialize the full structure including nested paymentData

Passing the raw Data object as a string, or re-encoding it incorrectly before sending to your backend, can corrupt the nested structure.

Cheers,

Paris X Pinkney |  WWDR | DTS Engineer

cybersource Payment Gateway not able to decrypt paymenttoken
 
 
Q