Secure Overlay API
The Secure Overlay is a way for PDCflow customers/partners to easily encrypt and tokenize credit card and bank account numbers from their own sites/software without PCI Compliance concerns.
It provides a tight integration between account management software and PDCflow’s Payment Processing Products and takes the core software platform out of PCI Scope. Enter credit card or bank account data from within your software system using our secure overlay form. The sensitive data field resides on our secure, PCI Level 1 Certified servers, and overlays the data entry field on the core software’s payment page.
Sensitive Data is encrypted, tokenized, and stored in a secure vault. The token is then returned to your software system through the HTML MessageChannel api, eliminating your transmission of any PCI relevant data.
Implementation
Your HTML page
Iframe src
Test url:
https://wsdemo.pdc4u.com/SecureOverlay/v2_0?iframeId=myIframe
Live url:
https://ws.pdc4u.com/SecureOverlay/v2_0?iframeId=myIframe
<script type="text/javascript">
...
window.addEventListener('message', receiveMessage, false);
const remoteDomain = 'https://wsdemo.pdc4u.com';
let preType = 'CCN';
//These are used to set up and communicate through the dedicated channel
const channel1 = new MessageChannel();
let port1 = channel1.port1;
/*
* This function will be used once, to handle the PRELOAD function
* On the PRELOAD function, we will set up a dedicated MessageChannel to converse between iFrame and parent page
*/
function receiveMessage(event) {
if(event.origin !== remoteDomain) {
console.log('remote origin: ' + event.origin);
return;
}
if (event.data.function === 'PRELOAD') {
//Establish the MessageChannel and handle any preload data (if you already have a token, pass it here)
}
}
function receivedPortMessage(e) {
//Once the MessageChannel is established, any communication from the overlay will be received here
}
function sendMessage(data) {
port1.postMessage(data);
}
function tokenizeData() {
var requiredData = {};
...
sendMessage(data);
}
...
</script>
The secure overlay uses the HTML MessageChannel()
protocol. This allows messages to be posted from the parent website (your page) to the iframe and back.
Thus, the parent page can initiate the tokenization and when the Credit Card or Bank Account number, entered on our page, is tokenized,
the token can be returned to the parent page.
The iframeId
in the URL is not required; however, it is useful in identifying which iframe has loaded in the case the multiple SecureOverlay
iframes are loaded on the same page.
API Functions
The API can be called with these functions. Each represents a different function to be executed on the Secure Overlay field.
Attribute | Description |
---|---|
PRELOAD
JSONN/A
|
This function can be used to preload the field with an existing token, style the field, and define some functionality. See object definition below. |
PROCESS
JSONN/A
|
The command to tokenize the value in the Secure Overlay field. See object definition below. |
PATCH
JSONN/A
|
The command to make changes to an existing token. See object definition below. |
BULK_UPLOAD
JSONN/A
|
The command to upload a bulk file. This is to be used with the file upload page. The endpoint expects a csv file with all columns used for processing a transaction, and will return a JSON object with a list of the data, including tokens, suitable for processing the transactions. See object definition below. |
BILLING
JSONN/A
|
The command to tokenize for PDCFlow billing. This will tokenize the card or bank account to be used for billing purposes.
The token returned can only be used by PDCFlow for monthly invoice payment. The required data is the same as the processData .
See object definition below.
|
CLEAR
JSONN/A
|
Will clear all characters in the input field. See object definition below. |
Preload Data
Preload Data Object
{
"function": "PRELOAD",
"backgroundColor": "#fff",
"fontSize": "12",
"token": "thisIsAToken1234",
"focus": "false",
"shouldNotify": "true",
"clearFieldOnFocus": "true",
"dataType": "CCN",
"placeholder": "Card Number"
}
Attribute | Description |
---|---|
function
Alpha7
|
The function to be performed by the remote javascript.
Valid value(s):
PRELOAD |
backgroundColor
AlphanumericN/A
|
Set the background color of the input field using a CSS color.
Format: Text (red, blue), Hexadecimal (#RRGGBB), RGB (rgb(255,0,0))
|
fontSize
AlphanumericN/A
|
Set the size of the font in the input box. Append the unit to the font size (12px, 2em, 12pt, etc).
Format: 12px
|
token
Alphanumeric16
|
An existing token to prepopulate the field with. |
focus
Boolean5
|
Whether or not to set focus to the input field on page load. If you preload the token, it is not recommended that
you focus on the field, as that may clear the preloaded token, based on whether clearFieldOnClick is true or not.
Valid value(s):
true , false |
shouldNotify
Boolean5
|
Define whether change events on the data field should send a NOTIFY post message. See object definition below for potential notifications.
Valid value(s):
true , false Default: false
|
clearFieldOnClick
Boolean5
|
Use this to define whether the data field should automatically clear its contents when focus is put on the field.
Valid value(s):
true , false Default: true
|
dataType
Alpha3
|
Use this to define whether the field is being used for card or bank account data. This only affects the real-time validation as handled by the shouldNotify events. This will be passed in again in the Process Data object to define the final dataType to tokenize.
Valid value(s):
CCN - Credit card, BAN - Bank account numberDefault: CCN
|
placeholder
Alpha32
|
This will set a placeholder value in the data entry field. |
Process Data
Process Data Object
{
"function": "PROCESS",
"companyId": 1234,
"apiKey": "yourApiKeyHere",
"dataType": "CCN",
"ccExpMonth": "12",
"ccExpYear": "2024",
"routingNumber": "",
"bankAccountType": "",
"authorizedForFutureUse": "true",
"secondName": ""
}
Attribute | Description |
---|---|
function
Alpha7
|
The function to be performed by the remote javascript. PROCESS is used for general data tokenization. BILLING is used to create a token that will be used by PDCflow to process your company's invoice.
Valid value(s):
PROCESS , BILLING Note: If a token has already been created and a
PROCESS request is sent, and we detect no changes in the secure overlay field, we will treat the request as a PATCH request |
apiKey
AlphanumericN/A
|
Your PDCFlow APIKey for tokenizing data.
|
companyId
Numeric8
|
Your PDCFlow Company Id. |
dataType
Alpha3
|
The type of data you are tokenizing.
Valid value(s):
CCN - Credit card, BAN - Bank account number |
ccExpMonth
Numeric2
Conditional
|
The expiration month of the card. Required for dataType=CCN
Format: MM
|
ccExpYear
Numeric4
Conditional
|
The expiration year of the card. Required for dataType=CCN
Format: YYYY
|
routingNumber
Numeric9
Conditional
|
The routing number for the bank that the bank account number is associated with. Required for dataType=BAN
|
bankAccountType
Alpha8
Conditional
|
The type of account the bank account number is. Required for dataType=BAN
Valid value(s):
CHECKING , SAVINGS |
authorizedForFutureUse
Boolean5
Required
|
Whether the card number or bank data can be used for future transactions. Setting this to false will result in the token being usable for one transaction
(including CREDIT and VOID of that transaction) but any future transaction with this token will be blocked.
|
secondName
AlphanumericN/A
|
This parameter can be used to validate the values are equal between two Secure Overlay fields. If you have a second Secure Overlay iframe on
the page and you want to validate that the user has entered the same value in both Secure Overlay fields, you can pass in the name of the second
iframe and SecureOverlay will validate that the values in the fields are equal.
|
Patch Data
Patch Data Object
{
"function": "PATCH",
"companyId": 1234,
"apiKey": "yourApiKeyHere",
"dataType": "CCN",
"ccExpMonth": "12",
"ccExpYear": "2024",
"routingNumber": "",
"bankAccountType": "",
"existingToken": "ThisIsAToken1234",
"authorizedForFutureUse": "true",
"secondName": ""
}
Attribute | Description |
---|---|
function
Alpha7
|
The function to be performed by the remote javascript. A PATCH request will update an existing token with the provided data.
Valid value(s):
PATCH |
apiKey
AlphanumericN/A
|
Your PDCFlow APIKey for tokenizing data.
|
companyId
Numeric8
|
Your PDCFlow Company Id. |
dataType
Alpha3
|
The type of data you are tokenizing.
Valid value(s):
CCN - Credit card, BAN - Bank account number |
ccExpMonth
Numeric2
Conditional
|
The expiration month of the card. Required for dataType=CCN if ccExpYear is present.
Format: MM
|
ccExpYear
Numeric4
Conditional
|
The expiration year of the card. Required for dataType=CCN if ccExpMonth is present.
Format: YYYY
|
routingNumber
Numeric9
|
The routing number for the bank that the bank account number is associated with. |
bankAccountType
Alpha8
|
The type of account the bank account number is. Valid value(s):
CHECKING , SAVINGS |
authorizedForFutureUse
Boolean5
|
Whether the card number or bank data can be used for future transactions. Setting this to false will result in the token being usable for one transaction
(including CREDIT and VOID of that transaction) but any future transaction with this token will be blocked.
|
secondName
AlphanumericN/A
|
This parameter can be used to validate the values are equal between two Secure Overlay fields. If you have a second Secure Overlay iframe on
the page and you want to validate that the user has entered the same value in both Secure Overlay fields, you can pass in the name of the second
iframe and SecureOverlay will validate that the values in the fields are equal.
|
Bulk Upload
Bulk Upload Request
{
"function": "BULK_UPLOAD",
"companyId": 1234,
"apiKey": "yourApiKeyHere",
"dataType": "CCN",
"bulkType": "TRANSACTION"
}
Attribute | Description |
---|---|
function
Alpha7
|
The function to be performed by the remote javascript. BULK_UPLOAD is used for uploading the bulk csv file.
Valid value(s):
BULK_UPLOAD |
apiKey
AlphanumericN/A
|
Your PDCFlow APIKey for tokenizing data.
|
companyId
Numeric8
|
Your PDCFlow Company Id. |
dataType
Alpha3
|
The type of data you are tokenizing.
Valid value(s):
CCN - Credit card, BAN - Bank account number |
bulkType
Alpha11
|
Which type of bulk/validation/response is expected?
Valid value(s):
TRANSACTION - Bulk file includes all details for transactions. |
Bulk Upload CSV
Header row (card):
FIRST_NAME, LAST_NAME, STREET_ADDRESS_ONE, CITY, STATE, ZIP, COUNTRY, PAYMENT_AMOUNT, FEE_AMOUNT, ACCOUNT_NUMBER, EMAIL_ADDRESS, PHONE_NUMBER, MEMO, CARD_NUMBER, CARD_MONTH, CARD_YEAR, CARD_CODE, POST_AUTHORIZATION
Header row (check):
FIRST_NAME, LAST_NAME, STREET_ADDRESS_ONE, CITY, STATE, ZIP, COUNTRY, PAYMENT_AMOUNT, FEE_AMOUNT, ACCOUNT_NUMBER, EMAIL_ADDRESS, PHONE_NUMBER, MEMO, BANK_ACCOUNT_NUMBER, BANK_ROUTING_NUMBER, BANK_ACCOUNT_TYPE
Required card fields:
FIRST_NAME
, LAST_NAME
, PAYMENT_AMOUNT
, ACCOUNT_NUMBER
, CARD_NUMBER
, CARD_MONTH
, CARD_YEAR
Required check fields:
FIRST_NAME
, LAST_NAME
, PAYMENT_AMOUNT
, ACCOUNT_NUMBER
, BANK_ACCOUNT_NUMBER
, BANK_ROUTING_NUMBER
, BANK_ACCOUNT_TYPE
The columns can be in any order and any combination of the non-required fields may be present, as long as they are specified in the header row and each row has a value (or empty value) for them. See the Object Definition below.
Clear
Clear Data Object
{
"function": "CLEAR"
}
Attribute | Description |
---|---|
function
Alpha5
|
The function to be performed by the remote javascript.
Valid value(s):
CLEAR |
Post Message Handling
These are the definitions of the objects the integrating website can expect to receive in a posted message.
Attribute | Description |
---|---|
PRELOAD
|
The iframe will post a message when it is loaded and ready to establish a MessageChannel and set any preload data. See object definition below. |
NOTIFY
|
The iframe will post messages pertaining to changes in the data field. See object definition below. |
RESPONSE
|
The iframe will post a message with the response to the tokenization request. This will include both success and/or error messages. See object definition below. |
Preload Handling
Preload Object
{
"function": "PRELOAD",
"id": "secondIframeId"
}
Attribute | Description |
---|---|
function
Alpha7
|
The function that should be handled by the integrating website. When this message is received, the iframe is loaded and ready to handle a postMessage with the preloadData .
Valid value(s):
PRELOAD |
id
AlphaNumericN/A
|
The id of the iframe containing the Secure Overlay field. This is particularly useful for determining which field is ready if 2 Secure Overlay iframes are loaded on a single page. |
Notify Data
Notify Data Object
{
"function": "NOTIFY",
"code": "001",
"message": "Data in field changed to valid.",
"cardType": "VISA"
}
Attribute | Description |
---|---|
function
Alpha7
|
The function that identifies this post message.
Valid value(s):
NOTIFY |
code
Alpha6
|
A code to define which event has happened to the data field.
Valid value(s):
Definitions:001 , 002 , 003 , 004 , 005 , 006 , 007 , 008 , 009 , 010 001 - Enter button pressed on secure overlay field. SecureOverlay prevents any action happening when the user pushes Enter while focused on the Secure Overlay field. This notification event allows the integrator to handle this event if they desire.002 - Secure overlay field is no longer empty.003 - Secure overlay field changed to empty.004 - Value in field is no longer valid. - The validation here will be defined by the dataType in the PRELOAD message.005 - Value in field changed to valid. - The validation here will be defined by the dataType in the PRELOAD message.006 - Card type. - As a card is entered, the card type will be passed once it can be determined.007 - Hostname mismatch. - When initially establishing the port, if the postMessage does not match the hostname of the parent page, this notification will be triggered. In most cases, this can be ignored, as browser
extensions and other browser plugins may trigger postMessages that are not from the parent page.008 - Connection ports established. - This event is sent when the initial port connections have been established. Any communication after this event will/must be through the established port.009 - Focus out of secure overlay field. - This notification event will be triggered when the user clicks into a secure overlay field.010 - Focus is on secure overlay field. - This notification event will be triggered when the user clicks outside of the secure overlay field |
message
Alphanumeric48
|
The message related to the NOTIFY event. Defined in the code definition above.
|
cardType
Alphanumeric48
|
The cardType for the entered data. This is only returned with code value of 6.
Valid value(s):
More types may be detected in the future.
VISA , MASTERCARD , AMERICAN_EXPRESS , DISCOVER , UNKNOWN |
Response Handling
Single Token Response Object
{
"function": "RESULT",
"result": "ERROR",
"token": "",
"cardType": "VISA",
"mask": "4444441111",
"errorList": [
{
"code": "10003",
"description": "Field invalid",
"fieldName": "ccExpYear"
}
]
}
Attribute | Description |
---|---|
function
Alpha8
|
The function to be performed by the remote javascript.
Valid value(s):
RESPONSE |
result
Alpha7
|
The result of the tokenization request. PRELOAD will be returned only if an existing token was preloaded and was not overwritten with new data.
Valid value(s):
OK , ERROR , PRELOAD |
token
Alphanumeric16
|
The token that represents the encrypted data in the PDCFlow system. |
cardType
Alpha15
|
The type of card number that was tokenized, if the data was a card number.
Valid value(s):
VISA , MASTERCARD , DISCOVERY , AMERICAN_EXPRESS , UNKNOWN |
mask
Numeric10
|
The mask for the data that was tokenized. For a card, this consists of the first 6 numbers and the last 4 numbers of the card. For a bank account number, this consists of the last 3 numbers of the bank account number. |
errorList
ListN/A
|
A list of error objects. See object definition below
|
Bulk Response Handling
Bulk Response Object
{
"function": "RESPONSE",
"result": "OK",
"bulk": [
{
"firstName": "Monster",
"lastName": "Mash",
"paymentAmount": "125",
"feeAmount": "3.00",
"accountNumber": "123451",
"emailAddress": "test@test.com",
"memo": "Part of bulk transactions",
"cardMonth": "12",
"cardYear": "2025",
"token": "thisIsAToken1234",
"mask": "4000111234",
"cardType": "VISA"
},
{
"firstName": "November",
"lastName": "Rain",
"paymentAmount": "125",
"feeAmount": "3.00",
"accountNumber": "11111",
"emailAddress": "test2@test.com",
"memo": "Part of bulk transactions",
"cardMonth": "4",
"cardYear": "2023",
"token": "thisIsAToken2222",
"mask": "4000112222",
"cardType": "VISA"
}
]
}
Attribute | Description |
---|---|
function
Alpha8
|
The function to be performed by the remote javascript.
Valid value(s):
RESPONSE |
result
Alpha7
|
The result of the tokenization request. PRELOAD will be returned only if an existing token was preloaded and was not overwritten with new data.
Valid value(s):
OK , ERROR , PRELOAD |
bulk
List
|
The list of objects from the bulk upload. See object definition below. |
errorList
ListN/A
|
A list of error objects. See object definition below
|
Bulk Object
Bulk Object
Bank csv
FIRST_NAME *, LAST_NAME *, PAYMENT_AMOUNT *, FEE_AMOUNT *, ACCOUNT_NUMBER *, BANK_ACCOUNT_NUMBER, BANK_ROUTING_NUMBER, BANK_ACCOUNT_TYPE
Crazy, Bob, 125, 3.5, 123444, 123456789, 124000054, CHECKING
Lard, McGoo, 125, 3.5, 123444, 987654321, 124000054, SAVINGS
Card csv
FIRST_NAME *, LAST_NAME *, STREET_ADDRESS_ONE, CITY, STATE, ZIP, COUNTRY, PAYMENT_AMOUNT *, FEE_AMOUNT *, ACCOUNT_NUMBER *, EMAIL_ADDRESS, PHONE_NUMBER, MEMO, CARD_NUMBER *, CARD_MONTH *, CARD_YEAR *, CARD_CODE, POST_AUTHORIZATION
Crazy, Bob, here, there, UT, 84067, US, 125, 3.5, 123444, , , memo, 4000100011112224, 12, 2025, 444, postAuth
{
"firstName": "Monster",
"lastName": "Mash",
"city": "here",
"state": "CA",
"zip": "90210",
"country": "US",
"paymentAmount": "125",
"feeAmount": "3.00",
"accountNumber": "123451",
"emailAddress": "test@test.com",
"memo": "Part of bulk transactions",
"cardMonth": "12",
"cardYear": "2025",
"token": "thisIsAToken1234",
"mask": "4000111234",
"cardType": "VISA",
"errorList": []
}
Attribute | Description |
---|---|
firstName
AlphaNumeric45
Required
|
The first name of the person on the transaction. |
lastName
AlphaNumeric45
Required
|
The last name of the person on the transaction. |
city
AlphaNumeric
|
The city of the person on the transaction. |
state
Alpha2
|
The state of the person on the transaction. |
zip
Numeric5
|
The zip of the person on the transaction. |
country
Alpha2
|
The country of the person on the transaction. |
paymentAmount
NumericDecimal
Required
|
The amount for the transaction payment. |
feeAmount
NumericDecimal
|
The fee amount for the transaction. |
accountNumber
AlphaNumeric
Required
|
The account number for the person making the payment. |
token
AlphaNumeric
|
The token for the card or bank account number. |
mask
Numeric
|
The mask of the card number or bank account number. For a card, this is the first 6 and last 4 of the card number. For a bank account, this is the last 4 of the bank account. |
emailAddress
AlphaNumeric
|
The email address for the person making the payment. |
memo
AlphaNumeric
|
A memo on the payment. |
cardMonth
Numeric
|
The expiration month for the card, if cards. |
cardYear
Numeric
|
The expiration year for the card, if cards. |
cardType
Alphanumeric
|
The cardType for the card.
Valid value(s):
More types may be detected in the future.
VISA , MASTERCARD , AMERICAN_EXPRESS , DISCOVER , UNKNOWN |
bankRoutingNumber
Numeric
|
The routing number for the bank account. |
bankAccountType
Alpha
|
The type of bank account.
Valid value(s):
SAVINGS , CHECKING0 |
errorList
ListN/A
|
A list of error objects. See object definition below
|
Response Error
Response Error Object
{
"code": "10003",
"description": "Field invalid",
"fieldName": "ccExpYear"
}
Attribute | Description |
---|---|
code
Numeric5
|
A code to define the error.
Valid value(s):
Definitions:10001 , 10002 , 10003 , 10004 , 10005 10001 - Generic error. An unexpected error occurred.10002 - Invalid security credentials. Either the companyId or apiKey was not present in the request, or the apiKey was invalid.10003 - Field invalid. The value in the field was invalid. The fieldName parameter will have the name of the field.10004 - Missing required field. - A required field is empty. The fieldName parameter will have the name of the field.10005 - Duplicate field mismatch. - The value in the second SecureOverlay field does not match the first field. The fieldName parameter will be secondName . |
description
Alphanumeric48
|
The user-friendly description of the error. |
fieldName
Alpha48
|
The name of the field which had the error. This will only be present if there was an error on a specific field; for example, a validation error.
Other than secureData , which represents the card/bank account number field, these field names will match the values required in
the processData object. The secondName fieldName is returned if that name is not found in the dom or if
the value in the second field does not match the value in the first field.
Valid value(s):
secureData , apiKey , companyId , dataType ,
ccExpMonth , ccExpYear , routingNumber , bankAccountType ,
authorizedForFutureUse , secondName . |
Example Workflow
Here is an example workflow for how your integration may happen.
- Add an
<iframe>
element in the<body>
of your HTML, with the SecureOverlay as thesrc
, that will contain the secure input field. - Add a listener to listen for messages posted from the iframe, and the function to call when these messages are received. These posts will be from the domain
https://wsdemo.pdc4u.com
(testing) or fromhttps://ws.pdc4u.com
(live). - Add a function to post the required data to the iframe.
- Add a
MessageChannel
object to use for communication. - Listen for the
PRELOAD
functionpostMessage
from SecureOverlay - Initialize the port connection using the established
MessageChannel
ports - Listen for the
NOTIFY
event that specifies the port connection is established (code 008) - Submit the data to tokenize and receive the response
When a user loads the page that has the iframe, the secure entry field will be loaded in the iframe. Once the field has completed loading, your webpage will receive an HTML POSTMessage with an object. Thefunction
parameter in that object will have a value ofPRELOAD
.
Once your webpage has received this message, the SecureOverlay page has completed loading and is ready to accept instruction from your page. At this point, your webpage needs to establish the port connection with the SecureOverlay field. The SecureOverlay field will continue to post the PRELOAD message every half second for 5 seconds, or until this init message is received by SecureOverlay. Once the port connection is established all further communication will be through this port. To establish the port connection, send apostMessage
'init' request to the SecureOverlay Iframe with the channel port. Once SecureOverlay receives this 'init' message, the port connection will be established. SecureOverlay will send aNOTIFY
message through that port connection, withcode 008
to confirm that the port was established successfully. Once your webpage receives theNOTIFY
message, your webpage may automatically create an object with thefunction
set toPRELOAD
in order to designate some initial parameters. These parameters may include styling the input field as you desire or setting an initialdataType
, among others. View the Preload object for functionality.
It is recommended that the integration code handles the rare chance that a second PRELOAD message is received while the response to the first PRELOAD is already executing.
If theshouldNotify
field in thePRELOAD
object is set totrue
, as the user types in the secure field, SecureOverlay will post events to your webpage pertaining to the data in the field. This could include the cardType or early validation of the data. These notifications are defined in the Notification object definition
If the user chooses to pay by check instead of card, or vice-versa, your webpage can send anotherPreload Data
object at any time to define the newdataType
or define new styling.
Once the user has clicked theSubmit
button on your webpage, your webpage will send an object to SecureOverlay withfunction
typePROCESS
(View definition). SecureOverlay will then validate and tokenize the data that was entered in the secure field.
Once encryption of the data is complete, SecureOverlay willPOST
a Response back to your webpage, containing the token, which can then be used to process the transaction or store the data according to your business needs.
Sample Code
Sample Card tokenization
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<title>Payment</title>
<meta charset="utf-8" />
</head>
<body>
<div class="container">
<div class="ccPayment">
<iframe id="iframeId" src="https://wsdemo.pdc4u.com/SecureOverlay/v2_0"></iframe><br />
<input type="tel" id="expMonth" placeholder="Expiration Month" /><br />
<input type="tel" id="expYear" placeholder="Expiration Year" /><br />
<p>Authorized for Future Use:</p>
<div>
<label for="authYes">Yes</label>
<input type="radio" id="authYes" name="authorizedForFutureUse" value="Yes" checked>
</div>
<div>
<label for="authNo">No</label>
<input type="radio" id="authNo" name="authorizedForFutureUse" value="No">
</div>
<br/>
<button id="nextButton" onclick="tokenizeData()">Tokenize</button>
</div>
</div>
<script type="text/javascript">
window.addEventListener('message', receiveMessage, false);
const remoteDomain = 'https://wsdemo.pdc4u.com';
let preType = 'CCN';
//These are used to set up and communicate through the dedicated channel
const channel1 = new MessageChannel();
let port1 = channel1.port1;
//We will use this to prevent submitting a PRELOAD request a second time in the case that a second PRELOAD message is received from SecureOverlay
let alreadyPreloading = false;
/*
* This function will be used once, to handle the PRELOAD function
* On the PRELOAD function, we will set up a dedicated MessageChannel to converse between iFrame and parent page
*/
function receiveMessage(event) {
if(event.origin !== remoteDomain) {
console.log('remote origin: ' + event.origin);
return;
}
switch(event.data.function) {
case 'PRELOAD':
if (alreadyPreloading) {
return;
}
alreadyPreloading = true;
//First we set up the dedicated channel
initiatePort();
break;
}
}
function initiatePort() {
//receivedMessage function will be called when a postMessage from the iframe through this port comes through
port1.onmessage = receivedMessage;
//Each MessageChannel has 2 ports. One is used on the parent side (channel1.port1) and one is passed to the iframe to establish the connection (channel1.port2)
document.getElementById("iframeId").contentWindow.postMessage('init', '*', [channel1.port2]);
}
function receivedMessage(e) {
//Notice there is no needs to validate the event.origin when receiving a message as this is a dedicated channel directly from the parent page to the iframe
console.log(e.data);
//It is recommended here to listen for the NOTIFY 008 message, which signifies the port connection is established. Then we can remove our generic message listener and also send our PRELOAD data through the port
if (e.data.function === 'NOTIFY' && e.data.code === '008') {
window.removeEventListener('message', receiveMessage);
const preloadData = {};
preloadData.function = 'PRELOAD';
// styleOptions.token = 'thisIsAToken1234';
preloadData.focus = false;
preloadData.clearFieldOnClick = false;
preloadData.backgroundColor = "RED";
preloadData.shouldNotify = true;
preloadData.dataType = preType;
sendMessage(preloadData);
}
else {
//handle other communication here (notifications/tokenization response, etc.)
}
}
function sendMessage(data) {
//All that is required to do to send a message is use the port1.postMessage();
port1.postMessage(data);
}
function tokenizeData() {
const data = {};
data.dataType = 'CCN';
data.ccExpMonth = document.getElementById('expMonth').value;
data.ccExpYear = document.getElementById('expYear').value;
data.apiKey = 'replaceWithRealApiKeyForTest';
data.companyId = 'replaceWithRealCompanyId';
data.function = 'PROCESS';
let radio = document.getElementsByName('authorizedForFutureUse');
for(let i = 0; i < radio.length; i++) {
if(radio[i].checked) {
data.authorizedForFutureUse = radio[i].value === 'Yes';
}
}
sendMessage(data);
}
</script>
</body>
</html>
Here is a sample HTML page that has all the code required to interact with the Secure Overlay API. Here a credit card number will be tokenized. It contains the complete Javascript code as well as a test form that includes the Secure Overlay field and additional field required for tokenizing a card.
Sample Bank Account Tokenization
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<title>Payment</title>
<meta charset="utf-8" />
</head>
<body>
<div class="container">
<div class="achPayment">
<iframe id="iframeId" src="https://wsdemo.pdc4u.com/SecureOverlay/v2_0"></iframe>
<br/>
<input type="tel" id="routingNumber" placeholder="Routing Number" />
<br/>
<label for="bankAccountType">Bank account type</label>
<select name="bankAccountType" id="bankAccountType" >
<option value="CHECKING" selected="selected">Checking</option>
<option value="SAVINGS">Savings</option>
</select>
<br/>
<p>Authorized for Future Use:</p>
<div>
<label for="authYes">Yes</label>
<input type="radio" id="authYes" name="authorizedForFutureUse" value="Yes" checked>
</div>
<div>
<label for="authNo">No</label>
<input type="radio" id="authNo" name="authorizedForFutureUse" value="No">
</div>
<br/>
<button id="nextButton" onclick="tokenizeData()">Tokenize</button>
</div>
</div>
<script type="text/javascript">
window.addEventListener('message', receiveMessage, false);
const remoteDomain = 'https://wsdemo.pdc4u.com';
let preType = 'BAN';
//These are used to set up and communicate through the dedicated channel
const channel1 = new MessageChannel();
let port1 = channel1.port1;
//We will use this to prevent submitting a PRELOAD request a second time in the case that a second PRELOAD message is received from SecureOverlay
let alreadyPreloading = false;
/*
* This function will be used once, to handle the PRELOAD function
* On the PRELOAD function, we will set up a dedicated MessageChannel to converse between iFrame and parent page
*/
function receiveMessage(event) {
if(event.origin !== remoteDomain) {
console.log('remote origin: ' + event.origin);
return;
}
switch(event.data.function) {
case 'PRELOAD':
if (alreadyPreloading) {
return;
}
alreadyPreloading = true;
//First we set up the dedicated channel
initiatePort();
break;
}
}
function initiatePort() {
//receivedMessage function will be called when a postMessage from the iframe through this port comes through
port1.onmessage = receivedMessage;
//Each MessageChannel has 2 ports. One is used on the parent side (channel1.port1) and one is passed to the iframe to establish the connection (channel1.port2)
document.getElementById("iframeId").contentWindow.postMessage('init', '*', [channel1.port2]);
}
function receivedMessage(e) {
//Notice there is no needs to validate the event.origin when receiving a message as this is a dedicated channel directly from the parent page to the iframe
console.log(e.data);
//It is recommended here to listen for the NOTIFY 008 message, which signifies the port connection is established. Then we can remove our generic message listener and also send our PRELOAD data through the port
if (e.data.function === 'NOTIFY' && e.data.code === '008') {
window.removeEventListener('message', receiveMessage);
const preloadData = {};
preloadData.function = 'PRELOAD';
// styleOptions.token = 'thisIsAToken1234';
preloadData.focus = false;
preloadData.clearFieldOnClick = false;
preloadData.backgroundColor = "RED";
preloadData.shouldNotify = true;
preloadData.dataType = preType;
sendMessage(preloadData);
}
else {
//handle other communication here (notifications/tokenization response, etc.)
}
}
function sendMessage(data) {
//All that is required to do to send a message is use the port1.postMessage();
port1.postMessage(data);
}
function tokenizeData() {
console.log("tokenizing");
const data = {};
data.dataType = 'BAN';
data.routingNumber = document.getElementById('routingNumber').value;
data.bankAccountType = document.getElementById('bankAccountType').value;
let radio = document.getElementsByName('authorizedForFutureUse');
for(let i = 0; i < radio.length; i++) {
if(radio[i].checked) {
data.authorizedForFutureUse = radio[i].value === 'Yes';
}
}
data.apiKey = 'replaceWithRealApiKeyForTest';
data.companyId = 'replaceWithRealCompanyId';
data.function = 'PROCESS';
sendMessage(data);
}
</script>
</body>
</html>
Here is a sample HTML page that has all the code required to interact with the Secure Overlay API. Here a bank account number will be tokenized. It contains the complete Javascript code as well as a test form that includes the Secure Overlay field and additional field required for tokenizing a bank account number.
Sample Multiple Fields Bank Account Tokenization
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<title>Payment</title>
<meta charset="utf-8" />
</head>
<body>
<div class="container">
<div class="achPayment">
<iframe id="myIframeId" src="https://wsdemo.pdc4u.com/SecureOverlay/v2_0?iframeId=myIframeId"></iframe>
<iframe id="iframe2Id" name="iframe2Id" src="https://wsdemo.pdc4u.com/SecureOverlay/v2_0?iframeId=iframe2Id"></iframe>
<br/>
<input type="tel" id="routingNumber" placeholder="Routing Number" />
<br/>
<label for="bankAccountType">Bank account type</label>
<select name="bankAccountType" id="bankAccountType" >
<option value="CHECKING" selected="selected">Checking</option>
<option value="SAVINGS">Savings</option>
</select>
<br/>
<p>Authorized for Future Use:</p>
<div>
<label for="authYes">Yes</label>
<input type="radio" id="authYes" name="authorizedForFutureUse" value="Yes" checked>
</div>
<div>
<label for="authNo">No</label>
<input type="radio" id="authNo" name="authorizedForFutureUse" value="No">
</div>
<br/>
<button id="nextButton" onclick="tokenizeData()">Tokenize</button>
</div>
</div>
<script type="text/javascript">
window.addEventListener('message', receiveMessage, false);
//mark that we have set a listener
let listenerExists = true;
const remoteDomain = 'https://wsdemo.pdc4u.com';
let preType = 'BAN';
//These are used to set up and communicate through the dedicated channel
const channel1 = new MessageChannel();
const channel2 = new MessageChannel();
let port1 = channel1.port1;
let port2 = channel2.port1;
//We will use this to prevent submitting a PRELOAD request a second time in the case that a second PRELOAD message is received from SecureOverlay
let alreadyPreloading = false;
/*
* This function will be used once, to handle the PRELOAD function
* On the PRELOAD function, we will set up a dedicated MessageChannel to converse between iFrame and parent page
* Because 2 Secure Overlay fields have been loaded, you will receive messages from each field, thus getting multiple PRELOAD messages.
* In order to distinguish which iframe is sending the message, the PRELOAD message will include the id of the iframe if it is provided in the src URL,
* in this case "myIframeId" or "iframe2Id"
* In most workflows, you will only need to tokenize one field. The second field would be used to validate that the user entered their information correctly
* by having them re-enter it in the second field.
* If the parent page has need to communicate with both SecureOverlay fields (for styling, for example), a second MessageChannel can be established, same
* as the first is.
*/
function receiveMessage(event) {
if(event.origin !== remoteDomain) {
console.log('remote origin: ' + event.origin);
return;
}
switch(event.data.function) {
case 'PRELOAD':
initiatePort(event.data.id);
break;
case 'RESPONSE':
if(event.data.errorMsg) {
console.log('error: ' + event.data.errorMsg);
}
console.log('data:');
console.log(event.data);
break;
}
switch(event.data.function) {
case 'PRELOAD':
if (alreadyPreloading) {
return;
}
//First we set up the dedicated channel for both iframe fields. This will allow us to style them both. We will only tokenize the first field, however.
//This id is only returned if it is provided in the iframe src URL (?iframeId=myIframeId)
alreadyPreloading = true;
initiatePort(event.data.id);
if (event.data.id === 'myIframeId') {
const styleOptions = {};
styleOptions.backgroundColor = '#ccc';
styleOptions.fontSize = '14px';
styleOptions.function = 'PRELOAD';
styleOptions.dataType = preType;
sendMessage(styleOptions);
}
break;
}
}
function initiatePort(id) {
//receivedMessage function will be called when a postMessage from the iframe through this port comes through
//Each MessageChannel has 2 ports. One is used on the parent side (channel1.port1) and one is passed to the iframe to establish the connection (channel1.port2)
if(id === 'firstIframe') {
port11.onmessage = channel1Message;
document.getElementById(id).contentWindow.postMessage('init', '*', [channel1.port2]);
}
else if(id === 'secondIframe') {
port12.onmessage = channel2Message;
document.getElementById('secondIframe').contentWindow.postMessage('init', '*', [channel2.port2]);
}
}
function channel1Message(e) {
console.log(e.data);
if (listenerExists) {
listenerExists = false;
window.removeEventListener('message', receiveMessage);
}
//We get a notification that the port is established so we can send the PRELOAD
if (e.data.function === 'NOTIFY' && e.data.code === '008') {
const preloadData = {};
preloadData.function = 'PRELOAD';
preloadData.focus = false;
preloadData.clearFieldOnClick = false;
preloadData.backgroundColor = "RED";
preloadData.shouldNotify = true;
preloadData.dataType = preType;
sendMessage(preloadData, '1');
}
}
function channel2Message(e) {
console.log(e.data);
if (listenerExists) {
listenerExists = false;
window.removeEventListener('message', receiveMessage);
}
//We get a notification that the port is established so we can send the PRELOAD
if (e.data.function === 'NOTIFY' && e.data.code === '008') {
const preloadData = {};
preloadData.function = 'PRELOAD';
preloadData.focus = false;
preloadData.clearFieldOnClick = false;
preloadData.backgroundColor = "BLUE";
preloadData.shouldNotify = false; //On the second field, we probably don't need NOTIFY events
preloadData.dataType = preType;
sendMessage(preloadData, '2');
}
}
function sendMessage(data, channel) {
//All that is required to do to send a message is using the correct port;
if (channel === '1') {
port1.postMessage(data);
}
else if (channel === '2') {
port2.postMessage(data);
}
}
function tokenizeData() {
console.log("tokenizing");
const data = {};
data.dataType = 'BAN';
data.routingNumber = document.getElementById('routingNumber').value;
data.bankAccountType = document.getElementById('bankAccountType').value;
let radio = document.getElementsByName('authorizedForFutureUse');
for(let i = 0; i < radio.length; i++) {
if(radio[i].checked) {
data.authorizedForFutureUse = radio[i].value === 'Yes';
}
}
data.apiKey = 'replaceWithRealApiKeyForTest';
data.companyId = 'replaceWithRealCompanyId';
data.function = 'PROCESS';
//We want SecureOverlay to validate that the data in each field is the same, thus send the id of the second iframe
data.secondName = 'iframe2Id';
//We only need to tokenize field 1; we will get the token back for it and use that token for processing
sendMessage(data, '1');
}
</script>
</body>
</html>
Here is a sample HTML page that has all the code required to interact with the Secure Overlay API.
Here a bank account number will be tokenized. It contains the complete Javascript code as well as a test form that includes the Secure Overlay field and
additional field required for tokenizing a bank account number.
Notice the iframeId
value in the URL. Providing this value allows SecureOverlay to identify in the PreloadData
which iframe is loaded.
The second Secure Overlay field also expects input, and the data.secondName
in the tokenizeData()
method will force SecureOverlay to validate that the values in the two Secure Overlay fields are identical.
Sample Bulk Card Tokenization
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<title>Payment</title>
<meta charset="utf-8" />
</head>
<body>
<div class="container">
<div class="bulkPayments">
<iframe id="iframeId" src="https://wsdemo.pdc4u.com/SecureOverlay/v2_0/bulk"></iframe>
<button id="nextButton" onclick="uploadBulk()">Upload</button>
</div>
</div>
<script type="text/javascript">
window.addEventListener('message', receiveMessage, false);
const remoteDomain = 'https://wsdemo.pdc4u.com';
//These are used to set up and communicate through the dedicated channel
const channel1 = new MessageChannel();
let port1 = channel1.port1;
//We will use this to prevent submitting a PRELOAD request a second time in the case that a second PRELOAD message is received from SecureOverlay
let alreadyPreloading = false;
/*
* This function will be used once, to handle the PRELOAD function
* On the PRELOAD function, we will set up a dedicated MessageChannel to converse between iFrame and parent page
*/
function receiveMessage(event) {
if(event.origin !== remoteDomain) {
console.log('remote origin: ' + event.origin);
return;
}
switch(event.data.function) {
case 'PRELOAD':
if (alreadyPreloading) {
return;
}
alreadyPreloading = true;
//First we set up the dedicated channel
initiatePort();
break;
}
}
function initiatePort() {
//receivedMessage function will be called when a postMessage from the iframe through this port comes through
port1.onmessage = receivedMessage;
//Each MessageChannel has 2 ports. One is used on the parent side (channel1.port1) and one is passed to the iframe to establish the connection (channel1.port2)
document.getElementById("iframeId").contentWindow.postMessage('init', '*', [channel1.port2]);
}
function receivedMessage(e) {
//Notice there is no needs to validate the event.origin when receiving a message as this is a dedicated channel directly from the parent page to the iframe
console.log(e.data);
//It is recommended here to listen for the NOTIFY 008 message, which signifies the port connection is established. Then we can remove our generic message listener and also send our PRELOAD data through the port
if (e.data.function === 'NOTIFY' && e.data.code === '008') {
window.removeEventListener('message', receiveMessage);
const preloadData = {};
preloadData.function = 'PRELOAD';
preloadData.backgroundColor = "RED";
preloadData.shouldNotify = true;
sendMessage(preloadData);
}
else {
//handle other communication here (notifications/tokenization response, etc.)
}
}
function sendMessage(data) {
//All that is required to do to send a message is use the port1.postMessage();
port1.postMessage(data);
}
function uploadBulk() {
console.log("Uploading");
const data = {};
data.dataType = 'CCN';
data.apiKey = 'replaceWithRealApiKeyForTest';
data.companyId = 'replaceWithRealCompanyId';
data.function = 'BULK_UPLOAD';
data.bulkType = 'TRANSACTION';
sendMessage(data);
}
</script>
</body>
</html>
Here is a sample HTML page that has all the code required to interact with the Secure Overlay API. Here a bulk file will be uploaded. We specify the dataType as CCN, and as such, the file must contain credit card numbers. Also, specifying the bulkType as TRANSACTION, the service will validate all required fields for transactions. This will NOT process said transactions, only tokenize the card numbers. It contains the complete Javascript code as well as a test form that includes the Secure Overlay field and additional field required for tokenizing a bank account number.