Single transaction

Prepare all the data required to perform the transaction as follows.

1
2
3
4
5
6
7
8
$paypal_params = array(
    'sale'     => array(
        'amount'      => 19.99,
        'currency'    => 'EUR',
        'description' => 'Product #1'
    ),
    'back_url'  => 'http://example-page.com',
);
1
2
3
4
5
6
7
8
paypal_params = {
    'sale' => {
        'amount'      => 19.99,
        'currency'    => 'EUR',
        'description' => 'Product #1'
    },
    'back_url' => 'http://example-page.com'
}
1
2
3
4
5
6
7
8
paypal_params = {
  'sale' : {
    'amount'      : 19.99,
    'currency'    : 'EUR',
    'description' : 'Product #1'
  },
  'back_url' : 'http://example.com'
}
1
Sale sale = new Sale(19.99, "EUR", "Product #1");

Now simply perform the transaction using the paypalSale method.

You can check whether the transaction was performed successfully by calling the isSuccess method.
Retrieving the transaction ID number (or error details, if anything goes wrong) is also very simple and can be done as shown below.

If the paypalSale method was performed successfully, you can redirect the customer to the PayPal’s website, where they’ll perform the payment. Use the URL returned by the paypalSale.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try {
    $status = $client->paypalSale($paypal_params);
} catch (Exception $e) {
    // handle exceptions here
}  

if ($client->isSuccess()) {
    echo "Success, id_sale: {$status['id_sale']} \n";
} else {
    die("Error ID: {$status['error']['id_error']}, \n".
        "Error number: {$status['error']['error_number']}, \n".
        "Error description: {$status['error']['error_description']}");
}

header('Location: ' . $status['redirect_url']);
die;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
begin
    status = client.paypal_sale(paypal_params)
rescue PayLane::ClientError => e
    # handle exceptions here
end

if client.success?
    puts "Success, id_sale: #{status["id_sale"]}"
else
    puts "Error ID: #{status["error"]["id_error"]}, \n"\
         "Error number: #{status["error"]["error_number"]}, \n"\
         "Error description: #{status["error"]["error_description"]}"
end

# redirect to url in status['redirect_url']
exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
try:
    status = client.paypal_sale(paypal_params)
except Exception, e:
    # handle exceptions here

if client.is_success():
    print 'Success, id_sale: %s' % status['id_sale']
else:
    print 'Error (%s), %s - %s' % (status['error'].get('id_error'),
                                   status['error'].get('error_number'),
                                   status['error'].get('error_description'))

# redirect to url in status['redirect_url']
sys.exit()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
api.payPalSale(sale,"http://example-page.com",new Callback<RedirectSaleResult>(){

    @Override
    public void onFinish(RedirectSaleResult result) {
        WebView webview =...;
        webview.loadUrl(result.getRedirectUrl());
    }

    @HandleException
    public void onProtocolError(ProtocolException e) {
        // invoke if not success
        // e.getCode() - error code
        // e.getMessage() - error message
    }

    @Override
    public void onError(Exception e) {
        // connection error etc.
    }
});

Ruby note:
There is no native function in Ruby to redirect to another website – you either have to use a mechanism provided by the used framework or write a function that will suit you best.
Python note:
There is no native function in Python to redirect to another website – you either have to use a mechanism provided by the used framework or write a function that will suit you best.

For Django, you can use:
1
2
from django.http import HttpResponseRedirect
HttpResponseRedirect(status['redirect_url'])
For Pylons, you can use:
1
2
from pylons.controllers.util import redirect
redirect(status['redirect_url'])

After submitting the payment on the PayPal’s website, the customer will be redirected back to your site (the back_url, to be precise). You should now verify the returned information to avoid any fraud attempts and check the transaction’s status.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$salt        = 'YOUR_HASH_SALT';
$status      = $_GET['status'];
$description = $_GET['description'];
$amount      = $_GET['amount'];
$currency    = $_GET['currency'];
$hash        = $_GET['hash'];

$id = '';
if ($status !== 'ERROR') // success, get id_sale
    $id = $_GET['id_sale'];

$calc_hash = sha1("{$salt}|{$status}|{$description}|{$amount}|{$currency}|{$id}");

