Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at the New York ColdFusion User Group (Jul. 2009) with: Sean Schroeder

Accepting PCI-Compliant Payments Without A Merchant Account Using Stripe And ColdFusion

By Ben Nadel on

This week, I started looking at simple solutions for collecting online payments without the hassle of obtaining a merchant account. I have a couple of personal projects in mind and I wanted to find a way to charge people a nominal amount of money with ease while adhering to proper PCI (Payment Card Industry) compliance standards. When I asked for suggestions on Twitter, a good number of people suggested that I check out Stripe.com.


 
 
 

 
  
 
 
 

Stripe provides a fee-based online payment gateway that requires nothing more than your bank routing number and account number. When you collect a payment through Stripe, you get charged a flat fee of 30 cents plus 2.9% of the purchase amount. This hold true for all accepted credit cards, including American Express. Furthermore, there's no setup fee of ongoing service fees. And, you don't get charged for failed transaction; as they say on their homepage, "you only pay when you make money."

In addition to the easy setup, the most exciting thing about Stripe is that it facilitates adherence to PCI (Payment Card Industry) compliance by allowing you to process an order without ever having credit card information touch your server. It does this by performing a secure, client-side AJAX request to the Stripe API. During this request, the client (ie. browser) exchanges credit card information for a one-time-use token. This token can then safely be submitted to your server and subsequently used to charge the aforementioned credit card.


 
 
 

 
 Stripe.com allows online payment forms to maintain PCI compliance by using client-side credit card handling. 
 
 
 

If you need to create a subscription-based payment plan, this one-time-use token can also be used to create a Stripe customer record and subscription. This customer and associated credit card (stored on the Stripe PCI-compliant servers) can then be charged periodically using Stripe "Plans" (ie. subscription plans) and the Stripe API.

The whole concept seemed rather intriguing so I signed up (in about 2 minutes with immediate activation) and wanted to see if I could code an online payment form. For this demo, I'll be accepting personal information (name and email) as well as credit card information. This will require dual validation, with one API call going to Stripe and one API call going to my server.

