Passing Credit Card Number into LP
Project Summary
This Document outlines the project scope related to the Citi - PCI Compliance issue with sending CCN (Credit Card Number) project.
Business Requirements
Today, Citi passes the full credit card number (CCN) via an authenticated token as part of the JWT, and it gets displayed on the Customer Info widget. However, Citi can no longer send and display the CC number in this way due to PCI compliance regulations.
Nevertheless, agents still need to access this information by copying and pasting it into Eclipse, UCD, and Olympus. Implementing a secure form requesting an account number for all of these chats is not feasible.
High-Level Requirements
Find a way to show the CCN to the agent without disrupting PCI compliance on the account.
Option #1 - Decryption with Citi API
- Citi to create a symmetric key (Secret key) or asymmetric keys pair (RSA private/public keys).
- Citi to use a symmetric key or asymmetric public key to encrypt CCN in JWT.
- Citi to expose API endpoint for CCN decryption:
- API endpoint should be accessible externally;
- API endpoint should accept encrypted version of CCM and respond with decrypted;
- API endpoint should implement authentication.
- Create a FaaS function of type “Conversational Command” with similar functionality:
javascript:
const { Toolbelt, ConversationContentTypes, LpServices } = require("lp-faas-toolbelt");
const lpClient = Toolbelt.LpClient();
const httpClient = Toolbelt.httpClient();
const accountId = process.env.BRAND_ID;
async function lambda(input, callback) {
try {
const { conversationId } = input.payload;
const record = await getMessageHistory(conversationId);
if(record && record.sdes && record.sdes.events) {
console.info(JSON.stringify(record.sdes.events));
const customerInfo = record.sdes.events.find((sde) => sde.sdeType === 'CUSTOMER_INFO');
if(customerInfo) {
const encryptedCCN = customerInfo.customerInfo.customerInfo.accountName;
const decryptedCCN = decryptStringFromEndpoint(encryptedCCN);
console.info("DECRYPTED_CCN: " + decryptedCCN);
callback(null, decryptedCCN);
} else {
callback(null, "No SDEs found");
}
} else {
callback(null, "No record found");
}
} catch(e) {
callback(e, null);
}
}
async function getMessageHistory(convId) {
try {
const messagingHistory = await lpClient(LpServices.MSG_HIST, `/messaging_history/api/account/${accountId}/conversations/conversation/search?v=2`, {
method: "POST",
json: true,
body: {
conversationId: convId,
contentToRetrieve: [ConversationContentTypes.SDES],
cappingConfiguration: "CustomerInfoEvent:1:desc,PersonalInfoEvent:1:desc,CustomerInfoEventEnriched:1:desc,PersonalInfoEventEnriched:1:desc,ConversationSummaryEvent:1:desc,CartStatusEvent:1:desc,ServiceActivityEvent:1:desc,MarketingCampaignInfoEvent:1:desc,PurchaseEvent:1:desc,ViewedProductEvent:1:desc,VisitorErrorEvent:1:desc,LeadEvent:1:desc,SearchContentEvent:1:desc"
},
});
if (!messagingHistory || !messagingHistory.conversationHistoryRecords || !messagingHistory.conversationHistoryRecords[0]) {
console.info(convId, "Conversation not exist");
return null;
}
return messagingHistory.conversationHistoryRecords[0];
} catch (err) {
throw err;
}
}
const decryptStringFromEndpoint = function(toDecrypt) {
const request = {
url: process.env.DECRYPTION_URL,
method: "POST"
};
const data = {
toDecrypt
}
let response = await httpClient(request.url, {
method: request.method,
headers: {
"Content-Type": "application/json",
"Authorization": "..."
},
body: JSON.stringify(data),
simple: false,
resolveWithFullResponse: true
});
switch (response.statusCode) {
case 200, 201:
return JSON.parse(response.body);
default:
throw `Recieved unexpected status code ${
response.statusCode
} during request`;
}
};
- Modify authenticated SDE, where encrypted CCN is sent in JWT. In the example of the function above, it is sent in CustomerInfo.AccountName SDE.
- Deploy FaaS function.
- Repeat the steps above for each env, where the solution should be deployed.
Option #3 - Decryption with Citi custom widget
- Citi to create a symmetric key (Secret key) or asymmetric keys pair (RSA private/public keys).
- Citi to use a symmetric key or asymmetric public key to encrypt CCN in JWT.
- Citi to utilize any existing or to create a new custom widget to decrypt CCN and present it in the widget
- Custom widget to store a symmetric key (Secret key) or RSA private key.
- Custom widget to read encrypted CCN from authenticated SDEs.
- Custom widget to perform decryption of CCN and present in the widget.
Option #4 - CCN lookup with Citi custom widget
- Citi to utilize any existing or to create a new custom widget to lookup CCN info in the Citi CRM/other system, based on other customer-related data points (email, customer ID, etc.)
Option #5 - CCN mapping with other customer-specific attributes and manual lookup
- Citi to define any customer-related attribute in the auth JWT (email, customer ID, etc.);
- Agent to manually copy it from the Customer Info widget;
- Agent to manually make a lookup in Citi CRM by attribute to find CCN;
- Agent CCN for their needs;
Agent UX (for Option #1 and Option #2)
- The CCN is stored in encrypted way on LP side;
- The agent starts typing something like “/Decrypt” (the command is tied to the function name) and will be offered with available commands:

- Selecting of the command will execute the FaaS function and provide the CCN to the agent.
- Provided CCN:
- is not recorded anywhere
- presented only once
- only to the agent, which executed the command.

Hours
Component | Capabilities Included | Hours |
LivePerson Professional Services Engagement | FaaS Function Dev and QA | 10-15 hours |
Example of a Private Key
-----BEGIN ENCRYPTED PRIVATE KEY-----\n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\n-----END ENCRYPTED PRIVATE KEY-----\n