0
votes

I am working Paypal checkout php sdk. I follow the document from here https://github.com/paypal/Checkout-PHP-SDK

First I create an order

$env = new SandboxEnvironment($clientId, $secretKey);

$client = new PayPalHttpClient($env);

$request = new OrdersCreateRequest();

$request->prefer('return=representation');

$request->body = buildOrder($order);

//buildOrder has this param:
/*
"application_context" => [
     "return_url" => 'domain/paypal/return.php',
     "cancel_url" => 'domain/paypal/cancel.php'
 ]
*/

//request body
$body = array (
  'intent' => 'CAPTURE',
  'purchase_units' => 
  array (
    0 => 
    array (
      'reference_id' => 9,
      'amount' => 
      array (
        'value' => 125.63,
        'currency_code' => 'USD',
        'breakdown' => 
        array (
          'item_total' => 
          array (
            'currency_code' => 'USD',
            'value' => 125.63,
          ),
        ),
      ),
      'items' => 
      array (
        0 => 
        array (
          'name' => 'Demo 46',
          'description' => NULL,
          'sku' => NULL,
          'unit_amount' => 
          array (
            'currency_code' => 'USD',
            'value' => 98.0,
          ),
          'quantity' => '1',
        ),
        1 => 
        array (
          'name' => 'Demo 28',
          'description' => NULL,
          'sku' => NULL,
          'unit_amount' => 
          array (
            'currency_code' => 'USD',
            'value' => 12.22,
          ),
          'quantity' => '1',
        ),
        2 => 
        array (
          'name' => 'Addon 33',
          'description' => NULL,
          'sku' => NULL,
          'unit_amount' => 
          array (
            'currency_code' => 'USD',
            'value' => 15.41,
          ),
          'quantity' => '1',
        ),
      ),
    ),
  ),
  'application_context' => 
  array (
    'return_url' => 'http://domain.test/paypal/return',
    'cancel_url' => 'http://domain.test/paypal/canceled',
  ),
)
$response = $client->execute($request);

Create Order response:

{"statusCode":201,"result":{"id":"10M47599SM3059709","intent":"CAPTURE","status":"CREATED","purchase_units":[{"reference_id":"9","amount":{"currency_code":"USD","value":"125.63","breakdown":{"item_total":{"currency_code":"USD","value":"125.63"}}},"payee":{"email_address":"[email protected]","merchant_id":"XEH8BEAE3FXPW"},"items":[{"name":"Demo 46","unit_amount":{"currency_code":"USD","value":"98.00"},"quantity":"1"},{"name":"Demo 28","unit_amount":{"currency_code":"USD","value":"12.22"},"quantity":"1"},{"name":"Addon 33","unit_amount":{"currency_code":"USD","value":"15.41"},"quantity":"1"}]}],"create_time":"2021-09-30T22:59:31Z","links":[{"href":"https:\/\/api.sandbox.paypal.com\/v2\/checkout\/orders\/10M47599SM3059709","rel":"self","method":"GET"},{"href":"https:\/\/www.sandbox.paypal.com\/checkoutnow?token=10M47599SM3059709","rel":"approve","method":"GET"},{"href":"https:\/\/api.sandbox.paypal.com\/v2\/checkout\/orders\/10M47599SM3059709","rel":"update","method":"PATCH"},{"href":"https:\/\/api.sandbox.paypal.com\/v2\/checkout\/orders\/10M47599SM3059709\/capture","rel":"capture","method":"POST"}]},"headers":{"":"","Content-Type":"application\/json","Content-Length":"1085","Connection":"keep-alive","Date":"Thu, 30 Sep 2021 22","Application_id":"APP-80W284485P519543T","Cache-Control":"max-age=0, no-cache, no-store, must-revalidate","Caller_acct_num":"XEH8BEAE3FXPW","Paypal-Debug-Id":"95be3b11c12e7","Strict-Transport-Security":"max-age=31536000; includeSubDomains"}}

Then I can get orderID, I store it in session. Next I redirect buyer to approve url from Paypal response. enter image description here

Next, buyer makes payment and Paypal drives buyer to my return url above.

In return.php I capture order by this piece of code

$env = new SandboxEnvironment($clientId, $secretKey);

$client = new PayPalHttpClient($env);

//$orderId can get from session or from `token` param in return url
$request = new OrdersCaptureRequest($orderId);

$request->prefer('return=representation');


$response = $client->execute($request);

New response from OrdersCaptureRequest:

{"name":"NOT_AUTHORIZED","details":[{"issue":"PERMISSION_DENIED","description":"You do not have permission to access or perform operations on this resource."}],"message":"Authorization failed due to insufficient permissions.","debug_id":"e8021203038f1","links":[{"href":"https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED","rel":"information_link"}]} {"exception":"[object] (PayPalHttp\\HttpException(code: 0): {\"name\":\"NOT_AUTHORIZED\",\"details\":[{\"issue\":\"PERMISSION_DENIED\",\"description\":\"You do not have permission to access or perform operations on this resource.\"}],\"message\":\"Authorization failed due to insufficient permissions.\",\"debug_id\":\"e8021203038f1\",\"links\":[{\"href\":\"https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED\",\"rel\":\"information_link\"}]}

The response I have is (old):

{"name":"NOT_AUTHORIZED","details":[{"issue":"PERMISSION_DENIED","description":"You do not have permission to access or perform operations on this resource."}],"message":"Authorization failed due to insufficient permissions.","debug_id":"ff1bfd34831cb","links":[{"href":"https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED","rel":"information_link"}]} {"exception":"[object] (PayPalHttp\\HttpException(code: 0): {\"name\":\"NOT_AUTHORIZED\",\"details\":[{\"issue\":\"PERMISSION_DENIED\",\"description\":\"You do not have permission to access or perform operations on this resource.\"}],\"message\":\"Authorization failed due to insufficient permissions.\",\"debug_id\":\"ff1bfd34831cb\",\"links\":[{\"href\":\"https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED\",\"rel\":\"information_link\"}]}

Then I came with solution to combine between client and server

  1. I embed the Paypal checkout button
  2. Create order from server
  3. Handle approval from js client
  4. Capture order by Paypal js function. And Paypal responses with COMPLETED status.
<script
            src="https://www.paypal.com/sdk/js?client-id=[SANDBOX_CLIENT_ID]"></script>
<script>
paypal.Buttons({
            createOrder: function(data, actions){
                return fetch('create-order.php', {
                    method: 'post',
                    headers: {
                        'content-type': 'application/json'
                    },
                }).then(function(res) {

                    return res.json();
                }).then(function(data) {

                    return data.token;
                });
            },
            onApprove: function(data, actions){
                return actions.order.capture().then(function(details){
                   console.log(details);
                });
            }
});
</script>

Even I tried to send orderID from onApprove event of Paypal js to my server for capturing order, the same issue with PERMISSION-DENIED happens.

Please help on this.

1

1 Answers

0
votes

Redirecting away to a rel:approve URL is for old websites. You should use the PayPal button rather than redirecting away, it's a much nicer and more modern in-context experience for the buyer, keeping your site loaded in the background/lightbox fade.

The problem you are having with capturing an order on the server side appears to be a matter of using the wrong request object:

//$orderId can get from session or from `token` param in return url
$request = new OrdersCreateRequest($orderId);

At this stage, you need an OrdersCaptureRequest instead. See the sample bundled as part of the SDK.