The client-side API call being made to Stripe.com is facilitated by the Stripe JavaScript library, which is loaded directly off of their CDN (content delivery network). This takes care of the secure, cross-domain AJAX request that obtains a one-time-use token given the user's credit card information. Since the payment form ultimately submits back to itself, there is only one page in this demo (not including the confirmation page which holds no interesting value).

  • <!--- Param the form posts. --->
  • <cfparam name="form.submitted" type="boolean" default="false" />
  • <cfparam name="form.name" type="string" default="" />
  • <cfparam name="form.email" type="string" default="" />
  • <cfparam name="form.donation" type="numeric" default="1" />
  • <cfparam name="form.stripeToken" type="string" default="" />
  •  
  • <!--- A flag for validation-only requests (for AJAX). --->
  • <cfparam name="form.validateOnly" type="boolean" default="false" />
  •  
  •  
  • <!--- Create an errors collection. --->
  • <cfset errors = [] />
  •  
  •  
  • <!---
  • Check to see if the form has been submitted. The credit card
  • form will be posting back to itself. However, note that we are
  • NOT POSTING any credit card information to OUR server (to keep
  • in accordance with PCI compliance).
  • --->
  • <cfif form.submitted>
  •  
  •  
  • <!--- Check for a name. --->
  • <cfif !len( form.name )>
  •  
  • <cfset arrayAppend( errors, "Please enter your name." ) />
  •  
  • </cfif>
  •  
  • <!--- Check for an email. --->
  • <cfif !isValid( "email", form.email )>
  •  
  • <cfset arrayAppend( errors, "Please enter a valid eamil." ) />
  •  
  • </cfif>
  •  
  • <!--- Check for an amount. --->
  • <cfif (form.donation lt 1)>
  •  
  • <cfset arrayAppend( errors, "Please select a donation." ) />
  •  
  • </cfif>
  •  
  • <!--- Check for transaction token. --->
  • <cfif !len( form.stripeToken )>
  •  
  • <cfset arrayAppend( errors, "Something went wrong with your credit card information. Please double-check your information." ) />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • Check to see if we are using asynchronous validation of the
  • form. If so, let's just return an "API" response rather than
  • fully processing the form data.
  • --->
  • <cfif form.validateOnly>
  •  
  • <!--- Check to see if there are any errors. --->
  • <cfif arrayLen( errors )>
  •  
  • <!--- Create an error response. --->
  • <cfset response = {} />
  • <cfset response[ "success" ] = false />
  • <cfset response[ "errors" ] = errors />
  •  
  • <cfelse>
  •  
  • <!--- Create a success response. --->
  • <cfset response = {} />
  • <cfset response[ "success" ] = true />
  •  
  • </cfif>
  •  
  • <!--- Serialize the response. --->
  • <cfset responseJSON = serializeJSON( response ) />
  •  
  • <!--- Return the API response. --->
  • <cfcontent
  • type="text/x-application-json"
  • variable="#toBinary( toBase64( responseJSON ) )#"
  • />
  •  
  • <!--- NOTE: API processing has been halted. --->
  •  
  • </cfif>
  •  
  •  
  • <!---
  • If we made it this far, we are doing server-side processing.
  • Check to see if there were any errors.
  • --->
  • <cfif !arrayLen( errors )>
  •  
  •  
  • <!---
  • Try to process the credit card transaction. Since a
  • number of things can go wrong at this point, let's
  • wrap this in a try/catch block.
  • --->
  • <cftry>
  •  
  •  
  • <!---
  • Charge the customer using the Stripe API. For this
  • request, the username is our SECRET key. The password
  • will be left blank.
  • --->
  • <cfhttp
  • result="charge"
  • method="post"
  • url="https://api.stripe.com/v1/charges"
  • username="#application.stripeSecretKey#"
  • password="">
  •  
  • <!--- Our donation amount (in cents). --->
  • <cfhttpparam
  • type="formfield"
  • name="amount"
  • value="#(form.donation * 100)#"
  • />
  •  
  • <!--- Our currency (only USD if supported. --->
  • <cfhttpparam
  • type="formfield"
  • name="currency"
  • value="usd"
  • />
  •  
  • <!---
  • For the "Card" value, we will provide the Stripe
  • transaction token that we received from the client-
  • side API call.
  • --->
  • <cfhttpparam
  • type="formfield"
  • name="card"
  • value="#form.stripeToken#"
  • />
  •  
  • <!---
  • A description of the transaction to show up in
  • OUR records for tracking purposes. It is
  • considered a good practice to add the Email
  • address here in order to follow up if necessary.
  • --->
  • <cfhttpparam
  • type="formfield"
  • name="description"
  • value="Testing the Stripe.com API. (#form.email#)."
  • />
  •  
  • </cfhttp>
  •  
  •  
  • <!--- Deserialize the response. --->
  • <cfset response = deserializeJSON( charge.fileContent ) />
  •  
  •  
  • <!---
  • Check to see if an ERROR key exists. If so, then
  • there was a problem with the transaction.
  • --->
  • <cfif structKeyExists( response, "error" )>
  •  
  • <!--- Add the message to the errors. --->
  • <cfset arrayAppend(
  • errors,
  • response.error.message
  • ) />
  •  
  • <!--- Throw an errors to break the processing. --->
  • <cfthrow type="InvalidRequestError" />
  •  
  • </cfif>
  •  
  •  
  • <!--- ----------------------------------------- --->
  • <!--- ----------------------------------------- --->
  •  
  •  
  • <!---
  • If we made it this far without error, then we
  • successfully processed the credit card and can move
  • to the confirmation page.
  • --->
  • <cflocation
  • url="./success.cfm"
  • addtoken="false"
  • />
  •  
  •  
  • <!--- ----------------------------------------- --->
  • <!--- ----------------------------------------- --->
  •  
  •  
  • <!--- Catch invalid request errors. --->
  • <cfcatch type="InvalidRequestError">
  •  
  • <!--- Nothing to do here. --->
  •  
  • </cfcatch>
  •  
  •  
  • <!--- Catch any unexpected errors. --->
  • <cfcatch>
  •  
  • <cfset arrayAppend(
  • errors,
  • "There was an unexpected error during the processing of your purchase. The error has been logged an our team is looking into it."
  • ) />
  •  
  • </cfcatch>
  •  
  • </cftry>
  •  
  •  
  • </cfif>
  •  
  •  
  • </cfif>
  •  
  •  
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  •  
  •  
  • <!--- Reset the content buffer. --->
  • <cfcontent type="text/html; charset=utf-8" />
  •  
  • <cfoutput>
  •  
  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Accepting Online Payments With Stripe</title>
  •  
  • <!-- Include linked scripts. -->
  • <script type="text/javascript" src="../jquery-1.7.js"></script>
  •  
  • <!-- Load the STRIPE API from their CDN. -->
  • <script type="text/javascript" src="https://js.stripe.com/v1/"></script>
  • </head>
  • <body>
  •  
  • <h1>
  • Accepting Online Payments With Stripe
  • </h1>
  •  
  •  
  • <!--- --------------------------------------------- --->
  • <!--- --------------------------------------------- --->
  •  
  •  
  • <!--- Check to see if we have any errors. --->
  • <cfif (
  • form.submitted &&
  • arrayLen( errors )
  • )>
  •  
  • <h3>
  • Please review the following:
  • </h3>
  •  
  • <ul>
  • <!--- Output the list of errors. --->
  • <cfloop
  • index="error"
  • array="#errors#">
  •  
  • <li>
  • #error#
  • </li>
  •  
  • </cfloop>
  • </ul>
  •  
  • </cfif>
  •  
  •  
  • <!--- --------------------------------------------- --->
  • <!--- --------------------------------------------- --->
  •  
  •  
  • <form method="post" action="#cgi.script_name#">
  •  
  • <!--- Flag the form submission. --->
  • <input type="hidden" name="submitted" value="true" />
  •  
  • <!---
  • This is the Stripe token. It holds a one-use-only
  • value that can be used to charge the given credit
  • card a given amount. Once we pass the credit card
  • info to the Stripe site (note: PCI comppliance),
  • we will get a token in return.
  • --->
  • <input type="hidden" name="stripeToken" value="" />
  •  
  •  
  • <p>
  • Name:<br />
  • <input
  • type="text"
  • name="name"
  • value="#htmlEditFormat( form.name )#"
  • size="20"
  • />
  • </p>
  •  
  • <p>
  • Email:<br />
  • <input
  • type="text"
  • name="email"
  • value="#htmlEditFormat( form.email )#"
  • size="20"
  • />
  • </p>
  •  
  • <p>
  • Donation:<br />
  • <select name="donation">
  • <option value="1">$1</option>
  • <option value="2">$2</option>
  • <option value="3">$3</option>
  • <option value="4">$4</option>
  • <option value="5">$5</option>
  • </select>
  • </p>
  •  
  •  
  • <!---
  • The user is going to enter their credit card
  • information below. Notice that NONE of the credit-
  • card fields have Name values. This will prevent them
  • from being submitted to OUR server which is what we
  • need to avoid in order to comply with PCI standards
  • (the credit card information CANNOT touch our server).
  • --->
  •  
  • <!-- ------------------------------- -->
  • <!-- BEGIN: Credit Card Information. -->
  • <!-- ------------------------------- -->
  •  
  • <p>
  • Credit Card:<br />
  • <input
  • type="text"
  • value="4242424242424242"
  • size="20"
  • class="creditCard"
  • />
  • </p>
  •  
  • <p>
  • Expiration:<br />
  • <input type="text" size="5" class="expirationMonth" />
  • <input type="text" size="5" class="expirationYear" />
  • <em>(MM/YYYY)</em>
  • </p>
  •  
  • <p>
  • Security Code:<br />
  • <input type="text" size="5" class="securityCode" />
  • </p>
  •  
  • <!-- ----------------------------- -->
  • <!-- END: Credit Card Information. -->
  • <!-- ----------------------------- -->
  •  
  •  
  • <p>
  • <input type="submit" value="Make A Donation!" />
  • </p>
  •  
  • </form>
  •  
  •  
  • <!--- Now that the DOM is mostly ready. --->
  • <script type="text/javascript">
  •  
  •  
  • // Get a reference to our main DOM elements.
  • var dom = {};
  • dom.form = $( "form" );
  • dom.stripeToken = dom.form.find( "input[ name = 'stripeToken' ]" );
  • dom.name = dom.form.find( "input[ name = 'name' ]" );
  • dom.email = dom.form.find( "input[ name = 'email' ]" );
  • dom.donation = dom.form.find( "select[ name = 'donation' ]" );
  • dom.creditCard = dom.form.find( "input.creditCard" );
  • dom.expirationMonth = dom.form.find( "input.expirationMonth" );
  • dom.expirationYear = dom.form.find( "input.expirationYear" );
  • dom.securityCode = dom.form.find( "input.securityCode" );
  •  
  •  
  • // ---------------------------------------------- //
  • // ---------------------------------------------- //
  •  
  •  
  • // Our Stripe.js file gave us an API to work with. Let's
  • // identify our site.
  • //
  • // NOTE: We are using the DEMO key for this example. This
  • // allows us to test without truly being charged.
  • Stripe.setPublishableKey( "#application.stripePublicKey#" );
  •  
  •  
  • // Intersect the form submission so that we can interact
  • // the Stripe API to get our transaction token.
  • dom.form.submit(
  • function( event ){
  •  
  • // Cancel the default event - we don't want the
  • // form to submit... YET. We need to contact the
  • // Stripe API first.
  • event.preventDefault();
  •  
  • // Get a transaction token from the Stripe API.
  • // This will store the credit card in the Stripe
  • // database. We can then use the token to
  • // actually execute the charge.
  • Stripe.createToken(
  •  
  • // The credit card information.
  • {
  • number: dom.creditCard.val(),
  • exp_month: dom.expirationMonth.val(),
  • exp_year: dom.expirationYear.val(),
  • cvc: dom.securityCode.val()
  • },
  •  
  • // The amount of the purchase. This amount
  • // is in the form of cents.
  • (dom.donation.val() * 100),
  •  
  • // The callback for our transaction token.
  • tokenHandler
  •  
  • );
  •  
  • }
  • );
  •  
  •  
  • // I handle the response from the Stripe token request.
  • // Since this request is asynchronous, we will get a
  • // response using a callback mechanism.
  • function tokenHandler( status, response ){
  •  
  • // Check to see if the response contains an error
  • // (ie. if the "error" key exists in the response).
  • if (response.hasOwnProperty( "error" )){
  •  
  • // Oh snap! Something went wrong. Alert the user.
  • alert(
  • "Something went wrong!\n\n" +
  • response.error.message
  • );
  •  
  • // Return out - there's no more processing to
  • // be done at this point.
  • return;
  •  
  • }
  •  
  • // If the "error" key did not exist, then our token
  • // should have been returned successfully. We can
  • // now store it in the form and process the form.
  • dom.stripeToken.val( response.id );
  •  
  • // Now, let's validate our non-stripe data.
  • var validation = $.ajax({
  • type: "post",
  • url: "#cgi.script_name#",
  • data: {
  • submitted: true,
  • validateOnly: true,
  • name: dom.name.val(),
  • email: dom.email.val(),
  • donation: dom.donation.val(),
  • stripeToken: response.id
  • },
  • dataType: "json"
  • });
  •  
  • // Check the validate asynchronous response.
  • validation.done(
  • function( response ){
  •  
  • // Check to see if the validate passed.
  • if (response.success){
  •  
  • // Both the stripe API call and the local
  • // server validation worked. Unbind any
  • // form handlers (so we don't go into an
  • // endless loop) and submit the form.
  • dom.form
  • .unbind( "submit" )
  • .submit()
  • ;
  •  
  • } else {
  •  
  • // Alert the errors.
  • alert(
  • "Something went wrong!\n\n- " +
  • response.errors.join( "\n- " )
  • );
  •  
  • }
  •  
  • }
  • );
  •  
  • }
  •  
  •  
  • </script>
  •  
  • </body>
  • </html>
  •  
  • </cfoutput>

In the demo code, take notice that none of the credit-card-based form fields have a "Name" attribute. This ensures that, should anything go wrong, no credit card information will ever be submitted to our server - unnamed form fields are never submitted with the HTTP POST. The only relevant values that get submitted to our server are the purchase amount and the one-time-use token returned by the Stripe API.

Once the payment form has been submitted to our server, we can use the one-time-use token to charge the credit card using ColdFusion's CFHTTP tag and the Stripe API. This call can result in either a success or an error JSON response:


 
 
 

 
 The Stripe.com API will return either a success or error JSON response. 
 
 
 

All in all, the whole thing was super easy to get set up. Obviously, there's room for some more unified validation and error checking; but, as far as going from nothing to working online payment form, we're talking like 2 hours of coding and testing. And, speaking of testing, all you have to do is use the "test" public and private keys; no different API urls; no setting the mode in the Stripe dashboard; just use the test keys and you're ready to process transactions without actually charging people money.

As a web developer, I've always got a few small, personal project ideas rattling around in my head. Some of these ideas provide services that cost me money (ex. using Twilio to send/receive SMS text messages). It's nice to know that I can quickly and easily create secure, online, PCI-compliant payment forms if I end up creating a service that actually costs money to run. There's a lot more experimenting that needs to be done with Stripe.com; but, from my initial research, this payment gateway seems super easy to work with.



Reader Comments

This service looks very similar to Braintree Payment Solutions which works the same way, more or less. The mechanics are all the same (e.g. the browser submits the card to them in the background in exchange for a token) which keeps your site out of scope for compliance, though at a glance Braintree appears to be a more mature system and has a lot more options. They're also more expensive with a monthly fee and setup charge. Their transaction rates are about the same though. Stripe.com looks to be easier to implement and geared towards developers where Braintree has a more corporate feel to it. I'm about to implement Braintree on a project so it will be interesting to see how my resulting code compares to this. It's good to have additional options for taking cards outside of PCI compliance.

Reply to this Comment

Looks pretty interesting. Definitely feels less kludgy than the entry level PayPal integration, especially since that requires going outside your cart/checkout process and depending on getting payment information back through IPN.

Reply to this Comment

Just how much better is it than PayPal? How does Stripe scale up - can they grow as the small business grows?

Reply to this Comment

@Justin,

A few people had mentioned Braintree when I asked on Twitter. One thing I didn't like about it, from a cursory glance, was that is drew a separation between Merchant account and payment gateway. The nice thing about Stripe is that they make no mention of this, really. In fact, they tell you straight off you don't need one:

"You don't need a merchant account or gateway. Stripe handles everything, including storing cards, subscriptions, and direct payouts to your bank account."

Stripe's whole message seems to be about making stuff really easy, and that's what I was looking for. And, they seem to have subscription and recurring payment plans, which I think will cover most of what I would need.

That said, I've only gotten this far, so my reaction is really skin-deep.

@Bob,

You always make my day ;)

