Replacing PayPal SetExpressCheckout SOAP API with REST API V2 - paypal

We are in the process of replacing our Paypal SOAP API calls (SetExpressCheckout etc.) with the Paypal REST API V2.
Three questions:
1) Paypal has two similar APIs: orders and payments. Which one is considered to be the replacement for SetExpressCheckout?
2) We use the tokens returned by SetExpressCheckout to do a capture or refund later. Can the tokens we got from SetExpressCheckout also be used to do a capture / refund using the REST APIs? (If not, we cannot do a "big-bang" migration, but keep both implementations in place until we are sure no capture or refund will take place for transactions which have been issued with the SOAP API).
3) Does the merchant need to amend anything in his profile, e.g. give new rights to use the REST API? For example, we use SOAP API call TransactionSearch, which requires special rights - are those also valid for REST API calls?

1) Creating a v2/order replaces SetExpressCheckout. Capturing a v2/order replaces DoExpressCheckoutPayment. The capture will return a new transaction id that is a v2/payment object, and this v2/payment object id is the only thing that is preserved in www.paypal.com for accounting purposes (the v2/order id is not used for accounting; like an EC token, it is for the payment approval process only)
For the front-end, use
https://developer.paypal.com/demo/checkout/#/pattern/server
[ You mentioned capturing later, so the following won't apply to that particular case, but: if your flow were set up to capture right after approval with the buyer present, then -- once everything about your implementation is working for the happy path -- don't neglect to add support for handling funding source failures, so that if the immediate capture fails due to e.g. the buyer's first card being declined, this is propagated back to the UI and the buyer can select a different funding source right away ]
2) SetEC tokens cannot be mixed with REST APIs for capture
3) Yes and no. If you're using a REST API to search transactions, then what will matter are the permissions of the REST ClientID+Secret you are using. What will be most straightforward will be for the merchant to generate a new REST app in https://www.paypal.com/signin?intent=developer&returnUri=https%3A%2F%2Fdeveloper.paypal.com%2Fdeveloper%2Fapplications with all the necessary permissions, and provide you with that REST App's live ClientID+Secret.

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)

PayPal Node SDKs: difference between paypal-rest-sdk and #paypal/checkout-server-sdk for webhooks?

I have this question regarding 2 npm PayPal packages, what is the difference between
paypal-rest-sdk and #paypal/checkout-server-sdk ? And can you implement webhooks using #paypal/checkout-server-sdk or there is no need for webhooks for this package ?
paypal-rest-sdk
checkout-server-sdk
var paypal = require('paypal-rest-sdk');
const paypal = require('#paypal/checkout-server-sdk');
All PayPal-*-SDK for every language have been deprecated for a long time and should not be used for anything. This includes the one for node that's in npm as #paypal/paypal-rest-sdk.
The Checkout-*-SDK for every language, in npm for node as #paypal/checkout-server-sdk, implements the v2/checkout/orders API (and only that API). It can still be used if desired, although I've heard it will be deprecated soon as well. Currently all developer.paypal.com documentation only references doing direct HTTPS REST API integrations, using a client id and secret to first obtain an access_token. For node in particular, there is a full stack example in the PayPal Checkout integration guide that serves as a useful starting point, although I recommend the client side onApprove function in this approval flow since that sample includes client-side error handling of the capture response (restarting or showing an error as appropriate)
As for webhooks, they are a separate matter. There is no current SDK for them. The server-side capture API response is already sufficient for normal orders API payments so you may not need webhooks for what you're doing, but if there are specific events you're interested in listening for (such as refunds or disputes that occur on PayPal.com ) you'll need to subscribe to the event(s) you want -- either in the REST app or using webhook API calls.

Search client transactions data

I'm building an application that resembles personal financing. For that, I need to fetch information about that customer's transactions.
I managed to run the GetBasicPersonalData example within the permissions service.
Here it says that requesting TRANSACTION_SEARCH will allow me to use TransactionSearch on behalf of the customer.
There is no such endpoint and calling the NVP service with METHOD=TransactionSearch and similarly constructed X-PAYPAL-AUTHORIZATION header doesn't do it either.
How can I use the token and token secret retrieved from the permissions service to list that customer's transactions?
Update: According to FAQ#6 here, the X-PAYPAL-AUTHORIZATION is supposed to be used to replace the USER, PWD, and SIGNATURE params. When I call the nvp service that way I get:
TIMESTAMP=2016%2d11%2d07T15%3a35%3a36Z&CORRELATIONID=f50b7296c2d28&ACK=Failure&VERSION=94%2e0&BUILD=24616352&L_ERRORCODE0=10002&L_SHORTMESSAGE0=Authentication%2fAuthorization%20Failed&L_LONGMESSAGE0=You%20do%20not%20have%20permissions%20to%20make%20this%20API%20call&L_SEVERITYCODE0=Error
I'd like to share below useful documents for your reference:
TransactionSearch API guide here;
TransactionSearch API reference here;
PayPal API Endpoint here(Refere Merchant APIs);

