Documentation

Adding a payment method with a transparent redirect

The primary way to add a payment method is to use a transparent redirect. This allows you to collect a credit card and pass it to Core without ever touching any of the sensitive information.

Build a payment form

First, build a payment form on your site:

<form accept-charset="UTF-8" action="https://core.spreedly.com/v1/payment_methods" method="POST">
    <fieldset>
        <input name="redirect_url" type="hidden" value="http://example.com/transparent_redirect_complete" />
        <input name="environment_key" type="hidden" value="Ll6fAtoVSTyVMlJEmtpoJV8Shw5" />
        <input name="utf8" type="hidden" value="✓">

        <label for="credit_card_first_name">First name</label>
        <input id="credit_card_first_name" name="credit_card[first_name]" type="text" />

        <label for="credit_card_last_name">Last name</label>
        <input id="credit_card_last_name" name="credit_card[last_name]" type="text" />

        <label for="credit_card_number">Card Number</label>
        <input autocomplete="off" id="credit_card_number" name="credit_card[number]" type="text" />

        <label for="credit_card_verification_value">Security Code</label>
        <input autocomplete="off" id="credit_card_verification_value" name="credit_card[verification_value]" type="text" />

        <label for="credit_card_month">Expires on</label>
        <input id="credit_card_month" name="credit_card[month]" type="text" />
        <input id="credit_card_year" name="credit_card[year]" type="text" />

        <button type='submit'>Submit Payment</button>
    </fieldset>
</form>

The names of the input fields are critical, but other than that you have complete control - you can style, layout, and beautify your payment form however you’d like.

Notice the autocomplete="off" attribute on the card number and verification value fields. This is a way to tell browsers to not store these fields in plaintext somewhere on the computer, which is even more important for customers using public computers.

The utf8 hidden field ensures that older versions of Internet Explorer will correctly encode the strings it sends as UTF-8.

NOTE: you do still need to have an SSL certificate for your payment form page. This gives customers confidence in your payment process, and prevents a malicious middle man from tampering with your payment form before it gets to the customer.