@Robert,

I started off looking at the PayPal solutions. I even started to fill out their forms... but it just never felt good. In fact, the form bombed out on me (returning a server error), I think because I tried to enter a new "business account" using my existing personal PayPal credentials.

I went back to the PayPal website a few times; but each time, I was just turned off by something.

@Jason,

Cool, glad this was timely!

@Lola,

I can't say I know anything about scalability. But, on the Stripe website, they have a picture of a "cloud".... doesn't everything in the cloud automatically scale, magically, without problem (he says not really believing anything he just said).

Reply to this Comment

@All,

Also, one thing about the PayPal website that I didn't like was that the "recurring billing" feature seemed to be a flat fee of like $30/month just to have available. I believe Stripe provides this for free (once again, they only charge you *when* you are actually making money).

Reply to this Comment

The other downside to PayPal is not being able to work directly with their API unless you fork out the extra bucks for a PayFlow account (IIRC). Otherwise you have to post your cart to PayPal's site let, let them handle the checkout process, and then redirect back to your site which totally blows your UX out of the water.

This seems like a much better solution, IMHO. I will definitely be playing with this soon.

Reply to this Comment

@Ben, I hadn't noticed the distinction with the merchant accounts, but that is an important one. I suspect Stripe is handling that in the background for you where Braintree will work with an existing merchant account if you have one. Once I have actually integrated it we will have to compare notes at one of the conferences. Just like operating systems and programming languages, use whatever works best for you. I will certainly be considering Stripe for some of my smaller clients that need to take payments though.