REST API: Providing redirect URIs to external services using client app domain

Background
I have a RESTful API accessed through the domain http://restapi.com
I have a client app using http://restapi.com. The client app has the domain http://myapp.com
The way I have my HATEOAS setup is that the API presents URIs without a domain. So instead of http://restapi.com/some/resource, it contains links to resources like so /some/resource. Example API json resource below:
{"_links":{"self":{"href":"/some/resource"}}}
The benefit this has is that the API doesn't need to know about the client app, and the client app has to do very little to get the correct resource from the API and doesn't have to reformat all the URIs in the resource. For example, in the client app, the following URI would be used by the browser http://myapp.com/some/resource. When the app gets the request, it then needs to call the API to get the resource and simply swaps the domain i.e. http://restapi.com/some/resource.
This has been successful so for, and allows a lot of flexibility to have different clients use the API with the only knowledge required being the initial end point (domain) of the API. It also completely decouples the API from the client apps.
The problem I have run into is that I have started using some external services (specifically PayPal adaptive payments) where I need to provide a redirect URL for cancelled payments and successful payments. For example, the browser navigates to http://myapp.com/payment. The resource returned by http://restapi.com/payment presents a link to PayPal. Without going into too much detail, the API has to ask PayPal for a payment ID, which can then be used to create a link to a PayPal payment e.g. http://paypal.com?PayId-123456. Part of the creation process requires that URLs are provided to redirect on payment cancellation or success. Again, don't want to go into details, but when requesting a PayId from PayPal, the redirect URLs are sent as variables to PayPal, and I guess PayPal stores them against the specific PayId created.
The browser navigates to the link returned in the resource - http://paypal.com?PayId-12345. Payment is made and PayPal then uses the redirect URLs as needed to redirect back to my app e.g. on successful completion of payment, PayPal should redirect to http://myapp.com/paymentcomplete. Note: I realise that this is not a restfully named URI, but it simplifies building up the description of my problem
Problem
The problem I have may now be obvious. I need to redirect back to http://myapp.com/paymentcomplete, BUT its the API that provides the redirect URL to PayPal. It has no knowledge of the client application. Since PayPal is an external service, the full URL must be provided. The best the API can do is send http://restapi.com/paymentcomplete as the redirect URL, but if PayPal redirects to this, the resulting response will be a JSON string (the output format of my API) not the nicely formatted page of the client app.
My question is, what is a good way to correctly provide the redirect URL to PayPal?
One thought I had was to make the client application handle creating the PayPal PayId, but I don't like this option as I would like to keep the creation of the PayPal payment ID on the API side. It would also require every client app to provide its own implementation, something I also don't want.
The other option I though of was to ask the client to provide its domain in the request. Currently the request the client makes to get the resource with the link to PayPal is GET http://restapi.com/payment, but I could use POST http://restapi.com/payment with the client providing its domain as a param. The API can then use this to construct the correct redirect URL. I don't really like this idea either as its seems a bit hackish and also requires the app to know that is must fill in this field i.e. a human user wouldn't fill the domain input in.
Additional solutions, or thoughts greatly welcomed.
As you had already mentioned, PayPal is an external api that requires this additional parameter and you do not have control over it. Looks like the client is the only party that can provide the Redirect URI Information.
Couple of ideas come to mind.
The client could send the redirect uri to restapi via header and thus
keeping your rest urls intact. This is a grey area and not a violation of restful api
in my opinion. (Then again, its just my opinion).
The restapi could return the response with a placeholder for the
client to fill in before rendering. This way the API need not know
about the redirect uri and the responsibility is left to the client
which has this information.
It would be nicer if you could implement option 2 with executing couple of lines on Javascript code on the browser to fill-in the placeholder. Which is easy. Ultimately, only 2 end points of this transaction would be aware of the redirect uri - browser & paypal.
This alleviates most of your concerns. The job of handling PayPal id will continue to remain with your API.
You should be able to use the Referer header to determine the client's full URI. It might be populated automatically for you. If not, you can add it yourself. The URI class has methods to pull out the client's host for you. When the API builds the PayPal URI to return to the client, it can include the client's host.
Note that referer is not always included and sometimes gets stripped by intermediaries, as detailed on the wiki page. Since you control both the client and the server in this case, you should be able to tell everybody to play nicely.
I would keep the GET http://restapi.com/payment and pass in a query param with the client domain
GET http://restapi.com/payment?domain=http://myapp.com (of course, the "http://myapp.com" needs to be encoded)

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