Payload provides metadata that includes the information based on if the consumer uses the PAN, or token.
Field |
Description |
---|---|
card |
Card data associated with the PAN used for the purchase. Supplied if the indicated payload type is FULL or PAYMENT and the SRC system determines that a PAN-based payload is returned. Note: Either a Card or a Payment Token credential is returned, never both Format: Card structure |
token |
Payment Token data associated with the PAN used for the purchase. Supplied if the indicated payload type is FULL or PAYMENT and the SRC system determines that a Payment Token- based payload is returned. Note: Either a Card or a Payment Token credential is returned, never both Format: PaymentToken structure |
paymentAccountReference |
The Payment Account Reference (PAR) associated with the cardholder account that uniquely identifies the account to which the payment card is associated. Format: String |
dynamicData |
Dynamic data (cryptograms) applicable for transactions. If Click to Pay facilitates Issuer Authentication (3DS), then CAVV will be provided in the dynamic data. Format: List of DynamicData structures |
billingAddress |
Billing address of the selected card. Format: Address structure |
shippingAddress |
Shipping address of the consumer; supplied when available, for example:
Format: Address structure |
consumer |
Consumer's information. Format: Consumer structure |
panExpirationYear |
The year when the account number is set to expire. Format: Numeric; 4 digits |
threeDsOutputData |
(Deprecated) Result of 3DS payment authentication. |
{
"card": {
"primaryAccountNumber": "430...08",
"panExpirationMonth": "12",
"panExpirationYear": "2023",
"cardholderFullName": ". ",
"cardholderFirstName": ". ",
"cardholderLastName": ". "
},
"billingAddress": {
"addressId": "e43. 02",
"countryCode": "US"
},
"shippingAddress": {
"addressId": "5c4. 01",
"line1": ". ",
"city": ". ",
"state": ". ",
"zip": ". ",
"countryCode": "US"
},
"consumer": {
"firstName": ". ",
"lastName": ". ",
"fullName": ". ",
"emailAddress": "[email protected]",
"mobileNumber": {},
"countryCode": "US",
"languageCode": "en-US"
},
"threeDsOutputData": []
}
{
"token": {
"paymentToken": "489...69",
"tokenExpirationMonth": "12",
"tokenExpirationYear": "2024"
},
"paymentAccountReference": "V00...23",
"dynamicData": [
{
"dynamicData": "AgA...A=",
"dynamicDataType": "CARD_APPLICATION_CRYPTOGRAM_LONG_FORM",
"dynamicDataExpiration": "Thu Jun 25 03:23:13 GMT 2020"
},
{
"dynamicDataValue": "Y2F...g=",
"dynamicDataType": "CARDHOLDER_AUTHENTICATION_CRYPTOGRAM"
}
],
"billingAddress": {
"addressId": "b3f...02",
"countryCode": "GB"
},
"shippingAddress": {
"addressId": "89e...01",
"line1": "...",
"city": "...",
"state": "ON",
"zip": "K1G 4B5",
"countryCode": "CA"
},
"consumer": {
"firstName": "...",
"lastName": "...",
"fullName": ". ",
"emailAddress": ". @gmail.com",
"mobileNumber": {},
"countryCode": "US",
"languageCode": "en-US"
},
"threeDsOutputData": []
}
3DS provides additional fields in the response.
"assuranceData": {
"verificationData": [
{
"methodResults": {
"transStatus": "Y",
"dsTransId": "06c...16",
"acsTransId": "6f5...09"
}
}
],
"eci": "05"
}
The following Java code, using the JOSE4j API jose4j-0.6.5.jar, provides an example of decrypting the payload.
package ...;
import java.security.MessageDigest;
import javax.crypto.spec.SecretKeySpec; import org.jose4j.jwe.JsonWebEncryption;
public class DecryptJWE {
public static String decryptJWE(String secret, String jwe) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(secret.getBytes("UTF-8"));
JsonWebEncryption jweDecryptor = new JsonWebEncryption(); jweDecryptor.setCompactSerialization(jwe); jweDecryptor.setKey(new SecretKeySpec(digest, "AES"));
return jweDecryptor.getPlaintextString();
}
}
var jose = require('node-jose'); var crypto = require('crypto');
module.exports = {
decryptJWE: function (secret, payload) {
return new Promise(function (resolve, reject) {
var SS_Hashed =
crypto.createHash('sha256').update(secret).digest('hex'); jose.JWK.asKey({
kty: 'oct', k: Buffer.from(SS_Hashed,
'hex')
})
.then(function (key) {
jose.JWE.createDecrypt(key)
.decrypt(payload)
.then(function (result) {
resolve(result);
})
.catch(function (error) {
reject(error);
});
})
.catch(function (error) {
reject(error);
});
});
}
};
This code snippet is used for creating PAN JWE on the browser side. This example uses the node-jose library in browserify format.
// getNodeJoseLib(); Get node-jose library in browserify format
// Code to generate JWE using node-jose library
/**
* @param kid kid for public certificate. Contact Visa representative for this value
* @param keys Public key to be used for encryption.
Contact Visa representative for *
@param payload Card information to be encrypted,
{"card":{ "primaryAccountNumber":"424..2", "panExpirationMonth":"10",
.."panExpirationYear":"2022", "cardSecurityCode":"123",
.."cardholderFullName":"cardholder name"}
}
* @param cb Returning encrypted PAN as JWE string to this callback function */
function generateJWE(kid, keys, payload, cb) {
const keyInput = {
"kty": "RSA",
"e": keys.e, // Public key exponent "kid": kid,
"use": "enc",
"n": keys.n, // Public key modulus "alg": "RSA-OAEP-256",
"ext_content": "payload"
};
jose.JWK.asKey(keyInput)
.then((key) => {
console.log("JWK ", JSON.stringify(key)); const contentAlg = 'A25..CM';
let options = {
format: 'compact',
contentAlg: contentAlg, fields: {
kid: key.kid, typ: 'JOSE',
iat: Date.now(), alg: key.alg, enc: contentAlg
}
};
jose.JWE.createEncrypt(options, key).update(payload).
final().then((serializedJWE) => {
console.log("Encrypted data: ", JSON.stringify(serializedJWE));
cb(serializedJWE);
}, (error) => {
console.log("Error occurred: ", error.message); cb(null);
});
}, (error) => {
console.log("Error occurred: ", error.message); cb(null);
})
}
The encryption key provided during onboarding is used to encrypt and decrypt payloads. JSON Web Encryption (JWE) content should be signed or encrypted using the shared secret that was provided to client at the time of onboarding.
Visa uses JSON Web Encryption (JWE) to encode sensitive field level information. Encrypted input parameters should be constructed before sending them in API requests.
Visa Installment Solutions APIs use the following naming convention for fields that require encryption in this document.
"enc<FIELD>" : "JWE ( ... ) "
See the complete specification for JWE: https://tools.ietf.org/html/draft-ietf-jose-json-web- encryption-40.
BASE64URL (UTF8 (JWE Header)) || ‘.’ ||
BASE64URL (JWE Encrypted Key) || ‘.’ || BASE64URL (JWE IV) || ‘.’ ||
BASE64URL (JWE Ciphertext) || ‘.’ || BASE64URL (JWE Authentication Tag)
The conventions are as follows:
Note: The JWE Protected Header is input as the AAD (Additional Authenticated Data) parameter of the authenticated encryption (AES-GCM) of the “text to encrypt”.
"header": {
"alg": "RSA-OAEP-256""typ": "JOSE",
"kid": "50charAPIKey", // API key "enc": "A256GCM"
}
"header": {
"alg": "AGCM256KW""typ": "JOSE",
"tag": "<128bitvalue>", // HMAC generated from applying AES-256-GCM-KW to the CEK
"kid": "50charAPIKey", // API key "enc": "AGCM256"
}
"header": {
"alg": "AGCM256KW""typ": "JOSE",
"tag": "<128bitvalue>", // HMAC generated from applying AES-256-GCM-KW to the CEK
"kid": "50charAPIKey", // API key "enc": "AGCM256"
}
“encrypted_key”: “UghIOgu ... MR4gp_A=”, “iv”: “AxY8DctDa….GlsbGljb3RoZQ=”,
“ciphertext”: “KDlTthhZTGufMY…….xPSUrfmqCHXaI9wOGY=”, “tag”: “Mz-VPPyU4…RlcuYv1IwIvzw=”