Reply to this Comment

@Justin,

That's a good point - I hadn't thought of that. I suspect that Stripe is aimed at people going from zero-to-something. I don't see a way to work with an existing merchant account.

Anyway, this is the *first* time I've done anything that didn't go through Authorize.NET or PayFlowPro... so, I'm just hypothesizing about any intents / benefits.

@Anna,

My pleasure :)

Reply to this Comment

Ben, will you please send me your address so I can send you some sort of gift, booze or loose women??? We have been looking for a simple solution for a payment gateway so we can make huge piles of cash (much like our Twilio service)!! Your better than an ATM brother!

Reply to this Comment

I've been poking around at that site, but all I see are code examples. Are there any live sites that use Strip? I'm trying to get an idea of how this implementation works out in reality.

Reply to this Comment

Ben,

We have a couple of CF client sites which we setup on Stripe.com over the past couple of months and are very pleased. We did some testing on Stripe during their beta period and liked what we saw and implemented it in production recently.

Their pricing is generous in comparison to PayPal and Braintree if you are doing smaller transactions. FYI, if you are charging in the hundreds of thousands/month then PayPal will seriously discount for you and make it lucrative to use them as your merchant.

We just switched over one of our clients for instance that had a merchant account with BofA -- BofA though is switching all merchant accounts from internal/Cybersource to another processor/gateway. It was easier, quicker and more cost effective to just switch to stripe.com.