Notice the action attribute - this form POST`s directly to Core. Once Core has recorded the information, it will redirect the browser to the url specified in the redirect_url field, tacking on a token that represents the credit card the customer entered. You should then save that returned token - you’ll use it to actually run the payment. In this case the user would be sent to this url:

http://example.com/transparent_redirect_complete?token=CfsYDBam9io4xcvtXq3HNIFNi74

Of course you don’t have to add a real credit card in order to test this out: Core has a set of test cards you can use against a Test Gateway, as well as a simple means of triggering specific errors for testing purposes.

Adding email and/or billing address to a payment method

You also have the ability to add additional fields to your payment form to allow you to store things like email, billing address, and/or phone number with the payment method. For example:

<form accept-charset="UTF-8" action="https://core.spreedly.com/v1/payment_methods" method="POST">
    <fieldset>
        <input name="redirect_url" type="hidden" value="http://example.com/transparent_redirect_complete" />
        <input name="environment_key" type="hidden" value="Ll6fAtoVSTyVMlJEmtpoJV8Shw5" />
        <input name="utf8" type="hidden" value="✓">

        <label for="email">Email</label>
        <input id="email" name="email" type="text">

        <label for="credit_card_first_name">First name</label>
        <input id="credit_card_first_name" name="credit_card[first_name]" type="text" />

        <label for="credit_card_last_name">Last name</label>
        <input id="credit_card_last_name" name="credit_card[last_name]" type="text" />

        <label for="credit_card_number">Card Number</label>
        <input id="credit_card_number" name="credit_card[number]" type="text" />

        <label for="credit_card_verification_value">Security Code</label>
        <input id="credit_card_verification_value" name="credit_card[verification_value]" type="text" />

        <label for="credit_card_address1">Address</label>
        <input id="credit_card_address1" name="credit_card[address1]" type="text">

        <label for="credit_card_address2">Address 2</label>
        <input id="credit_card_address2" name="credit_card[address2]" type="text">

        <label for="credit_card_city">City</label>
        <input id="credit_card_city" name="credit_card[city]" type="text">

        <label for="credit_card_state">State</label>
        <input id="credit_card_state" name="credit_card[state]" type="text">

        <label for="credit_card_zip">Zip</label>
        <input id="credit_card_zip" name="credit_card[zip]" type="text">

        <label for="credit_card_country">Country</label>
        <input id="credit_card_country" name="credit_card[country]" type="text">

        <label for="credit_card_phone_number">Phone</label>
        <input id="credit_card_phone_number" name="credit_card[phone_number]" type="text">

        <label for="credit_card_month">Expires on</label>
        <input id="credit_card_month" name="credit_card[month]" type="text" />
        <input id="credit_card_year" name="credit_card[year]" type="text" />

        <button type='submit'>Submit Payment</button>
    </fieldset>
</form>

You’re given the token at the url:

http://example.com/transparent_redirect_complete?token=PIRGso72MK8IPGizNu03VTFeOBk

And you can see the details are saved in the payment method like so:

$ curl -u 'Ll6fAtoVSTyVMlJEmtpoJV8Shw5:RKOCG5D8D3fZxDSg504D0IxU2XD4Io5VXmyzdCtTivHFTTSylzM2ZzTWFwVH4ucG' \
  -H 'Content-Type: application/xml' \
  https://core.spreedly.com/v1/payment_methods/PIRGso72MK8IPGizNu03VTFeOBk.xml
<payment_method>
  <token>PIRGso72MK8IPGizNu03VTFeOBk</token>
  <created_at type="datetime">2014-04-23T18:31:03Z</created_at>
  <updated_at type="datetime">2014-04-23T18:31:03Z</updated_at>
  <email>frederick@example.com</email>
  <data nil="true"/>
  <storage_state>cached</storage_state>
  <test type="boolean">true</test>
  <last_four_digits>1111</last_four_digits>
  <first_six_digits>411111</first_six_digits>
  <card_type>visa</card_type>
  <first_name>Bob</first_name>
  <last_name>Smith</last_name>
  <month type="integer">1</month>
  <year type="integer">2020</year>
  <address1>345 Main Street</address1>
  <address2>Apartment #7</address2>
  <city>Wanaque</city>
  <state>NJ</state>
  <zip>07465</zip>
  <country>United States</country>
  <phone_number>201-332-2122</phone_number>
  <full_name>Bob Smith</full_name>
  <payment_method_type>credit_card</payment_method_type>
  <errors>
  </errors>
  <verification_value>XXX</verification_value>
  <number>XXXX-XXXX-XXXX-1111</number>
</payment_method>

Specifying full name

You may want your payment form to have only one name field rather than a separate field for first_name and last_name. If you’d prefer this option, you can do so with the full_name attribute like so:

<form accept-charset="UTF-8" action="https://core.spreedly.com/v1/payment_methods" method="POST">
    <fieldset>
        <input name="redirect_url" type="hidden" value="http://example.com/transparent_redirect_complete" />
        <input name="environment_key" type="hidden" value="Ll6fAtoVSTyVMlJEmtpoJV8Shw5" />
        <input name="utf8" type="hidden" value="✓">

        <label for="credit_card_full_name">Name</label>
        <input id="credit_card_full_name" name="credit_card[full_name]" type="text" />

        <label for="credit_card_number">Card Number</label>
        <input id="credit_card_number" name="credit_card[number]" type="text" />

        <label for="credit_card_verification_value">Security Code</label>
        <input id="credit_card_verification_value" name="credit_card[verification_value]" type="text" />

        <label for="credit_card_month">Expires on</label>
        <input id="credit_card_month" name="credit_card[month]" type="text" />
        <input id="credit_card_year" name="credit_card[year]" type="text" />

        <button type='submit'>Submit Payment</button>
    </fieldset>
</form>

You’re given the token at the url:

http://example.com/transparent_redirect_complete?token=2BzTYoFMQ9Lz3H2aE6NvI4o3BIa

And you can see the details are saved in the payment method like so:

$ curl -u 'Ll6fAtoVSTyVMlJEmtpoJV8Shw5:RKOCG5D8D3fZxDSg504D0IxU2XD4Io5VXmyzdCtTivHFTTSylzM2ZzTWFwVH4ucG' \
  -H 'Content-Type: application/xml' \
  https://core.spreedly.com/v1/payment_methods/2BzTYoFMQ9Lz3H2aE6NvI4o3BIa.xml
<payment_method>
  <token>2BzTYoFMQ9Lz3H2aE6NvI4o3BIa</token>
  <created_at type="datetime">2014-04-23T18:31:04Z</created_at>
  <updated_at type="datetime">2014-04-23T18:31:04Z</updated_at>
  <email nil="true"/>
  <data nil="true"/>
  <storage_state>cached</storage_state>
  <test type="boolean">true</test>
  <last_four_digits>1111</last_four_digits>
  <first_six_digits>411111</first_six_digits>
  <card_type>visa</card_type>
  <first_name>Gottfried Wilhelm</first_name>
  <last_name>Leibniz</last_name>
  <month type="integer">1</month>
  <year type="integer">2020</year>
  <address1 nil="true"/>
  <address2 nil="true"/>
  <city nil="true"/>
  <state nil="true"/>
  <zip nil="true"/>
  <country nil="true"/>
  <phone_number nil="true"/>
  <full_name>Gottfried Wilhelm Leibniz</full_name>
  <payment_method_type>credit_card</payment_method_type>
  <errors>
  </errors>
  <verification_value>XXX</verification_value>
  <number>XXXX-XXXX-XXXX-1111</number>
</payment_method>

Adding bank accounts

You can also add bank accounts as payment methods in Spreedly to be used with payment gateways that support them. This is done like so:

<form accept-charset="UTF-8" action="https://core.spreedly.com/v1/payment_methods" method="POST">
    <fieldset>
        <input name="redirect_url" type="hidden" value="http://example.com/transparent_redirect_complete" />
        <input name="environment_key" type="hidden" value="Ll6fAtoVSTyVMlJEmtpoJV8Shw5" />
        <input name="utf8" type="hidden" value="✓">

        <input name="payment_method_type" type="hidden" value="bank_account" />

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

        <label for="bank_name">Bank Name</label>
        <input id="bank_name" name="bank_name" type="text" />

        <label for="bank_routing_number">Bank Routing Number</label>
        <input id="bank_routing_number" name="bank_routing_number" type="text" />

        <label for="bank_account_number">Account Number</label>
        <input id="bank_account_number" name="bank_account_number" type="text" />

        <label for="bank_account_type">Account Type</label>
        <select id="bank_account_type" name="bank_account_type">
            <options value="checking" />
            <options value="savings" />
        </select>

        <label for="bank_account_holder_type">Account Holder</label>
        <select id="bank_account_holder_type" name="bank_account_holder_type">
            <options value="personal" />
            <options value="business" />
        </select>

        <button type='submit'>Submit Payment</button>
    </fieldset>
</form>

You’re given the token at the url:

http://example.com/transparent_redirect_complete?token=JXoi38frF8bB5mrt73mwpQhYD1x

The only required fields for a bank account are full_name (or first_name/last_name), bank_routing_number, and bank_account_number. The rest are optional at the Spreedly level, and whether you want to collect them will depend on what your gateway requires.

Currently only US bank accounts are supported, so the bank_routing_number must be a valid US ABA Number.

Valid values for bank_account_type are checking and savings, and valid values for bank_account_holder_type are personal and business.

A bank account looks like this when you pull it back out:

$ curl -u 'Ll6fAtoVSTyVMlJEmtpoJV8Shw5:RKOCG5D8D3fZxDSg504D0IxU2XD4Io5VXmyzdCtTivHFTTSylzM2ZzTWFwVH4ucG' \
  -H 'Content-Type: application/xml' \
  https://core.spreedly.com/v1/payment_methods/JXoi38frF8bB5mrt73mwpQhYD1x.xml
<payment_method>
  <token>JXoi38frF8bB5mrt73mwpQhYD1x</token>
  <created_at type="datetime">2014-04-23T18:31:04Z</created_at>
  <updated_at type="datetime">2014-04-23T18:31:04Z</updated_at>
  <email nil="true"/>
  <data nil="true"/>
  <storage_state>cached</storage_state>
  <test type="boolean">true</test>
  <full_name>Bob Smith</full_name>
  <bank_name>First Bank of Elbonia</bank_name>
  <account_type>checking</account_type>
  <account_holder_type>personal</account_holder_type>
  <routing_number_display_digits>021</routing_number_display_digits>
  <account_number_display_digits>4321</account_number_display_digits>
  <first_name>Bob</first_name>
  <last_name>Smith</last_name>
  <payment_method_type>bank_account</payment_method_type>
  <errors>
  </errors>
  <routing_number>021*</routing_number>
  <account_number>*4321</account_number>
</payment_method>

Tracking customers

Since Core uses a transparent redirect to actually receive the data for your customers, you need some way to know what user you’re dealing with when they arrive back at your system. There are two ways to do this: the redirect_url and/or by passing custom data through.

Using the redirect_url

In the transparent redirect form that gets POST'ed to Core, one of the fields is the redirect_url. The site building the form has complete control over what’s put in this field, which means that you can easily drop an identifier for the customer (and/or their order or other identifier) into the url, like so:

http://example.com/store/order/1234/finish

Where “1234” is the order number that needs to be completed. This would be redirected back to you like so:

http://example.com/store/order/1234/finish?token=coretoken

You can thus finish processing the order using the payment method token passed back from Core.

Core is also smart enough to handle query parameters, so this redirect_url:

http://example.com/store/order?id=1234

Will get sent back as:

http://example.com/store/order?id=1234&token=coretoken

Using Passthrough Data

Sometimes you need to pass more information than the redirect_url will comfortably contain, or you need to pass it in a format that’s not easily accommodated by a url. For these cases we’ve included the ability to pass custom data on the Core POST and pull it out using the token that’s passed back to you.

To pass data through, just specify the data fields in your form like so:

<form accept-charset="UTF-8" action="https://core.spreedly.com/v1/payment_methods" method="POST">
    <fieldset>
        <input name="redirect_url" type="hidden" value="http://example.com/transparent_redirect_complete" />
        <input name="environment_key" type="hidden" value="Ll6fAtoVSTyVMlJEmtpoJV8Shw5" />
        <input name="utf8" type="hidden" value="✓">

        <input name="data[how_many]" type="text" value="5" />
        <input name="data[some_other_data]" type="text" value="Here is some additional data" />

        <label for="credit_card_first_name">First name</label>
        <input id="credit_card_first_name" name="credit_card[first_name]" type="text" />

        <label for="credit_card_last_name">Last name</label>
        <input id="credit_card_last_name" name="credit_card[last_name]" type="text" />

        <label for="credit_card_number">Card Number</label>
        <input id="credit_card_number" name="credit_card[number]" type="text" />

        <label for="credit_card_verification_value">Security Code</label>
        <input id="credit_card_verification_value" name="credit_card[verification_value]" type="text" />

        <label for="credit_card_month">Expires on</label>
        <input id="credit_card_month" name="credit_card[month]" type="text" />
        <input id="credit_card_year" name="credit_card[year]" type="text" />

        <button type='submit'>Submit Payment</button>
    </fieldset>
</form>

The name attribute for the data fields is important. In the form above, we have ‘data[how_many]’ and ‘data[some_other_data]’. When you later inquire about the payment method, you’ll find that the data field holds whatever you passed through at the beginning:

$ curl -u 'Ll6fAtoVSTyVMlJEmtpoJV8Shw5:RKOCG5D8D3fZxDSg504D0IxU2XD4Io5VXmyzdCtTivHFTTSylzM2ZzTWFwVH4ucG' \
  https://core.spreedly.com/v1/payment_methods/RKrjpco9VtkhEgv3RQEPfmBWB9E.xml

That will give you output like this:

<payment_method>
  <token>RKrjpco9VtkhEgv3RQEPfmBWB9E</token>
  <created_at type="datetime">2014-04-23T18:31:04Z</created_at>
  <updated_at type="datetime">2014-04-23T18:31:04Z</updated_at>
  <email nil="true"/>
  <data>
    <how_many>5</how_many>
    <some_other_data>Here is some additional data</some_other_data>
  </data>
  <storage_state>cached</storage_state>
  <test type="boolean">true</test>
  <last_four_digits>1111</last_four_digits>
  <first_six_digits>411111</first_six_digits>
  <card_type>visa</card_type>
  <first_name>Bob</first_name>
  <last_name>Smith</last_name>
  <month type="integer">1</month>
  <year type="integer">2020</year>
  <address1 nil="true"/>
  <address2 nil="true"/>
  <city nil="true"/>
  <state nil="true"/>
  <zip nil="true"/>
  <country nil="true"/>
  <phone_number nil="true"/>
  <full_name>Bob Smith</full_name>
  <payment_method_type>credit_card</payment_method_type>
  <errors>
  </errors>
  <verification_value>XXX</verification_value>
  <number>XXXX-XXXX-XXXX-1111</number>
</payment_method>

The names you choose for your data fields can be whatever you’d like, as long as they’re using the format of ‘data[your_field_name_goes_here]’.

In your data fields, you can use a format like XML or JSON to pass a data structure through if you’d like. Of course, it has to live within the HTML form, so you may need to use something like Base64 to encode it if it ends up being at all complicated. In general though, you probably won’t want to pass through very much data in the transparent redirect since you have your own database to store information and the data field is really intended as a way for you to associate some application specific order information while keeping things simple with one payment form for your customer.

Now comes the important caveat: the data in this field can be tampered with (as can, for that matter, your redirect_url). What that means is that you should never pass any data through that either the customer should not know about, or that the customer should not be able to tamper with. A good example is an item price - if you pass it through the data field on the form, a customer could grab the form, change the price, and thereby give themselves a nice discount.

The easiest way to deal with the tampering issue is to not send through data that is valuable to tamper with. Instead of passing through the total amount, instead pass through the id of the invoice in your system, and use that to look up the invoice and pull the total from there. If you absolutely must passthrough tamper-sensitive data, then you will need to tamper proof it using a standard like HMAC, which is beyond the scope of this documentation.