Got Http response code 400 when Execute the paypal Payments - php

I use paypal/rest-api-sdk-php package to process paypal payment. when success payment it's working fine. but, bank decline payment we got error.
$payment = Payment::get($payment_id, $this->apiContext);
$execution = new PaymentExecution();
$execution->setPayerId($request->PayerID);
//Execute the payment
$result = $payment->execute($execution, $this->apiContext);
if ($result->getState() == 'approved') {
$paypalPaymentInfos->payment_status=1;
$paypalPaymentInfos->transaction_id=$payment_id;
$paypalPaymentInfos->save();
}

Examine the response body to determine the reason for the 400 error. It could be a normal processing decline, or it could be something else.
The rest-api-sdk-php has been deprecated for a long time and uses the old v1/payments API. Do not use it for anything.
You should integrate with the v2/checkout/orders API for payment processing : use either the Checkout-PHP-SDK (which was also recently deprecated) or direct HTTPS integration with the REST API endpoints (no PHP SDK). For payer approval use https://developer.paypal.com/demo/checkout/#/pattern/server rather than any redirect away from your site.

Related

PHP verify Paypal webhook signature

I'm having trouble trying to verify paypal webhook signatures with PHP. Using the new V2 of paypals APIs I am receiving the paypal webhook on my page.
However I can not seem to successfully validate the signature.
From the link HERE I got some sample webhook validation PHP code from paypal.
I can not get it working, I don't know where I am supposed to get bootstrap.php from in the paypal code. The paypal information seems incomplete or half baked. Paypal seems to be terrible to set-up compared to Stripe.
Has anyone got experience of validating paypal webhook signatures with PHP when using V2 of the paypal APIs ?
Well I have come to the conclusion that the Paypal developer information is rather poor, it is scatted all over the place, on multiple different pages and sites. The examples they give on the paypal developer website HERE are not a complete picture of what is required to validate a webhook signature. Stripe developer documentation is much better formatted and concise.
Installing Paypal Checkout V2 SDK does not give you the necessary development tools to validate paypal webhook signatures i.e. you can process payments and receive webhooks but you can not validate the webhook signatures....I know stupid. Tip do not download the SDK directly as you will not include the required autoload.php file. Use composer to install Paypal Checkout V2 SDK so that you get the autoload.php file.
Once you are to a point that you can process payments and receive webhooks form paypal you need to install the another SKD called Paypal Rest API SDK. Again use composer to install the SDK so that you get a autoload.php file which you will need.
When you install Paypal Rest API SDK amazingly you will still be missing files that are required to validate the payapl webhook signatures. I can find no mention of these anywhere on the paypal developer website.
bootstrap.php & common.php
Thanks to #Grumpy I got some samples provided on github HERE
Note you will probably need to modify the samples a bit in order to get them working with your website. Tip set the logger to false and save yourself some bother if you don't have the necessary access permissions to write.
Once you have bootstrap.php & common.php files created you can write the code for your webhook endpoint page i.e. the page that paypal sends the webhook to. I have included my PHP code below for how to validate and then process the paypal webhook. Tip in the below code you need to specify the webhook ID, each webhook that you create in paypal has a unique ID. Also when you are testing you can not use webhook simulator as this will fail validation, you can make manually a payment with your sandbox account details which will trigger a webhook payment event.
Paypal sure don't make it easy, their documentation is all over the place compared to Stripe. The Paypal webhooks can sometimes take several minutes to arrive after a payment is made, very frustrating when trying to debug. Also it's a bit ridiculous that they have a webhook simulator on the paypal developer website that can not be used to validate signatures...if stripe can do it why can't paypal.
<?php
//get the webhook payload
$requestBody = file_get_contents('php://input');
//check if webhook payload has data
if($requestBody) {
//request body is set
} else {
//request body is not set
exit();
}
use \PayPal\Api\VerifyWebhookSignature;
use \PayPal\Api\WebhookEvent;
$apiContext = require __DIR__ . '/bootstrap.php';
//Receive HTTP headers that you received from PayPal webhook.
$headers = getallheaders();
//need header keys to be UPPERCASE
$headers = array_change_key_case($headers, CASE_UPPER);
/*
example header paypal signature content for webhook, these values are recieved as an array, we then need to use this data to verify the payload
CONTENT-LENGTH : 1376
CORRELATION-ID : 6db85170269e7
USER-AGENT : PayPal/AUHD-214.0-54377828
CONTENT-TYPE: application/json
PAYPAL-AUTH-ALGO : SHA256withRSA
PAYPAL-CERT-URL : https://api.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a784-5edc0ebc
PAYPAL-AUTH-VERSION : v2
PAYPAL-TRANSMISSION-SIG : Hc2lsDedYdSjOM4/t3T/ioAVQqFPNVB/AY/EyPNlavXk5WYUfnAmt9dyEP6neAPOjFHiVkXMK+JlLODbr6dalw6i26aFQdsPXqGl38Mafuu9elPE74qgsqNferUFgHi9QFXL+UZCNYcb4mvlDePXZIIAPbB0gOuFGOdEv2uqNwTCSAa/D8aguv1/51FWb3RkytFuVwXK/XNfIEy2oJCpDs8dgtYAZeojH8qO6IAwchdSpttMods5YfNBzT7oCoxO80hncVorBtjj1zQrkoynEB9WNNN9ytepNCkT8l29fQ4Sx/WRndm/PESCqxqmRoYJoiSosxYU3bZP7QTtILDykQ==
PAYPAL-TRANSMISSION-TIME : 2020-04-05T14:40:43Z
PAYPAL-TRANSMISSION-ID : 6dec99b0-774b-11ea-b306-c3ed128f0c4b
*/
//if any of the relevant paypal signature headers are not set exit()
if(
(!array_key_exists('PAYPAL-AUTH-ALGO', $headers)) ||
(!array_key_exists('PAYPAL-TRANSMISSION-ID', $headers)) ||
(!array_key_exists('PAYPAL-CERT-URL', $headers)) ||
(!array_key_exists('PAYPAL-TRANSMISSION-SIG', $headers)) ||
(!array_key_exists('PAYPAL-TRANSMISSION-TIME', $headers))
)
{
exit();
}
//specify the ID for the webhook that you have set up on the paypal developer website, each web hook that you create has a unique ID
$webhookID = "ENTER_YOUR_WEBHOOK_ID_HERE";
//start paypal webhook signature validation
$signatureVerification = new VerifyWebhookSignature();
$signatureVerification->setAuthAlgo($headers['PAYPAL-AUTH-ALGO']);
$signatureVerification->setTransmissionId($headers['PAYPAL-TRANSMISSION-ID']);
$signatureVerification->setCertUrl($headers['PAYPAL-CERT-URL']);
$signatureVerification->setWebhookId($webhookID);
$signatureVerification->setTransmissionSig($headers['PAYPAL-TRANSMISSION-SIG']);
$signatureVerification->setTransmissionTime($headers['PAYPAL-TRANSMISSION-TIME']);
$signatureVerification->setRequestBody($requestBody);
$request = clone $signatureVerification;
try {
$output = $signatureVerification->post($apiContext);
} catch (Exception $ex) {
//error during signature validation, capture error and exit
ResultPrinter::printError("Validate Received Webhook Event", "WebhookEvent", null, $request->toJSON(), $ex);
exit(1);
}
$sigVerificationResult = $output->getVerificationStatus();
// $sigVerificationResult is a string and will either be "SUCCESS" or "FAILURE"
//if not webhook signature failed validation exit
if($sigVerificationResult != "SUCCESS"){
exit();
}
else if($sigVerificationResult == "SUCCESS"){
//paypay webhook signature is valid
//proceed to process webhook payload
//decode raw request body
$requestBodyDecode = json_decode($requestBody);
//pull whatever info required from decoded request body, some examples below
$paymentSystemID = $requestBodyDecode->id;
$eventType = $requestBodyDecode->event_type;
//do something with info captured from the webhook payload
}
This seems to work with php 8.1:
if (openssl_verify(
data: implode(separator: '|', array: [
$httpPayPalTransmissionId,
$httpPayPalTransmissionTime,
$webhookID,
crc32(string: $rawRequestBody),
]),
signature: base64_decode(string: $httpPayPalTransmissionSignature),
public_key: openssl_pkey_get_public(public_key: file_get_contents(filename: $cachedHttpPayPalCertUrl)),
algorithm: 'sha256WithRSAEncryption'
) === 1) {
die('OK');
} else {
die('FAILED');
}