I highly recommend stripe.com and their support with any questions has been great as well!

Let me know any questions for using it in production.

Regards,
Jeremy

Reply to this Comment

Thanks for posting this Ben.
It's amazing all of the great new companies there are to make people like us not cringe at the thought of integration.

This is Square, for developers.
Great find!

Reply to this Comment

I'm a huge fan of Stripe.

I looked into Braintree but in order to use it, you HAVE to use one of their client libraries. Since there's no CF library, you'd have to use the one for Java.

A cfhttp call is just more elegant IMO.

Stripe isn't the be-all-end-all-perfect solution for everything but in cases like this, it's amazing.

Reply to this Comment

@Aaron,

One of my clients has recently signed up for Braintree and their staff assures us that we can assemble our own XML and pass it to the gateway directly through an HTTP call without having to use one of their "preferred" libraries. I have not begun implementation yet, but I hope that bears out or we will be giving Stripe a good look instead.

Reply to this Comment

Thanks Ben. Very interesting. I have signed up to be notified when they make this available in Australia! I would love to ditch PayPal!

Reply to this Comment

just like @Murray, i would love to see this available outside the US. anybody anything similar to this available internationally?

Reply to this Comment

@Michael,

Ha ha ha, I'm super happy to help out :) Glad this stuff may come in handy for you!

@Neil,

Yeah, PCI is definitely a super pain. We had to do it for one of our production servers. I wasn't too involved with the process, but I know that the Remote Desktop login has to now be done over some secure connection and none of the Mac RDP clients can handle it... so in order to remote into the Windows machine, I have to boot up a Window Virtual Machine to use their RDP.... so frustrating.

@Lola,

Good question, I'm not sure.

@Jeremy,

Awesome feedback! And, unfortunately, charging hundreds of thousands per month is not a problem I have for any of my personal projects.... *yet*!! :D Also, I didn't know that any of the payment processors would offer any kind of high-volume discounts - it's good to know that PayPal will work with people on that - good tip.

Question: I see on many ecommerce sites that there are "Hacker Safe" graphics. In the past, I think we have only gotten those in conjunction with Authorize.net accounts. Do you know if Stripe-based checkout systems can get that kind of stuff? Unfortunately, I am never involved in the procurement of such certifications, so this might be a silly question.

@Joshua,

It's definitely an exciting time! It seems every day, more APIs come out that make our lives easier!

@Aaron,

That's lame about the BrainTree stuff, requiring a library. There's no ColdFusion library for Stripe.com, but the API is so dead simple, CFHTTP was sufficient. Though, maybe I'll try to whip something together for the API ;)

@Justin,

Ah, good to know! Keep us informed with overall experience.

@Murray, @Rafael,

Yeah, it seems like international support is their current weakness, from the posts I've been reading. Good luck with that!

Reply to this Comment

Very excited to have come across this post. We have been using CFXWorks product that interfaces directly with Elavon for a number of years now with no real issues, but it seems as though another new PCI compliance issue pops up every month and this would actually reduce our monthly fee expense. Definitely going to keep an eye on this one. The company appears to have been founded by PayPal people and backed by Sequoia, so it has some savvy people behind it.

Reply to this Comment

@Justin

Good to know Braintree has changed their offering. In June 2011 I asked them about CF/REST and I received this response:

We use the client libraries to ensure backwards compatibility, stability, and security for merchants as our backend gateway API evolves. We've talked about opening up the backend API down the road, but for the time being we're going to stick with client libraries in order to provide the highest level of support and stability.

