How do i cancel a PayPal (Express Checkout) transaction? - paypal

I have an application that uses Express Checkout to process payments.
I need some way to cancel a transaction after calling SetExpressCheckout (and having the user fill out his details on paypal's page) and before i actually complete it with DoExpressCheckoutPayment.
I can't find the right way to do it in paypal documentation, do i just let it time out or do i need to do some API call?

You just let it time out. If you haven't called DoExpressCheckoutPayment yet, no action has yet taken place.
The token automatically expires after three hours.

Technically you could just empty the token REQUEST, and unset the reshash SESSION and let it expire without risk (assuming you are using the same named variables the api samples came with. What language are you using? I can further provide examples.
In PHP I would simply do:
// empty token
$_REQUEST['token'] = NULL;
//unset reshash session
$_SESSION['reshash'] = NULL;
unset($_SESSION['reshash']);
Now you would ideally want to redirect the user to a cancellation page, something like
header( 'Location: http://www.example.com/transactionCancelled.html' )
Otherwise depending if the user is in the 'ReviewOrder' phase, they will just automatically get redirected back to paypal to start a new transaction.

Related

In the PayPal API, how exactly to work with Webhooks for PAYMENT.CAPTURE.COMPLETED & CHECKOUT.ORDER.APPROVED?

I am not sure I understand the difference? The way I understand it so far is that CHECKOUT.ORDER.APPROVED comes first and once the payment has been processed properly, it moves onto PAYMENT.CAPTURE.COMPLETED (based on this answer and this). So there could be an approved checkout without a completed payment capture, which means, that I should wait for PAYMENT.CAPTURE.COMPLETED before giving users access to content behind paywalls etc.
If this is true, can I generally rely on them coming in this order (e.g. for my webhooks)?
For example: Say I create a new order in my database, when the webhook for CHECKOUT.ORDER.APPROVED is triggered. Now in the webhook for PAYMENT.CAPTURE.COMPLETED I want to continue working with this data. Can I be confident, that this order will exist in the database at this point?
CHECKOUT.ORDER.APPROVED means a payer approved an order. It does not mean it has been captured, and any number of things could interrupt the capture. In general this event is best ignored / not subscribed to -- there is nothing useful to be done with it. Storing orders in your database before successfully capturing them is largely pointless.
PAYMENT.CAPTURE.COMPLETED indicates a transaction has been created. This is more useful. However, since it's an asynchronous notification it's generally only useful for payments that will take place in the future, such as Subscriptions.
For one-time payments, there's no need for webhooks. Just use the v2/checkout/orders API and make two routes (url paths) on your server, one for 'Create Order' and one for 'Capture Order'. You could use one of the (recently deprecated) Checkout-*-SDKs for the routes' API calls to PayPal, or your own HTTPS implementation of first getting an access token and then doing the call. Both of these routes should return/output only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should verify the amount was correct and store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as reserving product or sending an email) immediately before forwarding return JSON to the frontend caller. In the event of an error forward the JSON details of it as well, since the frontend must handle such cases.
Pair those 2 routes with this frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server . (If you need to send any additional data from the client to the server, such as an items array or selected options, add a body parameter to the fetch with a value that is a JSON string or object)

Is there a way to authorize orders calling the paypal api directly

For my users to be able to send money to each other on my website I figured the following flow:
User is authenticated with paypal connect
"Clicks on a pay button" calling my api
In the api
Create an order calling /v2/checkout/orders
what returns HATEOAS links, order id. And, I need the user to follow the authorize order
link from the HATEOAS links to authorize the order.
User follows the link.
I capture the order calling /v2/checkout/orders/{id}/capture
And, here is a question: how do I know when users follow the authorize order link to call the capture api? If that is not possible, is there a way to authorize orders calling the paypal api directly without making users following some links?
First of all, what you are actually talking about is user "approval", not authorizing.
The best approval flow to use is this one: https://developer.paypal.com/demo/checkout/#/pattern/server
This way, they don't follow a link and are not redirected away from your site. Your site stays loaded, but is just greyed out while they are presented with an in-context approval flow, and return to your site's JS, which will do a fetch call to your server, which can then do the capture.
An alternative legacy flow is to provide a return_url in your initial create call, where the payer will be redirected back to after approval. This is not recommended, the above solution (that uses no redirects at all) is much more modern and preferred.

How can I find out if a user deleted his consent on Future Payment?

As the title says, I would like to check if the user has deleted his consent on Future Payments in his PayPal profile. I am currently only testing in the Sandbox environment with the iOS mSDK and the Java REST API SDK.
I expected that creating new accessTokens using the refreshToken would throw an error, but it is still possible. Then I tried to query Userinformation, but this is also possible.
If I create a new Payment, then I get an error (REQUIRED_SCOPE_MISSING). But isn't there a way to check that without creating a transaction each time?
you can always call updateBillingAgreement API to check whether it is active or not.
Paypal also has IPN setup to adhere this kind of notifications.https://www.paypal.com/cgi-bin/webscr?cmd=p/acc/ipn-info-outside
I found no good solution for this problem without using IPN (not tested yet). I am now using a workaround as described here: https://github.com/paypal/PayPal-iOS-SDK/issues/189.
Conclusion: An accessToken generated with the refreshToken has the value "900" in the field "expires_in" if the user consent still exists. Otherwise, it is "28800".
Does anyone have a better solution?

executing payment without storing the paymetId in session but database

I'm using the examples in the paypal-php-sdk and setting up payments. It works fine and I'm getting the redirect URL and I'm able to make the payment.
In the example the PaymentId is stored in the session, and later in the executePayment.php retrieved. In the comments it says to store this, off course in a database.
But how can I link this PaymentId to the return values givin by the paypal api?
When the payment is approved I'm sent back to my webstore with this parameters:
ExecutePayment.php?success=true&token=EC-xxxxxx&PayerID=AXxxxxx
How can I link the token-payerID to my PaymentID? So I don't have to store it in a Session? For instance is it possible to get the ec-token during the build of the payment?
It turns out to be very simple!
In the return url parameter you just give the url an query string. Pretty simple:
$returnUrl = 'executePayment.php?orderId=234'
Paypal then automagically adds the token and payer-id to the return URL.

Would implementing openssl prevent users from changing the button values?

Would implementing openssl prevent users from changing the button values?
I've researched into encrypting buttons, from hosted to using openssl.
Using hosted buttons would provide security at the cost of flexibility although there are variables that you can override, but still you cant override the important ones.
would using and implementing openssl on my webserver prevent users from changing a non-hosted paypal button ?
or would it just be better to fall back to a hosted button and use/validate using IPN?
My answer is non–PayPal specific (applies to any kind of HTTP form input), but the short answer is no. Even SSL cannot prevent the browser from modifying the form values that it receives.
A user could use a bookmarklet to execute a JavaScript program of her choice on your page after it has loaded, which has the ability to change form values. Because SSL only protects the transport between the browser and the server, not after the page has been processed by the browser, it makes no difference at all whether you use it.
This could be automated with Greasemonkey, which is the same idea, except makes it even easier for users to install other people’s JavaScript programs to run on your web page. As above, using SSL does not affect this at all, because it is all execute client side, which you, as the server, have no control over.
As you alluded to, using encrypted PayPal buttons would solve the problem, as any modification of the button parameters would invalidate the checksum, and PayPal would not accept the item.
The best solution would be using Express Checkout. This allows you a great deal more flexibility than standard buttons can ever offer you.
If you're thinking if doing IPN, you're probably capable enough to integrate Express Checkout. All it really is, is 1 API call, followed by a redirect to PayPal, and a minimum of 1 more API call to finalize the payment.
A typical flow would look as follows:
Call the SetExpressCheckout API. If you're new to this, it's made dead-easy with PayPal's NVP API interface. You can just send the data as a GET NVP string to https://api-3t.paypal.com/nvp and get a response back in the same format.
Take the token from the response, and redirect to https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=XXXXXXX (https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=XXXXXXX for Sandbox testing)
As soon as the buyer is returned, PayPal will append a PAYERID to your RETURNURL. If you can't find it, call the GetExpressCheckoutDetails API and supply your token to retrieve it.
With the PAYERID and TOKEN, call DoExpressCheckoutPayment to finalize the payment.
To get started with this, I'd suggest taking a looking at the PHP NVP SDK they offer at https://www.x.com/community/ppx/sdks#NVP