Spreedly iFrame Payment Form

There are a variety of ways to send payment data to Spreedly. If you wish to implement a custom checkout experience while still limiting your PCI compliance, the recommended approach is to use the iFrame payment form. Although it is a lower level library than Express, it allows almost unlimited UX customization and behavior while still storing card data in your Spreedly vault without it ever touching your server environment.

If you are looking for specific commands or options, please see the iFrame Javascript API reference

For customers who are not using iframe-v1, or iframe-stable, Spreedly is implementing a deprecation plan for iFrame where all versions that are more than 3 months out of date will be deprecated and removed from service. This ensures that all customers are on recent versions with the latest security updates. We strongly recommended implementing one of our regularly updated release channels as they will always be up to date.

iFrame overview

Spreedly’s iFrame payment form is a pure, JavaScript library that provides two Spreedly-managed, fields for collecting the credit card number and CVV (the two PCI-sensitive fields of a payment method). No cookies are used to provide this functionality. Your host page places and styles these two fields within the checkout form, and the iFrame returns a tokenized payment method to the host page when the payment method has been successfully submitted. While an invalid PAN will prevent the iFrame from returning a payment method token, an invalid CVV will not. The CVV field may be hidden if you do not require the CVV to process payments through your gateway.

The credit card auto-complete attributes are enabled by default on the fields which will allow for browsers and password managers to more easily auto-fill the fields. The customer can make autocomplete more functional by adding the autocomplete attributes to the customer controlled fields for name (“cc-name”), expiration month (“cc-exp-month”), and expiration year (“cc-exp-year”).

By default the number input form has a maxlength of 19 and the CVV input form has a maxlength of 4. As the PAN is entered into the number input form, the maxlength of both the number form and CVV will update depending on the card type. Note: if the user highlights and replaces the entered PAN without deleting the initial value, the initial maxlength will remain in place. To ensure the cardholder can enter all digits according to their card type, they must delete the input values before reentering with another card number.

The following shows a rendered checkout page using the Spreedly iFrame to serve the number and CVV fields. The only parts contained within Spreedly-served iFrames are the individual number and CVV input fields. All the labels and other fields are part of the host checkout page.

Before You Begin

You will need your environment key and access secret from id.spreedly.com, as well as your gateway token. Since invalid card numbers will fail silently until error handling is implemented, you may also find it helpful to have valid test card numbers at hand for easy reference. A more complete example of a payment page that uses iFrame can be found in the Sample Payment Frame.

Adding iFrame to your checkout page

To add iFrame to your checkout page, include the Javascript library in your host page:

<head>
  <script src="https://core.spreedly.com/iframe/iframe-v1.min.js"></script>
</head>

Then copy the following checkout form into the checkout page:

<form id="payment-form"
  action="https://yoursite.com/checkout"
  onsubmit='submitPaymentForm(); return false;'>

  <input type="hidden"  name="payment_method_token" id="payment_method_token">

  <label for="full_name">Name</label>
  <input type="text" id="full_name" name="full_name"><br/>

  <label>Credit Card Number</label>
  <div id="spreedly-number" style="width:225px; height:35px; border: 2px solid"></div><br/>

  <label for="month">Expiration Date</label>
  <input type="text" id="month" name="month" maxlength="2">
  <input type="text" id="year" name="year" maxlength="4"><br/>

  <label>CVV</label>
  <div id="spreedly-cvv" style="width:60px; height:35px; border: 2px solid "></div><br/>

  <input id="submit-button" type="submit" value="Pay Now" disabled>

</form>

This will create a very simple (and unstyled) payment form. However, the payment form will not yet contain the number or CVV fields nor will it be functional. It must first be configured before it can successfully tokenize your customers’ payment methods.

Configuration

Once the host form is on the page, the iFrame is initialized with the Spreedly Javascript module. Pass in the Spreedly environment key where your customers’ payment methods should be stored along with the id of the form HTML elements where the two card fields are to be placed.

In this example, payment methods will be tokenized in the C7cRfNJGODKh4Iu5Ox3PToKjniY Spreedly environment and the number and CVV form fields will render within the spreedly-number and spreedly-cvv elements, respectively. Here, spreedly-number and spreedly-cvv are the CSS ID selectors of the two divs from the above form.

Place the below snippet in a new script tag on the bottom of the checkout page, swapping out the example environment key with your own:

Spreedly.init("C7cRfNJGODKh4Iu5Ox3PToKjniY", {
  "numberEl": "spreedly-number",
  "cvvEl": "spreedly-cvv"
});

Ready

The ‘Pay Now’ button is initially disabled to prevent submission of the form before the iFrames have finished loading. A 'ready’ event is triggered when the iFrames have been successfully initialized. Create a listener for this event to toggle the 'Pay Now’ button to an enabled state.

Spreedly.on("ready", function () {
  var submitButton = document.getElementById('submit-button');
  submitButton.disabled = false;
});

