Charge credit cards in multiple currencies.
Always free to use for testing. Try it now →

Building Secure Payment Forms

Pin.js allows you to accept credit card payments without the need to send the credit card details to your server.

api.createCardToken(creditCard).then(function(cardToken) {

Your customer’s credit card details are posted securely and directly to Pin Payments in your customer’s browser, returning to you a card token which you can use on your server to perform a charge against the card using the API.


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 credit card details into a Pin Payments card token. It then submits the original form, along with the token, to your server.

  1. Include Pin.js

    Paste the following code in the <head> of your page:

    <script src=''></script>
  2. Create a payment form

    The lack of name attributes on the inputs prevents them from being submitted to your server. In addition, be mindful not to give any elements an id or name of 'submit' to ensure the form submits correctly.

    <form action='/url_to_your_server_to_create_charge' class='pin' method='post'>
      <div class='errors' style='display:none'>
          The lack of 'name' attributes on these inputs prevents
          the browser from submitting them to your server
        <label for='address-line1'>Address 1</label>
        <input id='address-line1'>
        <label for='address-line2'>Address 2</label>
        <input id='address-line2'>
        <label for='address-city'>City</label>
        <input id='address-city'>
        <label for='address-state'>State</label>
        <input id='address-state'>
        <label for='address-postcode'>Postcode</label>
        <input id='address-postcode'>
        <label for='address-country'>Country</label>
        <input id='address-country'>
          The lack of 'name' attributes on these inputs prevents
          the browser from submitting them to your server
        <label for='cc-number'>Credit Card Number</label>
        <input id='cc-number' type='text'>
        <label for='cc-name'>Name on Card</label>
        <input id='cc-name' type='text'>
        <label for='cc-expiry-month'>Expiry Month</label>
        <input id='cc-expiry-month'>
        <label for='cc-expiry-year'>Expiry Year</label>
        <input id='cc-expiry-year'>
        <label for='cc-cvc'>CVC</label>
        <input id='cc-cvc'>
        In order for the form to submit correctly, please be sure not
        to give any elements in the form an id or name of 'submit'.
      <input type='submit' value='Pay now'>
  3. 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.

    // 1. Wait for the page to load
    $(function() {
      // 2. Create an API object with your publishable api key, and
      // specifying 'test' or 'live'.
      // Be sure to use your live publishable key with the live api, and
      // your test publishable key with the test api.
      var pinApi = new Pin.Api('your publishable key', 'test');
      var form = $(''),
          submitButton = form.find(":submit"),
          errorContainer = form.find('.errors'),
          errorList = errorContainer.find('ul'),
          errorHeading = errorContainer.find('h3');
      // 3. Add a submit handler to the form which calls Pin.js to
      // retrieve a card token, and then add that token to the form and
      // submit the form to your server.
      form.submit(function(e) {
        // Clear previous errors
        // Disable the submit button to prevent multiple clicks
        submitButton.attr({disabled: true});
        // Fetch details required for the createToken call to Pin Payments
        var card = {
          number:           $('#cc-number').val(),
          name:             $('#cc-name').val(),
          expiry_month:     $('#cc-expiry-month').val(),
          expiry_year:      $('#cc-expiry-year').val(),
          cvc:              $('#cc-cvc').val(),
          address_line1:    $('#address-line1').val(),
          address_line2:    $('#address-line2').val(),
          address_city:     $('#address-city').val(),
          address_state:    $('#address-state').val(),
          address_postcode: $('#address-postcode').val(),
          address_country:  $('#address-country').val()
        // Request a token for the card from Pin Payments
        pinApi.createCardToken(card).then(handleSuccess, handleError).done();
      function handleSuccess(card) {
        // Add the card token to the form
        // Once you have the card token on your server you can use your
        // private key and Charges API to charge the credit card.
          .attr({type: 'hidden', name: 'card_token'})
        // Resubmit the form to the server
        // Only the card_token will be submitted to your server. The
        // browser ignores the original form inputs because they don't
        // have their 'name' attribute set.
      function handleError(response) {
        if (response.messages) {
          $.each(response.messages, function(index, paramError) {
              .text(paramError.param + ": " + paramError.message)
        // Re-enable the submit button
  4. 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 to create multiple charges over time with the Customers API.

    This example above used jQuery, but you don't have to—Pin.js itself does not depend on any front-end library.