PHP PayPal integration - Cancel link in approval e-mail

I need some help with PayPal integration.
I use this library:
https://github.com/paypal/PayPal-PHP-SDK/wiki/Installation-Composer
and I use WebHooks to receive notifications of payments.
I create payment link like this:
$apiContext = new \PayPal\Rest\ApiContext(
new \PayPal\Auth\OAuthTokenCredential($paypal_client_id, $paypal_client_secret)
);
$apiContext->setConfig([
'mode'=>$paypal_mode
]);
$payer = new \PayPal\Api\Payer();
$payer->setPaymentMethod('paypal');
$amount = new \PayPal\Api\Amount();
$amount->setTotal('1.00');
$amount->setCurrency(Config::get('paypal.currency'));
$transaction = new \PayPal\Api\Transaction();
$transaction->setAmount($amount);
$redirectUrls = new \PayPal\Api\RedirectUrls();
$redirectUrls->setReturnUrl(Uri::create(Config::get('paypal.redirect_url')))
->setCancelUrl(Uri::create(Config::get('paypal.cancel_url')));
$payment = new \PayPal\Api\Payment();
$payment->setIntent('sale')
->setPayer($payer)
->setTransactions(array($transaction))
->setRedirectUrls($redirectUrls);
$payment->create($apiContext);
$payment_url = $payment->getApprovalLink();
Then, I run this link, log in to PayPal and make a payment.
Now, I receive WebHook with event PAYMENTS.PAYMENT.CREATED - so, OK, but after several minutes I get an e-mail:
"Would you like to complete your PayPal payment at xxx?
To finish, go back to xxx and give your final approval."
And text „give your final approval” is linked to my Cancel Page witch I entered into setCancelUrl() metod.
I don’t receive any more webhooks.
Do you have any ideas?
See https://developer.paypal.com/docs/integration/direct/payments/paypal-payments/
You have reached step 3, the payment was created and approved.
You are apparently missing step 4 to actually execute the payment and create a PayPal transaction.... so, no money has moved yet.
Moreover, all of the above and your work so far with the PayPal-PHP-SDK is for an old version of the PayPal REST API, v1/payments. I recommend setting all of those things aside and instead trying out the new v2/orders PHP SDK: https://github.com/paypal/Checkout-PHP-SDK
Here is a demo pattern of the best UI: https://developer.paypal.com/demo/checkout/#/pattern/server
Here is a reference for the server-side integration: https://developer.paypal.com/docs/checkout/reference/server-integration/