Reload your checkout page to see the number and CVV fields rendered in your form. Once the fields are rendered, you need to tell iFrame when to tokenize a customer’s card data.

Tokenize payment method

iFrame doesn’t automatically hook into any form events. Instead, you must explicitly tell it when you want to send the collected card data to Spreedly for tokenization.

The most straight-forward approach is to create a form onSubmit handler that sets the required fields for a payment method (name and expiration date, in addition to the number and CVV fields which are handled for you) and delegates to Spreedly.tokenizeCreditCard.

Implement a top-level function submitPaymentForm that gets the values from the name and expiration date fields, passes them to the iFrame, and requests tokenization. Note that this function and all other JavaScript functions should be placed in a script tag on the checkout page.

Place the below snippet in the previously created script tag, below the call to Spreedly.init:

function submitPaymentForm() {

  var requiredFields = {};

  // Get required, non-sensitive, values from host page
  requiredFields["full_name"] = document.getElementById("full_name").value;
  requiredFields["month"] = document.getElementById("month").value;
  requiredFields["year"] = document.getElementById("year").value;

  Spreedly.tokenizeCreditCard(requiredFields);
}

When the form’s submit button is clicked, the required values from the host page will be sent to the iFrame and subsequently submitted to Spreedly for tokenization in your Spreedly environment. If the card is successfully tokenized, the token will be sent back to the host page via an event, which you must send back to your backend environment for processsing. Please note, successful tokenization does not execute a transaction or validation. In order to verify the payment method, you will need to invoke a purchase or authorization from your secure, server-side environment.

Error handling

If a card is not successfully tokenized, an error event is generated. This sample will log errors to your browser’s Javascript console; you may wish to selectively surface some errors to the user.

Spreedly.on('errors', function(errors) {
  for (var i=0; i < errors.length; i++) {
    var error = errors[i];
    console.log(error);
  };
});

See Spreedly’s response codes documentation for more information. In particular, note that the 422 error code is returned both for requests with inadequate data (such as a missing name or CVV) and for declined cards.

Receiving the tokenized payment method

When a card has been tokenized by Spreedly, an event is fired that includes the generated payment method token as well as the details of the payment method record. It is up to you to receive the token and send it to your backend environment.

This example shows how to register for the onPaymentMethod event, and add the payment method token to the host form which is then submitted to your backend:

Spreedly.on('paymentMethod', function(token, pmData) {

  // Set the token in the hidden form field
  var tokenField = document.getElementById("payment_method_token");
  tokenField.setAttribute("value", token);

  // Submit the form
  var masterForm = document.getElementById('payment-form');
  masterForm.submit();
});

While this exmple shows how to submit the payment method token via a form submission, you could just as easily send the token back via AJAX.

At this point you should have a working payment form that tokenizes the payment method at Spreedly and sends the token to your backend environment. Spreedly has tokenized the payment method, but has not processed a transaction.

Executing the transaction

After the iFrame tokenizes your customer’s payment method and submits the checkout form, it is up to you to execute the actual transaction from your backend server environment. This is necessary because the browser is not a secure environment and should never contain your Spreedly access secret (which is required to invoke the transactional portion of the Spreedly API).

When the checkout form is submitted, extract the payment_method_token parameter and use it to execute a purchase (or auth) against the appropriate gateway using the direct API:

$ curl https://core.spreedly.com/v1/gateways/LlkjmEk0xNkcWrNixXa1fvNoTP4/purchase.json \
  -u 'C7cRfNJGODKh4Iu5Ox3PToKjniY:4UIuWybmdythfNGPqAqyQnYha6s451ri0fYAo4p3drZUi7q2Jf4b7HKg8etDtoKJ' \
  -H 'Content-Type: application/json' \
  -d '{
        "transaction": {
          "payment_method_token": "56wyNnSmuA6CWYP7w0MiYCVIbW6",
          "amount": 100,
          "currency_code": "USD",
          "retain_on_success": true
        }
      }'

$ curl https://core.spreedly.com/v1/gateways/LlkjmEk0xNkcWrNixXa1fvNoTP4/purchase.xml \
  -u 'C7cRfNJGODKh4Iu5Ox3PToKjniY:4UIuWybmdythfNGPqAqyQnYha6s451ri0fYAo4p3drZUi7q2Jf4b7HKg8etDtoKJ' \
  -H 'Content-Type: application/xml' \
  -d '<transaction>
        <payment_method_token>56wyNnSmuA6CWYP7w0MiYCVIbW6</payment_method_token>
        <amount>100</amount>
        <currency_code>USD</currency_code>
        <retain_on_success>true</retain_on_success>
      </transaction>'

You can review the Spreedly API reference docs for details of the direct API, including the authentication, purchase and authorize calls.

Securing iFrame