In the meantime, you're welcome to experiment with integrating in any of our supported languages. Also, if you're interested, you are welcome to investigate how to load the Java client library in CF and interacting with it. This is something that CF supports, but not something we have full documentation around yet.

Reply to this Comment

@Steven,

Yeah, Stripe definitely has some big names behind it. That's gotta be a good sign; especially since it has PayPal experience poured into it.

@Aaron,

That's really strange! I wonder how a library would help ensure backwards compatibility anyway? Or, at least more than anything else? After all, if the API changes, how can the libraries (one has already downloaded and pushed to production) necessarily stay relevant? Odd response.

Reply to this Comment

Pretty cool find. I like the concept of stripe, but just a heads up. Stripe is not a bank so you don't have any guarantee on your money if they go under.

Maybe the risk isnt that big for small, occasional transactions, but I'd hate for my money to be in limbo and see a "small 12 person company" like stripe dissapear with my money!

Reply to this Comment

Ben, once again, I'm glad I haven't quit you (see your "Brokeback" post).

As you discovered, this could come in real handy.

  • nothing more than your bank routing number and account number

That caused me to tense up a bit. I might suggest you open a "Fun Money" account with a different bank, just to make sure that they don't have access to your millions of dollars you have stored at BoNY ;-)

Reply to this Comment

@Randall,

I like your suggestion about the "fun money" account. I'm glad you brought it up and to the attention of people reading this post and comments. I had a job, not too recently, but awhile back. I had become unemployed, and I took a job out of desparation, because it was a really bad time of unemployment, and I hadn't gotten my foothold in coldFusion, and some other parts of a long story...anyway, thankfully, I had set up a separate account at that time and used that account for business related to this new job I took. Anyway, the particular job turned sour, the people were not honest and not good people to work with, and before long, my bank account (the extra one I had set up) had become a place where fraudulant activity had taken place (without going into too much detail). It has screwed me up royally, and now, no matter what bank I go to, I can not set up another account. Thank goodness I had originally set that account up separately, and I still have my ONE account, but it has made me really wary of doing anything really with my bank account. I don't really like paying with checks anywhere, or anything other than cash or money orders because of my bad experience. But thankfully I have that account, or else, I would be having to stand in line and do all of my financial business at the wal-mart money center, or something if I had not kept my current bank account separate. And quite frankly, the bank I have may not have allowed the fraudulant activity...it probably would not have. I consider what happened to have been a weakness in that particular banking system (in addition to the fraudulant activity), and unfortunately now, most banks won't allow me to open an account there because of what has happened.

Reply to this Comment

Ben, Joshua mentioned it already, but www.square.com does this on Android and iOS, with a free reader.

Reply to this Comment

@Phil,

Very cool. Nothing wrong with having a couple of different projects working on the same concepts.

@Steve,

This is a valid point. And, since they only make payments every 7 days, they have a couple of days to build up some reserve of cash that may never get to you. But, I suppose this "float" is how they are able to keep costs down? Maybe they "play" with your money in the meantime to get a return on it somehow? Or is that just an insane idea? I always assumed that's what banks to make money.

@Randall,

Yeah, I know what you mean. Theoretically, with those numbers, you could turn a bar napkin into a check and start taking out money... but that's some serious fraud. I think the FBI gets involved at that point :D So, I'm trying not to be too concerned about it.... fingers crossed.

@Anna,