How to retrieve information about a transaction just performed?

This is my code:
$gateway = GatewayFactory::create('PayPal_Express');
$gateway->setUsername('name');
$gateway->setPassword('pass');
$gateway->setSignature('sig');
$gateway->setTestMode(true);
$resp = $gateway->purchase(
array(
'cancelUrl' => 'mysite/',
'returnUrl' => 'mysite/success',
'description' => "mysite item",
'amount' => $amount, //final amount
'currency' => 'EUR'
)
)->send();
if ($resp->isSuccessful()) {
// payment was successful: update database
// never reached
$a = new database('database');
$a->write database;
$dbp = null; die;
print_r($resp);
} elseif ($resp->isRedirect()) {
// redirect to offsite payment gateway
$resp->redirect();
} else {
echo $resp->getMessage();
header('Location: mysite/error');
exit;
}
How can I retrive informations about the transaction after the redirect?
How to adapt this code for credit card on paypal?
From your comments, I would assume that you're not getting to the successful payment stage.
With this in mind, let's take a look at the express checkout flow and compare it to a DoDirectPayment api call
===============
SetExpressCheckout API Call - the Shopping Cart announces the checkout details and gets back an "Express Checkout Token". The token identifies the checkout session that the shop has requested from PayPal
The buyer is redirected to the Express Checkout URL and the token gets appended to the redirect URL - https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-6C677292NP7377708
(if you skip step 5, you have to add a useraction=commit parameter to the redirect URL)
The buyer logs in and approves the payment
The buyer is redirected back to the Return URL announced in the SetExpressCheckout API call with the PayerID and the Token added to the return URL as HTTP GET Parameters
5. The integration initiates a GetExpressCheckoutDetails API call, retrieves the shipping info and displays one last overview and the added shipping charges to the buyer
Once the buyer decides to complete the payment, he initiates the payment through your integration on your website. The website then calls the DoExpressCheckoutPayment API
===============
For Credit Card Payments via the DoDirectPayment API, the API NVP Request and Response would look like this - it should be pretty straight forward.
Request:
VERSION = 109.0
METHOD = DoDirectPayment
PAYMENTACTION = Sale
IPADDRESS = 192.168.0.1
AMT = 0.01
CREDITCARDTYPE = Visa
ACCT = xxxxxxxx6840
EXPDATE = 102020
CVV2 = 123
FIRSTNAME = John
LASTNAME = Test
STREET = 12312 Port Grace Blvd
CITY = La Vista
STATE = NE
COUNTRYCODE = US
ZIP = 68128
CURRENCYCODE = USD
Response:
TIMESTAMP=2015-01-20T16:00:27Z
CORRELATIONID=180513f33ad52
ACK=Success
VERSION=109.0
BUILD=14726230
AMT=0.01
CURRENCYCODE=USD
AVSCODE=X
CVV2MATCH=M
TRANSACTIONID=0PA61839GE498951M}
===============
Judging by your comments in the code, you're assuming that the transaction completes once step 4 is complete.
As I do not see any code to initiate a DoExpressCheckoutPayment API call, you will need to make sure at least step 6 is being done.
https://devtools-paypal.com/integrationwizard/ has standalone sample code that might help.
However, using an SDK based integration will relieve much of the pain:
https://devtools-paypal.com/guide/expresscheckout/php?interactive=ON&env=sandbox
...
If you want to retrieve Payment Details at a later stage, you can run a GetTransactionDetails API call against the Transaction ID returned in the DoDirectPayment API call or the DoExpressCheckoutPayment calls.
See: https://developer.paypal.com/webapps/developer/docs/classic/api/merchant/GetTransactionDetails_API_Operation_NVP/
You can use Instant Payment Notification to receive notifications about the just completed transaction. IPN is the recommended way to go.

