Related
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":"sb-kpo1v7959755#business.example.com","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 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.
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.
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.
When using the new gocardless api examples I can list customers so I'm assuming that I have composer installed correctly but when I try the example for creating a subscription (as listed below) I get http error 500 does anybody know what I may be doing wrong?
<?php
require 'vendor/autoload.php';
$client = new \GoCardlessPro\Client(array(
'access_token' => 'my_sandbox_access_token_goes_here',
'environment' => \GoCardlessPro\Environment::SANDBOX
));
$client->subscriptions()->create([
"params" => ["amount" => 25,
"currency" => "GBP",
"name" => "Monthly test",
"interval_unit" => "monthly",
"day_of_month" => 1,
"metadata" => ["order_no" => "test1"],
"links" => ["mandate" => "MA125"]]
]);
?>
Thanks
I am currently building a e-mail client (inbound and outbound sending) using Mandrill as the e-mail sending / inbound service and Laravel 3.x.
In order to send messages, I am using the HTTPful bundle with the Mandrill using the following code in my mail/compose POST method.
$url = 'https://mandrillapp.com/api/1.0/messages/send.json';
$data = array(
'key' => '{removedAPIkey}',
'message' => array (
'to' => array( array( "email" => $_to ) ),
'from_name' => Auth::user()->name,
'from_email' => Auth::user()->email,
'subject' => $_subject,
'html' => $_body
),
'async' => true
);
$request = Httpful::post($url)->sendsJson()->body($data)->send();
Link to better formatted code above: http://paste.laravel.com/m79
Now as far as I can tell from the API log, the request is correctly made (with the expected JSON) and a response of the following format is sent back:
[
{
"email": "test#test.com",
"status": "queued",
"_id": "longmessageID"
}
]
However, what I am trying to do is access the response from the request (specifically the _id attribute), which is in JSON. Now as far as I'm aware, the HTTPful class should do this automatically (using json_decode()). However, accessing:
$request->_id;
is not working and I'm not entirely sure how to get this data out (it is required so I can record this for soft-bounce, hard-bounce and rejection messages for postmaster-like functionality)
Any assistance would be appreciated.
Edit
Using the following code, results in the mail being sent but an error returned:
$url = 'https://mandrillapp.com/api/1.0/messages/send.json';
$data = array(
'key' => '{removedAPIkey}',
'message' => array (
'to' => array( array( "email" => $_to ) ),
'from_name' => Auth::user()->name,
'from_email' => Auth::user()->email,
'subject' => $_subject,
'html' => $_body
),
'async' => true
);
$request = Httpful::post($url)->sendsJson()->body($data)->send();
if ( $request[0]->status == "queued" ) {
$success = true;
}
Results in an exception being thrown: Cannot use object of type Httpful\Response as array
I must say, a huge thanks to Aiias for his assistance. I managed to fix this myself (I must have spent hours looking at this). For anyone who wants to know, the HTTPful bundle has a body array, where the response is kept. Therefore, the code below works:
$url = 'https://mandrillapp.com/api/1.0/messages/send.json';
$data = array(
'key' => '{removedAPIkey}',
'message' => array (
'to' => array( array( "email" => $_to ) ),
'from_name' => Auth::user()->name,
'from_email' => Auth::user()->email,
'subject' => $_subject,
'html' => $_body
),
'async' => true
);
$request = Httpful::post($url)->sendsJson()->body($data)->send();
if ( $request->body[0]->status == "queued" ) {
$success = true;
}
Again, huge thanks to Aiias for clearing some major confusion up for me!
This is my first post in this forum.
I'm trying to develop all the payments to Adyen using the WS, instead of the skin/post method that I was using until now.
So, I downloaded from their example, this code (I'm posting also the class method to connect by WS)
function Adyen($login, $password, $host ="live", $debug=FALSE ) {
$this->DEBUG = $debug;
$this->client = new SoapClient( "https://pal-$host.adyen.com/pal/Payment.wsdl",
array(
"login" => $login,
"password" => $password,
'trace' => 1,
'soap_version' => SOAP_1_1,
'style' => SOAP_DOCUMENT,
'encoding' => SOAP_LITERAL
)
);
}
function authorise( $amount,$currencyCode,$cardHolder,$cardNumber,$expm,$expy,$cvc,$reference) {
global $merchantAccount;
$response = $this->client->authorise( array(
"paymentRequest" => array
(
"amount" => array (
"value" => $amount,
"currency" => $currencyCode),
"card" => array (
"cvc" => $cvc,
"expiryMonth" => $expm,
"expiryYear" => $expy,
"holderName" => $cardHolder,
"number" => $cardNumber,
),
"merchantAccount" => $merchantAccount,
"reference" => $reference,
)
)
);
When I'm executing this code, it returns this error
#!/usr/bin/php SOAP Error on test SoapFault Object ( [message:protected] => security 010 Not allowed [string:Exception:private] =>
Do you have any suggestions to solve it?
Best Regards.
Edit:
It's too strange, cause with the same method, but with different parameters (In case of the recurring payment, I haven't this error. This the case runs
$response = $this->client->authorise(
array(
"paymentRequest" =>
array(
"amount" => array("value" => $amount,
"currency" => $currencyCode),
"merchantAccount" => $merchantAccount,
"reference" => $reference,
"shopperReference" => $reference",
"shopperEmail" => $email,
"recurring" => array("contract" => "RECURRING"),
"selectedRecurringDetailReference" => "LATEST",
"shopperInteraction" => "ContAuth"
)
)
);
Had the same question, here is the support answer:
You are trying to make an API payment. Please be aware that there are a few downsides using the direct integration API.
Most important, due to strict industry regulations, the Merchant is required to be PCI DSS (Payment Card Industry Data Security Standard) compliant at Level 1 or 2. The PCI DSS certification process requires a big contribution from you in both time and money.
http://en.wikipedia.org/wiki/PCI_DSS
The direct integration also offers a limited set of payment methods and might require you to implement features like the 3D secure mechanism.
The normal integration works as follow:
Redirect the shopper from your website to our Hosted Payment Pages.
Shopper can choose several payment methods and makes the payment.
Shopper is redirected back to your website and we pass back a result code of the payment.
We sent also a notification via SOAP or HTTP Post.
From Adyen documentation
010 Not allowed You are not allowed to perform this action
I think you should send email to their support. May be your account not ready for use.
You need to add your ip in the ca admin area for the user 'Edit Allowed User IP Range'.
I think in this code you have mistakenly put extra double quotes( "shopperReference" => $reference",).
$response = $this->client->authorise(
array(
"paymentRequest" =>
array(
"amount" => array("value" => $amount,
"currency" => $currencyCode),
"merchantAccount" => $merchantAccount,
"reference" => $reference,
"shopperReference" => $reference",
"shopperEmail" => $email,
"recurring" => array("contract" => "RECURRING"),
"selectedRecurringDetailReference" => "LATEST",
"shopperInteraction" => "ContAuth"
)
)
);
My postback php for google wallet in-app payments looks like this:
<?php
$payload = array(
"iss" => $sellerIdentifier,
"aud" => "Google",
"typ" => "google/payments/inapp/item/v1",
"exp" => time() + 3600,
"iat" => time(),
"request" => array (
"name" => "pizza ",
"description" => "yum yum",
"price" => "10.50",
"currencyCode" => "USD",
"sellerData" => "",
)
);
$testToken = JWT::encode($payload, $sellerSecret);
?>
I have two questions:
1.
why do I see this error?... Uh oh. There was a problem. We couldn't complete your purchase because of a technical issue. Details of the problem below:Unfortunately, we could not confirm your purchase with the merchant's server. Your order has been canceled. Please contact the merchant if this problem continues.
2.
How can this work if I have multiple items for sale? the example php above lets you buy a 'pizza for $10.50' how can I add another item like a 'hotdog for $2.99'?
ps: I have studied the following documentation:
https://developers.google.com/in-app-payments/docs/tutorial#4
https://developers.google.com/in-app-payments/docs/jsreference#jwt
https://developers.google.com/in-app-payments/docs/postback
Thank you for your time.
//update!
postback.php:
require_once 'JWT.php';
JWT.php:
$json = json_encode($input, JSON_UNESCAPED_SLASHES);
Uh oh. There was a problem.
We couldn't complete your purchase because of a technical issue.
Details of the problem below:
Unfortunately, we could not confirm your purchase with the merchant's
server. Your order has been canceled. Please contact the merchant if
this problem continues.
You're supposed to decode the raw encoded jwt data sent to your postback.php.
In bare minimum your postback.php should look something like below (assuming your postback.php is hosted on apache server). Hope this helps
<?php
require_once(dirname(__FILE__) . "JWT.php");
$response = isset($HTTP_RAW_POST_DATA) ?
$HTTP_RAW_POST_DATA : file_get_contents("php://input");
$response = substr_replace($response, "", 0, 4); //remove "jwt=" from raw http data
$response = JWT::decode($response, "your secret key here");
print_r($response->response);
?>
is your postback.php accessible without a .htaccess password and username? I had that for a while - drove me nuts... until i figured realized that my postback.php was password protected -.-
to make a hotdog additionally do this:
<?php
$cake_payload = array(
"iss" => $sellerIdentifier,
"aud" => "Google",
"typ" => "google/payments/inapp/item/v1",
"exp" => time() + 3600,
"iat" => time(),
"request" => array (
"name" => "cake",
"description" => "yum yum",
"price" => "10.50",
"currencyCode" => "USD",
"sellerData" => "",
)
);
$hotdog_payload = array(
"iss" => $sellerIdentifier,
"aud" => "Google",
"typ" => "google/payments/inapp/item/v1",
"exp" => time() + 3600,
"iat" => time(),
"request" => array (
"name" => "hotdog",
"description" => "yum yum",
"price" => "5.99",
"currencyCode" => "USD",
"sellerData" => "",
)
);
$cake_token = JWT::encode($cake_payload, $sellerSecret);
$hotdog_token = JWT::encode($hotdog_payload, $sellerSecret);
?>
pass both to a separate purchase() function in javascript (so purchase_hotdog() and purchase_cake()
Your example worked perfectly #Pawan. Thanks. The only change I needed was on the path to JWT.php.
I now use
require_once(dirname(FILE) . "/lib/JWT.php");
Paul