Hosted Fields

Hosted Fields is a feature that allows you to outsource the handling of payment card data—possibly making it easier for you to maintain PCI-DSS compliance—while integrating seamlessly with your existing web pages and styles.

Hosted Fields uses JavaScript and iframes to ensure that payment card data is securely handled by Pin Payments’ servers rather than your own servers. This makes payment processing easier to implement and relieves your servers of having to handle your customers’ payment card information.

Example

This example shows how to include the script in your page, configure it with your publishable API key, and then capture the form submission event to convert the payment card details into a Pin Payments card token. It then submits the original form, along with the token, to your server.

This example uses jQuery, but you don’t have to—Hosted Fields does not depend on any front-end library.

  1. Include Hosted Fields

    Paste the following code in the head section of your web page:

    <script src='https://cdn.pinpayments.com/pin.hosted_fields.v1.js'></script>
    
  2. Create a payment form

    Hosted fields requires you to supply empty containers for each of the required form fields.

    <form id="payment_form" action="/url_to_your_server_to_create_charge" method="post">
      <label for="name">Full name</label><br/>
      <div id="name">
        <!-- Hosted Fields will populate this with the 'name' field -->
      </div>
      <div id="errors_for_name" class="error_message"></div>
    
      <label for="number">Card number</label><br/>
      <div id="number">
        <!-- Hosted Fields will populate this with the 'number' field -->
      </div>
      <div id="errors_for_number" class="error_message"></div>
    
      <label for="cvc">CVC</label><br/>
      <div id="cvc">
        <!-- Hosted Fields will populate this with the 'cvc' field -->
      </div>
      <div id="errors_for_cvc" class="error_message"></div>
    
      <label for="expiry">Expiry</label><br/>
      <div id="expiry">
        <!-- Hosted Fields will populate this with the 'expiry' field -->
      </div>
      <div id="errors_for_expiry" class="error_message"></div>
    
      <input type="submit" />
    </form>
    
  3. Add a default style for your containers

    Each of the hosted fields will completely fill its container, so style definitions are required to set the width and height. The Hosted Fields library adds the pin-form-field class to each container automatically.

    <style type="text/css" media="all">
      .pin-form-field {
        height: 2em;
        width: 50%;
        border: 1px solid black;
        padding: 0 0.5em;
      }
    </style>
    
  4. Create a Hosted Fields object

    Create a Hosted Fields object, which will initialise each of your hosted fields to be ready for the customer to enter their card details. Custom styles and placeholders can be provided to ensure the styling of each element matches your existing website.

    <script type="text/javascript">
      $(function() {
        fields = HostedFields.create({
          /* Set this to true when testing. Set it to false in production. */
          sandbox: true,
          /* Optional: set autocomplete to true to allow web browsers to suggest saved credit cards. */
          autocomplete: true,
    
          /*
            These are the CSS styles for the input elements inside the iframes. Inside each iframe
            is a single input with its id set to name, number, cvc or expiry.
    
            When the input has a valid value, it will have the 'hosted-fields-valid' class. When
            the input has an invalid value, it will have the 'hosted-fields-invalid' class.
          */
          styles: {
            'input': {
              'font-size': '16px',
              'font-family': 'helvetica, tahoma, calibri, sans-serif',
              'color': '#3a3a3a'
            },
            '.hosted-fields-invalid:not(:focus)': {
              'color': 'red'
            }
          },
    
          /*
            The fields object defines the fields to be created. All four fields are required
            (name, number, cvc, expiry).
    
            Each field requires a selector for the element in which to create an iframe. Optionally,
            you can define placeholder text and a label selector (the CSS selector of the label
            element for that particular field).
          */
          fields: {
            name: {
              selector: '#name',
              placeholder: 'Roland Robot'
            },
            number: {
              selector: '#number',
              placeholder: '4111 1111 1111 1111'
            },
            cvc: {
              selector: '#cvc',
              placeholder: '123'
            },
            expiry: {
              selector: '#expiry',
              placeholder: '12/34'
            }
          }
        });
      });
    </script>
    
  5. Add the submit event handler

    The submit handler prevents default submission, retrieves a token from Pin Payments, adds the token to the form, and then re-submits the form to the server.

    <script type="text/javascript">
      $(function () {
        /* The submit event for the form. */
    
        $('#payment_form').on('submit', function(e){
          /*
            If there's no card_token element in the form, then tokenisation hasn't happened yet.
            Ensure the default action is prevented and call a function to tokenise the field.
          */
          if( $('#card_token').length == 0 ) {
            e.preventDefault();
            tokenizeHostedFields();
          }
        });
      });
    
      /*
        Tokenises the hosted fields. Appends a hidden field for card_token on success, adds
        error messages otherwise.
      */
    
      function tokenizeHostedFields(){
    
        /*
          Tokenise the card. This requires address details not included in the hosted fields
          which can be pulled from elsewhere (such as other form elements).
        */
        fields.tokenize(
          {
            publishable_api_key: '<Your publishable API key>',
            address_line1: 'Unit 42',
            address_line2: '123 Example St',
            address_city: 'Perth',
            address_postcode: '6000',
            address_state: 'WA',
            address_country: 'Australia'
          },
          function(err, response){
            if(err) {
              /*
                Example error:
    
                {
                  error: "invalid_resource",
                  error_description: "One or more parameters were missing or invalid",
                  messages: [
                    {
                      code: "number_invalid",
                      message: "A valid card number is required",
                      param: "number"
                    }
                  ]
                }
              */
    
              handleErrors(err);
              return;
            }
    
            /*
              Example successful response:
    
              {
                address_city: "Perth",
                address_country: "Australia",
                address_line1: "Unit 42",
                address_line2: "123 Example St",
                address_postcode: "6000",
                address_state: "WA",
                customer_token: null,
                display_number: "XXXX-XXXX-XXXX-0000",
                expiry_month: 12,
                expiry_year: 2034,
                name: "Roland Robot",
                primary: null,
                scheme: "visa",
                token: "card_Evv6AG9AzI2Gg0n3FrmQdw"
              }
            */
    
            /* Append a hidden element to the form with the card_token. */
    
            $('<input>').attr({
              type: 'hidden',
              id: 'card_token',
              name: 'card_token',
              value: response.token
            }).appendTo('#payment_form');
    
            /* Resubmit the form with the added card_token input. */
            $('#payment_form').submit();
          }
        );
      }
    
      /* Handles rendering of the error messages to the form. */
    
      function handleErrors(err){
        /* Clear any existing error messages. */
    
        $('.error_message').text('');
    
        /* Add each error message to their respective divs. */
    
        err.messages.forEach(function(errMsg){
          $('#errors_for_' + errMsg.param).text(errMsg.message);
        });
      }
    </script>
    
  6. Now you can use the card_token parameters on the server using one of the APIs. For example, you can use the token to create a single charge with the charges API. Or you can use the customers API to vault the card details, allowing you to charge the customer repeatedly over time.

    Events

    Hosted Fields has its own event system—a way to run your own code when certain things happen.

    As an example, you might want to initially show the user a loading message and remove it once all the hosted fields are ready. You could hook into Hosted Fields’ ready event to accomplish this. Your code would look something like this:

    fields = HostedFields.create(/* ... details ... */);
    fields.on('ready', function (event) {
      // All the fields are ready, so remove loading messages.
      $('.hosted-fields-loading-message').remove();
    });
    

    Card Scheme Logos

    If you display one card scheme’s logo on your checkout page, you’re required to show other supported card brands equally.

    You can download card schemes logos from here.

Pin Payments acknowledges the Traditional Owners and Custodians of the Country throughout Australia and recognises their continuing connection to land, water and community.
We pay our respects to Aboriginal and Torres Strait Islander cultures, and to Elders past and present.