EBS payment gateway integration using PHP

i need to integrate ebs payment gateway. i am searching lot but i could find the solution.
Response is provided using POST method to the URL defined under ReturnURL parameter in the payment request. $response['ResponseCode'] == 0 means transaction successfully completed. Other than 0 value transactions failed. I can't find $response['ResponseCode'] == 0.
here my code
if(isset($_GET['DR'])) {
require('Rc43.php');
$DR = preg_replace("/\s/","+",$_GET['DR']);
$rc4 = new Crypt_RC4($secret_key);
$QueryString = base64_decode($DR);
$rc4->decrypt($QueryString);
$QueryString = split('&',$QueryString);
$response = array();
foreach($QueryString as $param){
$param = split('=',$param);
$response[$param[0]] = urldecode($param[1]);
}
}
I would understand how exactly the integration to EBC is done and look at one of the existing Broadleaf Payment modules as a template.
For example:
- Does EBC provide an API for direct server to server communication? (i.e. the Credit Card information is passed to your server and then relayed to the gateway? If so, take a look at http://docs.broadleafcommerce.org/curre ... odule.html
- Does EBC provide a mechanism for a Transparent Redirect or Silent Post? (i.e. the Credit Card form is sent directly to EBC thereby bypassing the merchant servers? If so, take a look at http://docs.broadleafcommerce.org/curre ... e.net.html
- Does EBC provide a mechanism for a Hosted Order Page? (i.e. you get redirected to EBC's servers to enter your credit card information. If so, take a look at http://docs.broadleafcommerce.org/curre ... odule.html)
The many different integration options that the Payment Gateway provides will determine how Broadleaf should integrate with it.
Hope that helps.
Reference : http://www.fetchflow.com/blog/authorize-net-invoicing

PayPal REST - Shipping info and transaction ID

Here is a simplified version of my "ExecutePayment" php file:
$payment = Payment::get($paymentId, $apicontext);
$execution = new PaymentExecution();
$execution->setPayerId($_GET['PayerID']);
$payment->execute($execution, $apicontext);
var_dump($payment);
The payment executes successfully, but the $payment variable contains no info about the customer's address, and no transaction ID. Even if I call $payment = Payment::get($paymentId, $apicontext); again after executing the payment, there is no useful information contained in the Payment object.
However, in the PayPal.log file, I see the customer's address, and the transaction ID. How do I access this data aside from reading the log file itself?
Apparently, the important object is the one returned from $payment->execute()
PayPal's sample on github is misleading... had to go through the PayPal API code to find my fix. :P

Categories