This document will guide you through the process of charging a user’s registered credit card. If you haven’t already, you may want to review the Registering Credit Cards Guide first.
To include the Javascript SDK in your web application, you will want to include the following 3 script tags:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script type="text/javascript" src="https://dashboard.atpay.com/sdk/v3.js"></script> <script type="text/javascript"> $(function(){ atpay.config({ merchant_id: YOUR_MERCHANT_ID # Make sure to include your Merchant ID if you registered for a Sandbox account }); }); </script>
Copy - Expand
For additional detailed information on configuring the @Pay Javascript SDK, please visit our Javascript SDK Documentation
Calling atpay.sale
with an amount, a callback, and an object with the @Pay card token returned from the registration call (ATPAY_TOKEN
) will trigger a transaction:
atpay.sale(55.0, saleValidator, { card: ATPAY_TOKEN, referrer_context: "ref-code-1" })
Copy - Expand
The @Pay Client requires you to write a callback function for this purpose.
function saleValidator(response){ if(response.error) { alert(response.error); } else { alert("Thanks for your Purchase!"); } };
Copy - Expand
It is highly advised that you not perform any action reflecting a transfer of funds until you receive a corroborating hook notification from @Pay. Without confirmation from @Pay, you are trusting the user to tell you if the purchase was successful or not. A malicious entity could take advantage of this.
As an alternative, you may send the signature returned in the javascript callback to your server and validate it without waiting for @Pay’s servers to send you a Sale hook.
Here is an example Ruby application using the Sinatra framework
module Hooks post 'hook' do body = JSON.parse request.body.read if valid_signature?(body) body['transaction']['type'].match(/fatal|error/) ? error_hook(body) : success_hook(body) else log_evil body end end private def valid_signature?(body) body['signature'] == OpenSSL::HMAC.hexdigest('sha1', PRIVATE_KEY, body['details'].to_json) end def error_hook(body) # Do something with an error end def success_hook(body) # Do something with a success end def log_evil(body) # log this nefarious behavior end end
Copy - Expand
Here is an example PHP application using the Cake PHP framework
class HooksController extends AppController { public $components = array('RequestHandler'); public function process() { $this->request->onlyAllow('Post'); $body = $this->request->input('json_decode', true); if ($this->signature_valid($body)) { $this->process_hook($body); } else { $this->set('result', 'Bad Signature!!!'); $this->set('_serialize', 'result'); } } private function signature_valid($payload) { $key = 'plBs9X+Zvr65z6iCa0oLNdAEGYZ85Dzf74Qy1yPTris='; return (hash_hmac('sha1', $payload['details'], $key) == $payload['signature']); } private function process_hook($payload) { if ($payload['error']) { // Do something with an error $this->set('result', 'Error'); $this->set('_serialize', 'result'); } else { // Do something with success $this->set('result', 'Success'); $this->set('_serialize', 'result'); } return; } }
Copy - Expand
Here is an example Java Servlet
import java.io.*; import java.util.regex.Pattern; import java.util.regex.Matcher; import javax.servlet.*; import javax.servlet.http.*; // Using json-smart for JSON parsing import net.minidev.json.*; import net.minidev.json.parser.*; // Calculate the SHA for our signature comparisons import java.security.SignatureException; import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class Hook extends HttpServlet { private static final String KEY = "plBs9X+Zvr65z6iCa0oLNdAEGYZ85Dzf74Qy1yPTris="; private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1"; private static Pattern pattern; private static Matcher matcher; private String result; public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); BufferedReader requestReader = request.getReader(); // Parse the JSON JSONObject json = (JSONObject)JSONValue.parse(new String(requestReader.readLine())); if(checkSignature(json)) { result = processHook(json, out); } else { result = "Signature Check Failed!!!"; } out.print(result); } public String processError(JSONObject body) throws IOException, ServletException { // Do something about an error return new String("Boo!"); } public String processSuccess(JSONObject body) throws IOException, ServletException { // Do something with success return new String("Yay!"); } // Check the Hook signature private Boolean checkSignature(JSONObject payload) throws IOException, ServletException { try { SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes(), HMAC_SHA1_ALGORITHM); Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); mac.init(signingKey); String details = payload.get("details").toString(); byte[] rawHmac = mac.doFinal(details.getBytes()); return(DatatypeConverter.printHexBinary(rawHmac).equals(payload.get("signature"))); } catch(Exception e) { return null; } } // Process the hook private String processHook(JSONObject payload, PrintWriter out) throws IOException, ServletException { pattern = Pattern.compile("error"); matcher = pattern.matcher(payload.get("details").toString()); if(matcher.find()) { return processError(payload); } else { return processSuccess(payload); } } }
Copy - Expand
Every hook includes a HMAC SHA1 signature consisting of your private key and the contents of details attribute in the hook. You should always verify the signature before you trust the data in the hook.
def valid_signature?(body) body['signature'] == OpenSSL::HMAC.hexdigest('sha1', PRIVATE_KEY, body['details'].to_json) end
Copy - Expand
<?php private function signature_valid($payload) { $key = 'plBs9X+Zvr65z6iCa0oLNdAEGYZ85Dzf74Qy1yPTris='; return (hash_hmac('sha1', $payload['details'], $key) == $payload['signature']); } ?>
Copy - Expand
private Boolean checkSignature(JSONObject payload) throws IOException, ServletException { try { SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes(), HMAC_SHA1_ALGORITHM); Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); mac.init(signingKey); String details = payload.get("details").toString(); byte[] rawHmac = mac.doFinal(details.getBytes()); return(DatatypeConverter.printHexBinary(rawHmac).equals(payload.get("signature"))); } catch(Exception e) { return null; } }
Copy - Expand
Once the hook has been verified you should notify your customer of the status of their transaction, at this point you should also take any appropriate fulfillment steps. @Pay can manage direct email notification of transaction success and failure with customers on your behalf if desired. However any communication outside of email or beyond the scope of transaction status must be managed by you.