
We receive payment via PayPal
Finished the integration of our site with the PayPal payment system . In my case, there was a small feature - we already accept payments from Robocassa 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:
In the end, everything worked out for me, although not without small shoals (as without them).
We go to developer.paypal.com . For this, a regular paypal account is suitable. Go to the Applications tab .
Create a new application. You should not have any difficulties. Of the important parameters: "Application return URL." This is the address to which PayPal will direct the user after payment (or cancellation). Also pay attention to Client ID and Secret. These are the keys by which the paypal will authorize us when using the api.
Next, you need to create a test account for the sandbox. Click the Sandbox accounts link to create a test user (under it we will conduct test payments). Difficulties should not arise either.
Install the SDK:
We create a test application (for example, a console application, although I use an empty test in the project for this purpose, QuickTests). And copy the code below into it, 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 put it together and brought it to a pleasant appearance.
We go to approvalUrl, log in under the test account, confirm the payment, we are transferred to http: // localhost: 11180 / PayPalResult? Success = true & token = EC-DSKFJDSKFJEO42M & PayerID = DFKJDFKLGJEOR (it does not matter if you have a web server that serves 111).
We take the PayerID parameter from this URL and insert it, along with PaymentId (we received it a bit earlier), in the following code:
Here payment.status is important for us, which has now received the value "approved". Hooray, the test is passed!
The documentation says that next we need to do Refund a sale (API reference) , but so far I have not figured out what it is.
Theoretically, there should be no problems with the integration of the code above into the application. But still I had them. This problem was associated with remembering paymentId between the two methods. Just remembering paymentId is not difficult, it is difficult to understand which of the remembered payments the current request belongs to. After all, paypal in resultUrl does not indicate any data other than PayerID. But with PayerID, getting paymentId doesn’t work out.
You can store this value in a session and assume that the user only conducts one transaction at a time.
And you can do trickier . You can generate an id for payment and ask PayPal to include this id in ResultUrl. Like this:
Using this value, you can already find the corresponding paymentId. In principle, you can immediately transfer paymentId to RedirectUrls, but it seems to me that it is not security (although the security guard is so-so from me, maybe these values are well protected and nothing can be obtained from them).
That's all. Not as difficult as it seemed. I hope someone else comes in with this instruction.
I have a couple of open integration questions. If you can answer them, I will be grateful.
Our workflow is very simple:
- the user enters the amount, clicks the button, goes to the payment system website
- pays and returns to us by the system
- we further check the payment status and do the necessary manipulations for us.
In the end, everything worked out for me, although not without small shoals (as without them).
What do we need
- PayPal REST API SDK . I wrote on .net, but there are SDKs for many platforms, and even if not, it's REST and OAuth - you can connect without the SDK.
- API Interaction Instruction
- Interactive guide with code examples . I took the code right from there, combed it, ruled bugs, filled in the “voids” (those same jambs above).
Step 1: Set up PayPal
We go to developer.paypal.com . For this, a regular paypal account is suitable. Go to the Applications tab .
Create a new application. You should not have any difficulties. Of the important parameters: "Application return URL." This is the address to which PayPal will direct the user after payment (or cancellation). Also pay attention to Client ID and Secret. These are the keys by which the paypal will authorize us when using the api.
Next, you need to create a test account for the sandbox. Click the Sandbox accounts link to create a test user (under it we will conduct test payments). Difficulties should not arise either.
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 the project for this purpose, QuickTests). And copy the code below into it, 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 put it together and brought it to a pleasant appearance.
var sdkConfig = new Dictionary { { "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 {
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 go to approvalUrl, log in under the test account, confirm the payment, we are transferred to http: // localhost: 11180 / PayPalResult? Success = true & token = EC-DSKFJDSKFJEO42M & PayerID = DFKJDFKLGJEOR (it does not matter if you have a web server that serves 111).
We take the PayerID parameter from this URL and insert it, along with PaymentId (we received it a bit earlier), in the following code:
string payerID = "YOUR_PAYER_ID";
string paymentId = "YOUR_PAYMENT_ID";
var sdkConfig = new Dictionary { { "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". Hooray, the test is passed!
The documentation says that next we need to do Refund a sale (API reference) , but so far I have not figured out what it is.
Step 3: integrate into our application
Theoretically, there should be no problems with the integration of the code above into the application. But still I had them. This problem was associated with remembering paymentId between the two methods. Just remembering paymentId is not difficult, it is difficult to understand which of the remembered payments the current request belongs to. After all, paypal in resultUrl does not indicate any data other than PayerID. But with PayerID, getting paymentId doesn’t work out.
You can store this value in a session and assume that the user only conducts one transaction at a time.
And you can do trickier . 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}"
};
Using this value, you can already find the corresponding paymentId. In principle, you can immediately transfer paymentId to RedirectUrls, but it seems to me that it is not security (although the security guard is so-so from me, maybe these values are well protected and nothing can be obtained from them).
Conclusion
That's all. Not as difficult as it seemed. I hope someone else comes in with this instruction.
I have a couple of open integration questions. If you can answer them, I will be grateful.
- How to use the token that PayPal passes to ResultUrl. It is clear that you can somehow use it to make sure that it is 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, then the user will not see it. For me it looks weird. Maybe these are the features of the sandbox?
Answer: If you transfer the list of goods and their price, then paypal checks the order amount. more details ... - Need to deal with Refund. This seems like an important step in paying. Interestingly, if you do not refund, can the user cancel the transaction?
The answer is: "do not need to do refund (this refund), it should be called when you say you can not deliver the goods but you received the payment ..." more ... . Thanks tzlom , - What should I do if the user paid and then canceled the transaction (like PayPal allows this)? Will there be a cancel request for ResultUrl and what is the period of cancellation?
Answer: “Instant Payment Notification (IPN) will come” (thanks hannimed , more ... ) and “refund will come in your case” (thanks tzlom , more ... )