Holy cow, that sucks :( The good thing about the Stripe people is that its built by people who come from reputable places and is backed by serious investors. That said, fingers crossed. I'm sorry you had such a sour time, though.

@Randall,

Good link! I had no idea that ING Direct had a person-to-person payment option.

Reply to this Comment

@Ben,

I know it sucks big time! One of the worst parts of it is that in recent years, since all of this mess happened, I had to get dudes to do my ordering for me, and I would just pay them back. It really sucks having to be dependent on dudes like that.

And I know I am at least partly at fault, as well. I am just, or was just a very naive person, but I was also a very sweet person who always wanted to believe the best in people, and I used to be so extremely optimistic. I'm not saying I'm not positive anymore, just a lot more careful! I get this from my dad, because he also believes in the good of people, and I can't tell you how many times he has gotten screwed, though. One of his problems is, he doesn't always learn from it. He has been getting screwed by the same mechanic for 5 - 10 years. Probably, the only thing that is getting ready to save him is the fact that this guy is going out of business. I guess he screwed way too many people, and most people were able to get wise to it and see the bad in him.

as to your response to @Steve, that is how I always understood it...that the banks "played" with your money and that's how they were able to make money off of it. One thing that confuses me, at least in now's times, is how they are still able to do that, because it was my understanding that they were investing in stocks, etc., and with the stock market as screwy as it is these days, I don't see how they are able to make money with it. But that may be part of the story behind so many of them having to be bailed out and take bail-out money. Maybe they played with people's money and lost out on quite a bit of it that way, so now they have to be bailed.

Reply to this Comment

Ben,

I've spent some time this weekend copy/pasting your code. I learned a lot!

1. I'm getting response.SUCCESS instead of response.success in validation.done.

2. I think I'd like to use input id="creditCard" instead of input class="creditCard" because that allows me to have label for="creditCard". I think that still follows the rule of not having it submit to the form, right?

3. I separated out the JavaScript from the html. I know that you included it all in one file for demonstration purposes, but separating it out caused a challenge: the ColdFusion variables in the script. I solved that by populating divs with the values from ColdFusion and then grabbing them with $('#stripePublicKey').text() and $('#SCRIPT_NAME').text().

Reply to this Comment

Based on Ben's great kickstart, I ended up implementing Stripe into a rush project over the Thanksgiving holiday.

So far - works great. Regarding the account concerns in some earlier comments - the first transfer (for a somewhat significant amount) hit today like clockwork 7 days after the initial charges. Dashboard presentation in their web client also works well and presents an easily digestible format for viewing the charge / transfer activity.

Thanks again Ben (also dived into your CoreMVC framework for this last one).

-Cheers

Reply to this Comment

@Phillip Senn,

Do they have .net examples, do you know? You listed the others, so I was curious if you knew about that one. Thanks!

Reply to this Comment

@Phillip,

Yeah, in order to maintain the original case, you have to use bracket notation rather than dot notation; otherwise, as you saw, it all goes to uppercase. Apparently this functionality was added to the language in order to stick to XML case sensitivity.

As far as the ID vs. Class, you are correct in that ID lends nicely to label interaction. Though, I think neither will be submitted to the server without a Name attribute.

I'd love to share my examples, but I fear that they are not nearly extensive enough :) The API is rather large.

@Jason,

Awesome my man! Glad to hear that, in production, this stuff is running as expected. I'm dying to try this on a personal project but haven't gotten around to it yet. Now, I'm all excited to get it going!

Reply to this Comment

lol, speaking of security and money transactions, I was on a site today, and on that site, it said the following:

This is the fastest, easiest, and probably the least expensive way of making a purchase. All you need to do is go to your bank, and ask them to set up your account for online banking... it only takes them about five minutes, or you can do it yourself online. Then it's as simple as logging on to your banks website, clicking send money via email money transfer, provide a skill testing questions which you would send me the answer to for security... I then receive the email and click on deposit

oh, is that all? Really? I would be really scared to do something like that with the bank, with the one account I have. lol. But, I would be really happy if anyone out there wanted to send me a deposit that way. Any takers?

@Ben, I ask about the .net not because I am going to get to do anything with this any time soon, but I do know someone who could probably use that. I don't program in .net. I only do the ColdFusion, php, and soon maybe java at work. But it would be interesting to get to use. I'm hoping my friend will get it set up and get to use it, and he is using the .net.

Reply to this Comment

I have a friend who did authorize.net for a client who said there was something like 4 or more other fees applied to the authorize.net account, but did not remember the average total transaction fee. But other than that, he said that what was listed on the site was pretty straight forward and accurate. I know his client wanted a deal, and they saw the best deal with authorize.net.

I'm not asking this for myself, but will this work for something like a member's paying site...I guess like an adult site? Or I guess maybe something like a dating site or something like that? Also, are there any other restrictions, like if it is of an adult nature. I'm not asking this for myself. A friend is dating a girl who has done stuff in the adult industry and said they wanted help with setting something up. I told him I didn't care to have any hands-on participation with it, but I would ask around.

Reply to this Comment

@Anna,

https://stripe.com/terms#section_b

as with most processors, they usually have restrictions like gambling sites, porn, tabacco, alcohol, etc.....

You need to go to an offshore, high risk processor for something like that. I've heard (and I know it sounds crazy) that some of these off shore guys take 10-25% of the transaction! Its like the Mafia almost!

Reply to this Comment

Does anyone know why some merchants charge a PCI insurance fee? What does this insurance cover and is it necessary?

Thank you

Reply to this Comment

@Ryan - The website below has some good information on the topic of fees:

http://www.merchantmaverick.com/pci-compliance/pci-compliance-fees/

In short, if it's listed as a "non-compliance" fee then you need to submit "proof" that you're compliant (usually in the form of a completed questionnaire and a clean quarterly scan report) and they will usually take that fee off. If it listed as a "PCI insurance" fee then that generally means that the processor has an insurance policy in place that would (in theory) cover any damages incurred in the event of a data breach which protects the processor and the merchant. As the article points out, the insurer may decline a claim and you may still be left to foot the bill for a breach, so I would recommend contacting your processor for details about liability if a breach occurs.

Reply to this Comment

Anybody working on a iOS / Android App to "swipe" physical cards - which would process the code and "charge" the card?

Thanks for your help!

Reply to this Comment

@Justin, thanks! I have one of them. I thought this thread was about Stripe.com. I must have not been clear enough in my question...

Is anybody working on an app, which utilizes a magnetic card reader, to actually "swipe" a CC, which will interface with Stripe.com to process transactions.

Many companies offer free magnetic card readers, or you can buy online; Squareup.com (Square) is even working on a more secure version. So, anyone can get one. But I would like to "swipe a card" and have it interface with this code (& an app) automatically.

Just thought it'd be neat.

Thanks!

Reply to this Comment

Interesting idea, Chris. Basically roll your own Square using Stripe.

If you search for "iphone credit card reader" in google shopping, you'll see there's a bunch of them.

My guess is that, like regular magnetic stripe readers and barcode scanners, it's just a keyboard interface.

Technically it seems very possible. Big hornet's nest is security/PCI compliance.

Reply to this Comment

Sorry to resurrect and old thread, but I just wanted to provide some feedback on our experience with Stripe.com. After seeing this post, I decided to take a chance on Stripe.com to process payments for online ticket orders for my son's youth baseball league car raffle. Setup was a breeze, integrating the JavaScript and CFML were equally as simple and the transactions have all been handled with ease. The support has been excellent and payments are happening as expected. I think I may need to change the payment processor for my primary business to Stripe.com. Thanks to Ben for bringing them to my attention.

Reply to this Comment

I was wondering if this is something I can use for my Etsy store? Thanking you in advance for your time.

Reply to this Comment

@nina,

If I remember correctly, eBay only allows sellers to accept payments through PayPal these days, so an outside payment solution like this probably wouldn't be applicable to an eBay store.

Reply to this Comment

@nina,

So of course as soon as I hit submit I realized that I misread your question. I am not too familiar with Etsy, but if they allow you to process your own payments then something like Stripe should work as long as the items you're selling aren't prohibited by Stripe's terms of service.

Reply to this Comment

1)Is this something that has to be implemented by someone well versed on programming? I have no experience-should I hire someone?

