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.
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
- I embed the Paypal checkout button
- Create order from server
- Handle approval from js client
- Capture order by Paypal js function.
And Paypal responses withCOMPLETED
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
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:
At this stage, you need an OrdersCaptureRequest instead. See the sample bundled as part of the SDK.
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.