Finished the integration of our site with the payment system
PayPal . In my case, there was a small feature - we already accept payments from
Robokassa and we would like to receive a similar workflow when paying. PayPal has a lot of different integration options and the biggest “difficulty” was finding the right option that matches the existing workflow.
Our workflow is very simple:
- the user enters the amount, presses the button, goes to the payment system site
- pays and returns to us
- we further check the payment status and do the necessary manipulations.
In the end, everything worked out for me, although not without small jambs (as without them).
What we need
Step 1: Set up PayPal
Go to
developer.paypal.com . For this, a regular paypal account will do. Go to the
Applications tab.
')
Create a new application. You should have no difficulties. Of the important parameters: "Application return URL." This is the address to which PayPal will send the user after payment (or cancellation). Also pay attention to Client ID and Secret. These are the keys by which the pipe will authorize us when using api.
Next you need to create a test account for the sandbox. Click the link
Sandbox accounts create a test user (under it we will conduct test payments). Difficulties, too, should not arise.
Step 2: Test Application
Install the SDK:
Install-Package RestApiSDK
We create a test application (for example, a console application, although I use an empty test in a project for this purpose, QuickTests). And copy-paste into it the code below,
after replacing YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with the parameters of our newly created application. The code, in principle, can be taken from the
Interactive Guide with code examples , I just gathered it together and brought it into a pleasant form.
var sdkConfig = new Dictionary<string, string> { { "mode", "sandbox" } }; string accessToken = new OAuthTokenCredential("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET", sdkConfig) .GetAccessToken(); var redirectUrls = new RedirectUrls { cancel_url = "http://localhost:11180/PayPalResult?cancel=true", return_url = "http://localhost:11180/PayPalResult?success=true" }; var amnt = new Amount { currency = "USD", total = "1" }; var createdPayment = new Payment { intent = "sale", payer = new Payer { payment_method = "paypal" }, transactions = new List<Transaction> { new Transaction { description = "Sample payment", amount = amnt }}, redirect_urls = redirectUrls} .Create(new APIContext(accessToken) { Config = sdkConfig }); var approvalUrl = createdPayment.links.Single(l => l.rel == "approval_url").href; var paymentId = createdPayment.id; Console.WriteLine(approvalUrl); Console.WriteLine(paymentId);
We pass on approvalUrl, log in under the test account, confirm the payment, throws us to
http: // localhost: 11180 / PayPalResult? Success = true & token = EC-DSKFJDSKFJEO42M & PayerID = DFKJDFKLGJEOR (doesn’t matter if you have a web server that has a service, you have a service, you have a service provider?
Take the PayerID parameter from this URL and insert it, along with PaymentId (we received it a little earlier), into the following code:
string payerID = "YOUR_PAYER_ID"; string paymentId = "YOUR_PAYMENT_ID"; var sdkConfig = new Dictionary<string, string> { { "mode", "sandbox" } }; string accessToken = new OAuthTokenCredential("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET", sdkConfig) .GetAccessToken(); var pymntExecution = new PaymentExecution { payer_id = payerID }; var payment = new Payment { id = paymentId } .Execute(new APIContext(accessToken) { Config = sdkConfig }, pymntExecution);
Here payment.status is important for us, which has now received the value “approved”. Hurray, the test is passed!
Documentation says that we should do
Refund a sale (API reference) further, but I, for now, did not understand what it is.
Step 3: Integrating into our application
With the integration of the code above in the application, theoretically, there should be no problems. But I still had them. This problem was connected with remembering paymentId between two methods. Just remembering paymentId is not difficult, it is difficult to understand which of the remembered payments belongs to the current request. After all, paypal in resultUrl does not specify any data other than PayerID. And by PayerID get paymentIdo not work out.
You can store this value in the session and assume that the user conducts only one transaction at a time.
And you can
do more cunning . You can generate an id for payment and ask PayPal to include this id in ResultUrl. Like this:
var redirectUrls = new RedirectUrls { cancel_url = "http://localhost:11180/PayPalResult?cancel=true&InvoiceId={SOME_ID}", return_url = "http://localhost:11180/PayPalResult?success=true&InvoiceId={SOME_ID}" };
With this value you can already find the corresponding paymentId. In principle, it is possible to immediately transfer paymentId to RedirectUrls, but it seems to me that it is not security (although the security officer from me is so-so, these values ​​can be well protected and nothing can be obtained from them).
Conclusion
That's all. Not so difficult as it seemed. I hope someone else will find this instruction useful.
I have a couple of open integration questions. If you can answer them - I will be grateful.
- How to use the token that PayPal sends to ResultUrl. It is clear that it can somehow be used to make sure that this is exactly PayPal, and not an attacker. The question is how.
- When paying PayPal shows the user only what we gave him. Those. if we have not transferred the order amount, the user will not see it. To me it looks weird. Maybe this is a sandbox feature?
Answer: If you transfer the list of goods and their price, then Paypal checks the order amount. more ... - Need to deal with Refund. It looks like an important step in payment. Interestingly, if you do not refund, can the user cancel the transaction?
Answer: “you do not need to refund (this is a refund), you need to call it when you say you can’t deliver the goods, but you accept payment ...”, more .... Thanks tzlom , - What to do if the user paid, and then canceled the transaction (like PayPal allows it)? Will cancel the request come to ResultUrl and what is the deadline for cancellation?
Answer: “Instant Payment Notification (IPN) will come” (thanks to hannimed , more ... ) and “refund will come in your case” (thanks to tzlom , more ... )