2)Is there a way to restrict my orders to US customers? I know only US merchants can work with Stripe. But they do take international payments as well.

Would truly appreciate your input.

Reply to this Comment

@Sam,

1) If you are not a programmer, you may want to hire one to implement stripe. That said, it is not too difficult to get up and running, so you may want to give it a try first before you throw down some cash on a developer.

2) Payments can be accepted from anyone - you just have to be in the US to join stripe

Reply to this Comment

Wow I must say I am blow away at how easy and fast it is to set up stripe. It is way better than paypal and is less expensive than authorize.net in that you dont have to pay those extraneous merchant fees.

Reply to this Comment

Thanks for this post Ben! Your way of coding made much more sense to me than some of the other projects I saw out there, thanks for keeping it simple.

Reply to this Comment

The biggest issue with PayPal is not a technical one. It is a business security one. PayPal requires that you "validate" with a bank account!

Nobody in their right mind should hand over bank acount information and authorization to withdraw from that account. This entirley bypasses the safety of using credit cards, both for the purchaser and for the merchant.

Unless PayPal has changed this policy, they should not be a go-to for credit card acceptance.

For merchants, a bank account is obviously required for fund deposits. The only sane way to work with PayPal is to set up a separate account with basically no money in it. Then transfer any received payments out of that account immediately. This prevents PayPal from making a withdrawal (which they have been known to do) and tying up your money. This goes for any service that required direct account access authorization.

Reply to this Comment

Trying out your json/dom version, and have copied as it is into CF10... but am getting a response "Received unknown parameter: amount" error.

Could this be due to a Stripe update? Your tut is about 2 years old as of today. Tx, Tami

Reply to this Comment

@Tami,

I'm currently using Stripe and I just double-checked and I am using a parameter called, "amount". It's supposed to be in cents, so I basically have amount = (amount * 100). Could that be your issue? Make sure you don't have any decimal places (since the value is a whole pennies).

Reply to this Comment

Hmmm, don't think so. There is a formfield 'amount' that is donation*100. but no explicit reference to amount in the dom.form.submit catcher function. (looking at lines 415-450ish).

I did a copy/paste from your code above and get this... (except for replacing your jquery link w/ the newer version)

I got it here: http://hhwdsandbox.com/lucky/teststripe.cfm, but no worries. I did get it to work using straight .js. Just like your approach better.

And thanks for the awesome photo :)

Reply to this Comment

I tried your code as is, except inputted the two keys. But I have gotten "something went wrong with your credit card information."

Please advise.

Much obliged and thank you for sharing that with everyone.

Donald

Reply to this Comment

BrainTree still hasn't setup an CF option yet so it looks like using the Java API will be necessary - except I don't know how to do that. Any volunteers to walk me through it? :D

Reply to this Comment

@Tom, funny timing. Just today Daryl on the cfpayment group said he will be giving the CF-wrapper-for-the-Java-library code a go in the next week or two. See here for details and to get in on it: groups.google.com/d/topic/cfpayment/0CyzBVGRgTc/discussion (link broken as site won't seem to let me post with it whole?)

Reply to this Comment

I don't know a thing about code, other than some html. Paypal makes it easy with 'create a button' for us code dummies. Copy and paste and viola, it's done. Anyone here that can do this for me? I'm trying to raise funds for a friend in medical expenses need. 1 raffle ticket for $10, 3 for $25 or 15 for $100. So I'd need three buttons. I know I'd have to stick my API key in one line. I'd like to retrieve their name and email addy for the records. Currently it's set up for Paypal but I'm having a little problem with them at the moment...so any help would be GREATLY appreciated.

Thank you,
Donna

Reply to this Comment

Would be interested in your comparisson now in 2014 about these two, they seem to be almost identical, other than the extra currencies on base features now..

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.