CyberSource — It’s not that difficult after all!

Mrinmoy Das
8 min readSep 29, 2018

If you have come across this post, you might be using CyberSource as your payment gateway in the application and yes, you might be facing difficulty implementing how exactly it works. Well, I was in the very situation a few weeks ago, but after reading their entire documentation (which was really a tedious process), I was able to implement it in our very application with ease. With over 400K merchants relying on CyberSource, the gateway has a few tricks up their sleeve to fully utilise it’s power! So, let me jot down my findings in order to make it easy for you —

1️⃣ Creating an account with CyberSource —

This is the foremost step (obviously!). Create an account with CyberSource which includes, you stating them the cards that you want your customers to make payment from, what will be the order of your reference number and few other things. Once done, they will provide you with 2 things —

  1. A merchant ID, login ID and a password to access your account.
  2. 2 sets of endpoints (rather be called APIs) — one, for testing purpose and the other for the real transaction. While developing your application (which needs to tested and re-tested before it goes into production), you can use the testing API and once it’s live, you can use the real one.

Now, once you login to your portal, under Profile, you’ll see something like ‘Customer Response’. Tapping on this leads to a page that takes an URL of the page you want to redirect once the payment is successful. Now don’t get carried away. You cannot put the link to your application page as it will not work — “WHY? You said CyberSource is supposed to be simple!”. Let me explain this in details.

2️⃣Redirection using CyberSource —

Now, the initial thing that needs to kept in mind is that, CyberSource server (or Engine, as they call it) emits a POST request to the endpoint you’ve mentioned in their portal. Now you cannot directly use a POST call to the route of your application (or any other website as such).

To understand this, you must realise that when we type an URL on a browser, what does it do? It emits a GET call on that URL and fetches the website on to your browser. However, if you change the call type to POST, what will happen? Does it work? Let’s try this —

You might have used an application called POSTMAN to test your APIs while building your application. Name the URL in POSTMAN to ‘google.com’ and change the request type to ‘POST’. What does it show? Instead of returning the HTML of the Google page, it returns an error stating the following —

