My objective is to use a simple shopping cart to create a "cart upload" form which takes the user to a friendly PayPal page that handles shipping, taxes, etc based on the facilitator's account dashboard settings in which we can set those items. However I'd like to send the server-generated values of the cart-upload form via POST request to the paypal website https://www.sandbox.paypal.com/us/cgi-bin/webscr without showing the form on the client so that people won't tamper with the form values and set their prices.
When I perform the POST manually (submit the generated cart upload form), the Network tab of my dev console shows a request with "Provisional Headers shown" warning for a very short time, after which the request is 'updated' to show a bunch of things that I have no idea where they came from but are probably necessary for the success of this mission. The Request Headers suddenly fills up with the big Cookie field which contains among other things an "ectoken=...". This is an 'express-checkout' token, but how does it get there?
My idea is to do a POST via server request and to send these things in the header, or set the cookie properly so that when the request goes, it will put up the correct page I want.
When I perform the POST via the server code, it complains that my cookies are not enabled, etc. I started experimenting by putting some cookies gleaned from the http response of this POST, and it started to at least show different behavior such as showing me a "Session logged out" screen.
I now know there's lots to learn about how these requests go back & forth, but I believe if I can do this manually with the browser I should be able to do the same thing with server code? Just how does that "ectoken" (& the rest of the request header) get formulated puzzles me.
Related
On an e-commerce site in the payment page I used the new js sdk from paypal.
When the user clicks on paypal button a popup appears and the user performs the transaction in the popup.
When the transaction is over the popup closes and a callback is called to do what is needed.
If the user manually closes the popup, a CANCEL event is emitted and the transaction is considered canceled.
The problem I'm having is that sometimes I see on the logs that I receive the CANCEL event (meaning that the user has closed the popup) but on PayPal account the transaction is succesfull and correctly payed...
Is it possible that the user closes the popup just before paypal sends the confirmation back or something like that? Anyone knows how this can be handled?
Using the JS SDK alone is for very simple use cases. For an ecommerce site of any importance, the JS SDK should be combined with the v2/checkout/orders API. This way orders are always captured from the server and recorded when successful, and things happening on the client side won't be relevant nor interfere with accurate payment tracking.
Your question doesn't give technical details for your current integration, but here's how to go about making a correct one from scratch:
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)
I've never used PayPal before, it's not really popular here, and I'm confused by how the order and payment works. Can anyone explain it to me? I've read the documentation and I'm still confused.
To complete payer approval, use the approve link to redirect the
payer. The API caller has 3 hours (default setting, this which can be
changed by your account manager to 24/48/72 hours to accommodate your
use case) from the time the order is created, to redirect your payer.
Once redirected, the API caller has 3 hours for the payer to approve
the order and either authorize or capture the order.
I have created a working PHP curl call for this API in sandbox env according to the sample
https://developer.paypal.com/docs/api/orders/v2/#orders_create
The APIs I created before work like this:
Send a request to 3rd party payment
Get a response containing a checkout link
Redirect customer to link
Customer complete payment
3rd party send a request containing order and payment detail to a file/path on my server
My server receives the request and updates the order status/payment in my database
3rd party redirect the customer to my webpage
With PayPal, what I got so far is:
Send request containing order detail to /v2/checkout/orders
Get a response containing various links
Redirect my customer to the rel:approve checkout link
Log in to my sandbox customer account and pay using PayPal balance, click Continue
A popup message is shown: We're sending you back to xxx's Test Store to complete this purchase
The popup message is closed and I'm still at the same payment page with the Continue button as seen in the image
Send request containing order detail to /v2/checkout/orders
Get a response containing links
Redirect my customer to approve link
Step (3) is an old integration method, for websites using an old redirect-based flow. The preferred way to integrate PayPal uses no redirects. At all. Your website remains loaded in the background. Do the following:
Follow the Set up standard payments guide and make 2 routes on your server, one for 'Create Order' and one for 'Capture Order', documented here. Both routes should return only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should 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 sending confirmation emails or reserving product) immediately before forwarding your return JSON to the frontend caller.
Pair those 2 routes with the frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
If, for some odd and inexplicable reason, you insist on using the legacy flow with a full page redirect instead of what I just described above, you must include a redirect_url in your orders creation request, so that PayPal has somewhere to return to after the order is approved. Immediately when the return happens, capture the order with an API call and show the success/failure result to the customer. If you want an intervening order review step before capture, you can do this, but you must also edit your initial order creation request to change the verbiage of the last button at PayPal from "Pay Now" to "Continue" so that the user is clicking on something that corresponds to what the next step will be. application_context.user_action needs to be continue for this change.
Capturing an order will return a v2/payments object which is the completed transaction with its own ID for accounting and refund purposes. (The order ID is only used during payer approval, and unimportant otherwise)
I had this issue too, and I eventually got a solution from the documentation.
You have to add application_context.return_url to your request.
Attached is an example in PHP:
$postData = [
"intent" => "CAPTURE",
"purchase_units" => $purchase_units,
"application_context" => [
"return_url" => "",
"cancel_url" => "",
],
];
You can make a whole lot of customisations to the PayPal Payment page by adding the Application Context option, For a full list of the possible customisations, you can check up the official documentation Application Context Documentation
We have a checkout page where the user enters their CC number, item they want to purchase, and they complete a challenge. When the form is submitted, the sever validates the challenge and then saves the payment and charges their card.
However, we want to change it to only prompt for the challenge when the person making the checkout is considered suspicious (and increase the difficulty of the challenge as they get more suspicious).
checkout button is pressed (POST)
server checks request data and compares it against previous checkouts
server determines if challenge is needed, if so, client needs to complete this and send back to the server
if challenge is not needed, checkout is accepted and CC is charged
What would be the RESTful way to do this?
What would be the RESTful way to do this?
How would you do it with web pages?
Probably - you would present the user with a form, the user would fill in the form and submit it. If the user looks innocent, then you would process the checkout as is, and send back a response that represents the checkout action.
If the user looks suspicious, then rather than processing that form, you would send the user a response that says we can't process your payment because you are suspicious; use this alternative form to make progress. The user would submit the alternative form, and then you would evaluate whether or not the user had met the security challenge.
That's the RESTful way to do it; you give the client forms to submit, and links to follow. Clients that recognize the semantics provided in the representations can make progress, those that cannot stop.
i usually use the standard POST form on my site, with fields that the user fills out, which POSTs directly to https://www.paypal.com/cgi-bin/webscr
what i would like to do now, is have the form submit to my own site, for my own internal programming purposes, and when that is done, my site would automatically forward the user to paypal, with the relevant field data in the URL, for example, to: https://www.paypal.com/cgi-bin/webscr?first_name=foo&last_name=bar& etc...
this would save me from having to put the intermediate stage of the form with the hidden fields, asking the user to "click here to complete your transaction on PayPal"
hope i'm understood....
thanks!
Sure, it'll work. But keep in mind that unless you involve the BMCreateButton or Express Checkout API's, the amount will be open to URL manipulation, so you must do a check on the paid amount afterwards.
For example; https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=blah#blah2.com&amount=0.99¤cy_code=GBP&item_name=Blah+for+sale
Note: The GET redirect must be initiated on the browser-side or via a header() redirect. You can't use cURL for this, since that's a server-to-server communication.
I'm wondering if anyone knows how exactly Gmail, Hotmail, Facebook etc handles following scenario. (NOTE: Assuming Cookie is shared between tabs)
Opens two login page to the application.
User 1 logs in the domain.
User 1 changes some data without saving it.
User 2 logs in the domain in a separate tab.
User 1 switches back to his tab and saves the data.
I tried repeating the steps FF for Gmail, it sometimes gives me
"This may have happened automatically because another user signed in from the same browser" and logs the previous user out automatically" but the other times just shows "The page isn't redirecting properly" and I'll have to clear my cookie.
Hotmail, seems to be a bit better, where it immediately detects that I'm logged in the first page and asking if I would like to switch account. If I selected to switch account and goes back to try to save the data, hotmail throws a login error message.
Anyone can shed some light on how each one is implemented as well as what might be the best practice to handle this problem?
In general, to counteract such issues you'll want to do cross-references of the identity from cookie and other submitted data. So the submitted form will include the user id, and the cookie will include the user session. If those are inconsistent, then reject the attempt, invalidate the session, and send the user to login.
If your forms have CSRF protection tokens (which they should), then the CSRF token can also encode the user ID, so the attempt for user 1 to save their data will fail due to an invalid CSRF token on the form.