// check hash salt
if ( $calc_hash !== $hash ) {
    die ("Error, wrong hash");
}

 // check transaction status
switch ($status) {
    case 'PERFORMED':
        echo "Success, transaction completed, id_sale: {$_GET['id_sale']}";
        break;
       
    default:
        die("Error, transaction declined, {$_GET['error_description']}");
        break;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Simple controller action code in Rails
# it's just an example - most of the logic should be moved to model

salt        = 'YOUR_HASH_SALT'
status      = params['status']
description = params['description']
amount      = params['amount']
currency    = params['currency']
hash        = params['hash']

id = ''
unless status == 'ERROR'
    id = params['id_sale']
else
# redirect to an index action to correct the payment + simple notice
# for Rails: redirect_to :index, :notice => "Error, transaction declined, #{description}"
end

calc_hash = Digest::SHA1.hexdigest("#{salt}|#{status}|#{description}|#{amount}|#{currency}|#{id}")

unless calc_hash == hash
# redirect to an index action to correct payment
# for Rails: redirect_to :index, :notice => "Wrong hash"
end


# check transaction status

if status = 'PERFORMED'
# redirect to some index action to correct payment and simple notice
# for rails: redirect_to :index, :notice => "Success, transaction completed, id_sale: #{id}"
else
# redirect to some index action to correct payment and simple notice
# for rails: redirect_to :index, :notice => "Transaction pending"
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# after back redirect
salt        = 'YOUR_HASH_SALT'
status      = get_request_param('status')
description = get_request_param('description')
amount      = get_request_param('amount')
currency    = get_request_param('currency')
hash        = get_request_param('hash')
id_sale     = None

# success, get id_sale
if status != 'ERROR':
    id_sale = get_request_param('id_sale')

calc_hash = hashlib.sha1(
    '|'.join([salt, status, description, amount, currency, id_sale])).hexdigest()

# check hash salt
if calc_hash != hash:
    sys.exit('Error, wrong hash')

# check transaction status
if status == 'PERFORMED':
    print 'Success, transaction completed, id_sale: %s' % id_sale
else:
    sys.exit('Error, transaction declined, %s' % \
        get_request_param('error_description'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
webview.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {

        if (url.contains(redirectUrl)) {
            try {
                Map<String, String> map = getQueryMap(new URL(url).getQuery());
                String salt = "YOUR_HASH_SALT";
                String status = map.get("status");
                String description = map.get("description");
                String amount = map.get("amount");
                String currency = map.get("currency");
                String id = map.get("id_sale");

                String calcHash = sha1(String.format("%1$s|%2$s|%3$s|%4$s|%5$s|%6$s", salt, status, description, amount, currency, id));

                // check hash salt
                if (!calcHash.equals(hash)) {
                    // Error, wrong hash
                }

                if (status.equals("PERFORMED")) {
                   String idSale=map.get("id_sale");
                    // Success, transaction completed

                } else {
                    String errorDescription=map.get("error_description");
                    // Error, transaction declined
                }

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else {
            view.loadUrl(url);
        }
        return true;
    }
});

public static Map<String, String> getQueryMap(String query) {
    String[] params = query.split("&");
    Map<String, String> map = new HashMap<String, String>();
    for (String param : params) {
        String name = param.split("=")[0];
        String value = param.split("=")[1];
        map.put(name, value);
    }
    return map;
}

private static String convertToHex(byte[] data) {
    StringBuilder buf = new StringBuilder();
    for (byte b : data) {
        int halfbyte = (b >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
            halfbyte = b & 0x0F;
        } while (two_halfs++ < 1);
    }
    return buf.toString();
}

public static String sha1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    md.update(text.getBytes("utf-8"), 0, text.length());
    byte[] sha1hash = md.digest();
    return convertToHex(sha1hash);
}
Python note:
The get_request_param function is supposed to collect data from GET params. Depending on your framework or any other toolkit, please use a proper function or write one that suits you best.

For Django, you can use:
1
param_from_get = request.GET.get('param_name')
For Pylons, you can use:
1
2
from pylons import request
param_from_get = request.GET.get('param_name')