<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content=”initial-scale=1, minimum-scale=1, width=device-width”>
<title>Error 405 (Method Not Allowed)!!1</title>
<style>
*{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
</style>
<a href=//www.google.com/>
<span id=logo aria-label=Google></span>
</a>
<p>
<b>405.</b>
<ins>That’s an error.</ins>
<p>The request method
<code>POST</code> is inappropriate for the URL
<code>/</code>.
<ins>That’s all we know.</ins>

It returns a 405 error! “THE REQUEST METHOD POST IS INAPPROPRIATE FOR THE URL”. POST calls to any website or their routes are disabled by default to prevent unknown users from injection code (often disruptive) into their server. That’s how security over the internet is maintained! Hence, if you attempt to give your application route in your CyberSource endpoint, it will not work!

What is the solution to this?

— “This post is supposed to show how easy CyberSource is, but it mentions more problems!”

The simple solution to this is to pass the POST call from CyberSource through your own server and capture certain fields that it provides. So, you need to create an API to accept the data sent back from CyberSource and store it and even in their (very long) documentation of their APIs, they prefer their merchants to store each and every transaction in their database.

For guidance, CyberSource does not return JSON! It takes and returns FormData. You can have a simple Google search on how to accept form data to be clear more on this. No matter what technology you’re using to build you API server, there are provision for FormData in it.

CyberSource returns all data that is sent to their engine. However, our team decided not to capture personal information (as it is not safe, again, we had no use for it) and capture the transaction ID, transaction status etc.

We used a parameter ‘cybersource_status’ to figure out whether the transaction was successful or not. For example, if it is successful, it will return ‘ACCEPT’, if not ‘ERROR’. On being ‘REJECT’ed, you’ll be notified in some other way which will be mentioned in the next points.

3️⃣How to reflect CyberSource redirection to the front-end —

When front-end makes a call to CyberSource (which will be explained further into this article), on successful attempt, you’ll realise that the page is being redirected to the API you have created for save the response of the CyberSource response. And the browser turned white even on successful transaction. You’ll notice that the URL the page is redirected to, is the same as that you’ve created to save the response. Now what?

We were using React as our application’s front-end technology, and we decided that we’ll stop the navigation, fetch the status using another API and then will redirect to the desired route. The plan seemed simple, isn’t it? But it didn’t work! Why? In order to stop navigation we’re using a common JavaScript function, window.stop(). Even though it worked in Chrome, it didn’t in Firefox. Adding to the issues, the redirection was sometimes so quick, even before we can stop the navigation, it has already navigated! That was a point we literally thought that using CyberSource has been a mistake!

After much thinking and discussion, we came up with a plan! (Yeah, that was it!) We decided to go for double redirection. So the plan was, when CyberSource returns a response, instead of just storing the data into the database and allowing the browser to be navigated to the POST API, we’ll return a redirection. A redirection to the page we want our application to go on successful transaction and on failure.

We’re using Java Spring Boot as our back-end API server and after a little searching, we found out that there was redirection using Spring Boot. So, on the very API that stores the data into the database, we responded with a redirection! And it worked flawlessly!

As of now, we have also implemented a count of attempts of unsuccessful transaction into the same API server based on the unique visitors we have for our application and on 3 failed attempts, we navigate the user to a ‘Failure Page’.

4️⃣What about the front-end? —

The initial point that needs to kept in mind while implementing CyberSource is that, it only accept’s FormData. Any data type other than that will lead to a failed transaction. The following in an example of how the form should look like —

<form id=”payment_confirmation” className=”col-md-12" action=”URL provided by CyberSource” method=”post”>
<input type=”text” id=”unsigned_field_names” name=”unsigned_field_names” value=”card_type,card_number,card_expiry_date” />
<input type=”text” id=”amount” name=”amount” />
<input type=”text” id=”bill_to_address_postal_code” name=”bill_to_address_postal_code” />
<input type=”text” id=”bill_to_address_state” name=”bill_to_address_state” />
<input type=”text” id=”transaction_uuid” name=”transaction_uuid” />
<input type=”text” id=”signed_field_names” name=”signed_field_names” value=”access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency,payment_method,bill_to_forename,bill_to_surname,bill_to_email,bill_to_phone,bill_to_address_line1,bill_to_address_city,bill_to_address_state,bill_to_address_country,bill_to_address_postal_code” />
<input type=”text” id=”locale” name=”locale” value=”en-US” />
<input type=”text” id=”transaction_type” name=”transaction_type” value=”create_payment_token” />
<input type=”text” id=”bill_to_email” name=”bill_to_email” />
<input type=”text” id=”reference_number” name=”reference_number” />
<input type=”text” id=”bill_to_address_country” name=”bill_to_address_country” />
<input type=”text” id=”bill_to_surname” name=”bill_to_surname” />
<input type=”text” id=”bill_to_address_line1" name=”bill_to_address_line1" />
<input type=”text” id=”profile_id” name=”profile_id” value=”Here goes your profile ID” />
<input type=”text” id=”access_key” name=”access_key” value=”Here goes your access key” />
<input type=”text” id=”bill_to_phone” name=”bill_to_phone” />
<input type=”text” id=”bill_to_address_city” name=”bill_to_address_city” />
<input type=”text” id=”currency” name=”currency” value=”USD” />
<input type=”text” id=”bill_to_forename” name=”bill_to_forename” />
<input type=”text” id=”signed_date_time” name=”signed_date_time” />
<input type=”text” id=”payment_method” name=”payment_method” value=”card” />
<input type=”text” id=”signature” name=”signature” />
<fieldset>
<div id=”UnsignedDataSection” class=””>
<input type=”text” id=”card_type” name=”card_type” value=”Here goes your card type”/>
<input type=”text” id=”card_number” name=”card_number” value=”Here goes your card number”/>
<input type=”text” id=”card_expiry_date” name=”card_expiry_date” value=”Here goes your card expiry date”/>
</div>
</fieldset>
<input type=”submit” id=”submit” className=”button_click_cs” value=”Confirm “ />
</form>

(Please copy paste in an editor to understand it better!)

I have many posts over the internet claiming that they see the following when they make an attempt to make a transaction —

By the time you can contact CyberSource and get a response for it, your need will dilute. Let me explain why this occurs —

Now, CyberSource doesn’t have any idea about what fields you are sending. The form contains 2 sections —

● Signed Data Section, and
● Unsigned Data Section

Signed Data Section contains all the fields regarding where the transaction is being made. If your client is USA based, the currency, the address etc will all be that of USA.

Unsigned Data Section Contains details about the card number, expiry date and card type.

CyberSource doesn’t keep track of what fields are your sending to them. And hence, you need to mention them before making a call to CyberSource.

If you see my example above, you’ll see inside the value of input field of singed data section, I have mentioned all the input tags name under it.
value=”access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency,payment_method,bill_to_forename,bill_to_surname,bill_to_email,bill_to_phone,bill_to_address_line1,bill_to_address_city,bill_to_address_state,bill_to_address_country,bill_to_address_postal_code”
The same goes for unsigned data section.

Now, when you create different input fields to pass value to their server, make sure, you provide those fields with the same name which you are providing as the value of signed and unsigned data fields. If not done so, CyberSource will not even accept the request to their server.

For example, for access_key, their should be a field who’s name is access_key and so on.

It took me sometime to understand this, but it was clearly mentioned in their documentation.

As mentioned earlier, we are using React to drive our front-end and what we have done is, we have created a separate form (which looks cooler!) and have another component having the CyberSource call. When the user submits the form in one, we are passing the value of card number, expiry date etc as props to the another component. You just been to submit the form in the second component only when the component have received the props correctly. (Use setTimeout if required to submit the second form)

5️⃣Testing your implementation —

It seems like a long time since you’ve started reading this article, but the wait finally will pay off! CyberSource as mentioned earlier, will provide you will 2 endpoints to hit. If you’re testing, use their testing API. Along with their API comes a few sample card number and expiry date. Use those to test your application and payment.

NOTE — Do not use random data! CyberSource engine is smart enough to understand which cards exist and which cards don’t, even in their testing endpoint! Always use valid data.

Once done, you can make payment flawlessly using CyberSource!

Before I forget about the card type number — Here is a link that contains details about what card type number must be sent for which card.

CyberSource Card Types

It’s going to be very long if-else isn’t it?

So, this concludes how you should be using CyberSource for your payment. It’s fast, it’s secure and it does help in solving the issue of creating a complex payment gateway for your system.

Drop a clap if you find the article to be helpful! Forty claps would do wonders.

--

--