API Docs

Quickstart Guide | @Pay API v3

Docs > API Docs

Accepting Credit Cards

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.


1. Include the @Pay Javascript SDK in your page

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


2. Charge a Card

Making The Sales Call

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

Handle The Sales Call

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


3. Retrieve & Process The Postback Hook

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.

Setup HTTP POST endpoint

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

Processing a Hook

Signature Verification

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.

Verifying Signature

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

Notification

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.

Top