skip to Main Content

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.

2

Answers


  1. 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.

    Login or Signup to reply.
  2. I just had this same situation and the problem was my access token.
    Generating an access token via /v1/oauth2/token
    and passing the
    Request Header "Authorization", "Basic " & Base64(clientID) & ":" & Base64(clientSecret)
    Works and returns an access token.
    But this token will only allow you to Create an Order not Capture it!

    You need to Base64 encode the ":" as well!
    Changing the request header to
    "Authorization", "Basic " & Base64(clientID & ":" & clientSecret)
    Creates a token that will allows capture as well.

    This took me ages to debug as the token was returning and working to create the order! I found this by checking the scope returned when creating the token.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search