In order to achieve the highest levels of PCI-DSS v3 compliance with the iFrame, you need to disable the creation of payment methods via the direct API. After confirming you are not using the XML, JSON, JSONP, CORS or transparent direct methods of adding a payment method, enable the “Spreedly iFrame or Express Only option in the Environment Settings page of your environment.

This prevents direct API submission of payment methods which is required to detect malicious attacks and, in general, enforce adherence to the PCI standard. The only way payment methods can be added to this Spreedly environment will be through the iFrame (or Express) payment forms.

Customizing the iFrame

The form and flow you have in place now should be functional, but is rudimentary and unstyled. Next, learn how to customize the iFrame using the iFrame Javascript API reference, which includes the following topics:

Recache existing payment method

Due to PCI compliance requirements, Spreedly is unable to store a card’s CVV past the original transaction. If you have an existing payment method already tokenized in your Spreedly environment, you can have the customer update the CVV for a new transaction without having to re-enter the rest of their card details.

Simply set iFrame to operate in recache mode and handle the recache event:

Spreedly.on('ready', function(){
 Spreedly.setRecache("56wyNnSmuA6CWYP7w0MiYCVIbW6" , {
   'card_type': 'visa',
   'last_four_digits': '1234'
 });
});

// Invoke Spreedly.recache() to recache CVV. On success,
// the "recache" event will be triggered.
Spreedly.on("recache", function(token, paymentMethod) {

  // Send ping back to server for post-recache transaction processing
  var masterForm = document.getElementById('payment-form');
  masterForm.submit();
});

Find more information about recache in the iFrame reference docs.

Skipping name and expiration date validation

By default Spreedly validates the presence of a name and expiration date associated with a credit card. However, in some cases you may want to skip this validation if this is not metadata you are interested in collecting. If you’d like to skip either or both of these validations you can set the following parameters to true.

Spreedly.on('ready', function(){
  Spreedly.setParam('allow_blank_name', true
  Spreedly.setParam('allow_expired_date', true)
});

Examples

A more complete example of a payment page that uses iFrame can be found in the Sample Payment Frame.

Browser compatibility

In general, Spreedly supports browser versions that are actively maintained and have up-to-date security profiles. At the time of this writing, that list includes:

We additionally require that all browsers support TLS 1.2 or higher.

Versioning

Spreedly iFrame is versioned by major numerical, e.g., v1. Backwards-incompatible features will cause the major version number to increment and will only be deployed if you update the script reference on your checkout page (meaning you choose when to accept major upgrades).

Any critical bug fixes or security updates will be automatically deployed as the current version number, thus automatically allowing you to run a secure, stable version.

Do not store a copy of the JavaScript library on your servers, always reference the version hosted by Spreedly. Any self-hosted versions of Spreedly’s code will be considered unsupported.

An iFrame specific Changelog RSS feed can be subscribed to at https://core.spreedly.com/iframe/feed.xml.

Deprecation

For customers who are not using iframe-v1, or iframe-stable, Spreedly is implementing a deprecation plan for iFrame where all versions that are more than 3 months out of date will be deprecated and removed from service. This ensures that all customers are on recent versions with the latest security updates. We strongly recommended implementing one of our regularly updated release channels as they will always be up to date. The only exception to this policy is iframe-1.93 as it is the last version supporting Internet Explorer.

Scheduled Releases

Spreedly offers three regularly updated channels for iFrame.

v1: This is the most commonly used iFrame asset (iframe-v1.min.js) that receives updates as soon as we release them. Updates do not come on any set schedule. iframe-v1 is recommended for end users who want the latest security updates and features as soon as they are available.

Candidate: Available by using iframe-candidate.min.js, candidate is updated on the 1st Tuesday of each month. It contains all updates that have been made to iframe-v1 from the prior month. This is recommended for users who wish to test upcoming updates to iframe-stable before they reach customers. This is not intended for production use.

If you encounter issues while using iframe-candidate.min.js, please contact support for assistance.

Stable: Available by using iframe-stable.min.js, stable is the sibling of candidate. It is updated on the 3rd Tuesday of the month to match the latest version of iframe-candidate. This is recommended for production use by customers performing testing on candidate

You can change which channel you are using by changing the asset in your script tag as shown below.

<head>
  <script> src="https://core.spreedly.com/iframe/iframe-[desired version].min.js"</script>
</head>

Legacy Browser Support

iFrame dropped support for Internet Explorer in June 15, 2022, the same time as Microsoft dropped support for IE. As Internet Explorer was the last browser to not support the current recommended version of JavaScript (ES6/JavaScript 2016). Starting December 2022, iFrame will no longer work on browsers that do not support ES6.

If you still want to support legacy browsers, you will need to lock to iFrame version 1.93 instead of the rolling iframe-v1 version. The 1.93 version will not receive any new feature updates.

<head>
  <script src="https://core.spreedly.com/iframe/iframe-1.93.min.js"></script>
</head>