- PayPal integration
- Writing your own app
- Further Java functionality
- Miscellaneous
This document describes all the steps you need to integrate PayPal payments in your own Java application.
-
paypal-core
contains the core classes you need for your own PayPal integration. It’s not there much magic. -
paypal-server
contains a ready to run command line server including a simple web form for testing PayPal transactions (sandbox and live). It also contains two example servlets needed by PayPal to cancel or to confirm a payment.
In the end, it’s so simple:
Transaction transaction = new Transaction(Currency.EUR); // Every price in EUR
transaction.addItem("Merlin software", 29.99).addTax(5.20); // The item to sell for 29.99 EUR.
Payment = new Payment(transaction);
// Do the PayPal call and see the returned PaymentExecution object:
Payment paymentCreated = PayPalConnector.createPayment(paypalConfig, payment);
Now you’ve already created an PayPal payment in PayPal. Refer [writing-your-own-app] for a step-by-step guide for your own application.
-
You define a payment including prices, items etc.
-
You create this payment by publishing it to PayPal with your PayPal credentials.
-
PayPal returns an url where to redirect the customer for processing the payment.
-
After an successful or cancelled payment PayPal will callback your server (on success as well as after cancellation by the user).
-
You confirm/execute the payment by calling PayPal back.
-
Enjoy the money!
You may also refer: PayPal flow diagram of a payment
First you need credentials for testing and preparing your going-live.
-
On the My Apps & Credentials page, click Log into Dashboard.
-
In the REST API apps section, click Create App.
PayPal generates a set of OAuth 2.0 client_id and secret credentials for your app for both the sandbox and the live environment.
Caution
|
Keep your credentials ( |
Create a property file for testing.
For now, it’s enough to enter the client_id
and the secret
you’ve got from the previous step.
paypal.client_id=<YOUR APPLICATION CLIENT ID> paypal.secret=<YOUR APPLICATION CLIENT SECRET>
You may name this file .paypal
and place it in your user home directory. The PayPal server will detect this file
automatically. You may alternatively define any other filename and specify this filename with the command line option.
You need a sandbox account to test sandbox installations: create PayPal sandbox account
Note
|
The normal PayPal accounts aren’t valid for PayPal’s sandbox. |
You may start the Paypal server in your IDE or from your command line.
Simply execute de.micromata.paypal.PayPalMain
in your IDE (e. g. IntelliJ with installed Gradle plugin).
You may give the optional program arguments -f <config-file>
(see above).
-
Run
gradle distZip
for a ready to run server (including Unix, MacOS and Windows start scripts). -
Unpack the zip file (located in
paypal-server/build/distributions/
) -
Start the server in your terminal:
bin/paypal-server
orbin/paypal-server -f <config file>
If you run the PayPal-Server on a private host, you will be redirected to PayPal but you can’t receive any call back from PayPal. For a complete testing you should run PayPal-Server on a public available host. Please configure the urls in the configuration file by adding the following lines:
... # The urls for the PayPal test server running on ip 159.69.120.42 paypal.return_url=http:/159.69.120.42:8142/receivePayment paypal.cancel_url=http://159.69.120.42:8142/cancelPayment
After successfully testing against PayPal’s sandbox your may want to connect to the real world by adding the following lines:
# Supported modes are sandbox (default) and live: paypal.mode=live paypal.no_warranty_acceptance=<Refer the log files for the value>
Note
|
The no-warranty-acceptance is required to make clear, that this Software was developed by an enthusiastic guy thrilled by passion without any commercial intentions. Dude, you have to accept, that you use this Software at your own risk without any warranty. This Software should help you to integrate PayPal in your own application but you have to modify and test it carefully. |
Don’t forget to replace the values paypal.client-id
and paypal.secret
by the live credentials of PayPal.
A final live complete configuration looks like:
# Supported modes are sandbox (default) and live: paypal.mode=live paypal.no_warranty_acceptance=I CONFIRM... paypal.client_id=<your client id> paypal.secret=<your client secret> # return url called by Paypal after successful payments: paypal.return_url=http://159.69.120.42:8142/receivePayment # cancel url called by Paypal after cancelled payments: paypal.cancel_url=http://159.69.120.42:8142/cancelPayment
Note
|
For dealing with both configurations (sandbox and live) on the same system, create both configuration files and
work e. g. with symbolic links you can easily switch: |
You may use the PayPal configuration file from above or alternatively it’s also possible to do the config stuff in the Java code yourself.
PayPalConfig payPalConfig = new PayPalConfig()
.setClientId("<client_id>").setClientSecret("<secret>")
.setReturnUrl("<return url>").setCancelUrl("<cancel url>")
.setMode(PayPalConfig.Mode.SANDBOX);
Or load the properties from a properties file:
File configFile = new File(System.getProperty("user.home"), ".paypal");
paypalConfig = new PayPalConfig().read(file);
<dependency>
<groupId>de.micromata.paypal</groupId>
<artifactId>paypal-core</artifactId>
<version>0.2</version>
</dependency>
Transaction transaction = new Transaction(Currency.EUR); // Every price in EUR
transaction.addItem("My software", 29.99).addTax(5.20); // Item to sell for 29.99 plus optional tax.
transaction.setInoviceNumber("1234"); // Must be unique, can't be used twice.
Payment payment = new Payment(transaction); // A payment has transaction(s).
payment.setNoteToPayer("Please contact ..."); // Note to payer for important messages.
payment.setShipping(ShippingPreference.NO_SHIPPING); // Don't prompt the user for a shipping address.
// Do the PayPal call and see the returned PaymentExecution object:
Payment paymentCreated = PayPalConnector.createPayment(paypalConfig, payment);
// You should save PayPal's original response json object e. g. in your database:
database.save(paymentCreated.getOriginalPayPalResponse()); // optional but recommended.
if (paymentCreated != null) {
String redirectUrl = paymentCreated.getPayPalUrlForUserPayment();
response.sendRedirect(redirectUrl); // Redirect the user to the PayPal site.
}
redirectUrl
contains the link where to redirect the user for proceeding with the payment.
Through the API you may configure
more complex shopping carts including shipping costs etc.
Note
|
This PayPal library supports chaining for creating objects and setting properties, such as: |
See PaymentReceiveServlet
and PaymentCancelServlet
of module paypal-server as an example and configure these both
urls in your PayPalConfig.
Place this code in your servlet which PayPal calls after a user’s successful payment:
String paymentId = request.getParameter("paymentId"); // Request parameter given by PayPal
String payerId = request.getParameter("PayerID");
Payment paymentExecuted = PayPalConnector.executePayment(config, paymentId, payerId);
if (paymentExecuted != null) {
// You should save PayPal's original response json object e. g. in your database:
database.save(paymentCreated.getOriginalPayPalResponse()); // optional but recommended.
// paymentExecuted contains all information related to the PayPal payment:
// payer, transaction, items, amounts, refund urls, time stamps etc.
}
You may get a list of payments with pagination, see https://developer.paypal.com/docs/api/payments/v1/#payment_list.
PaymentRequestFilter filter = new PaymentRequestFilter();
Payments payments = PayPalConnector.listPayments(config, filter);
...
Optional you may filter your payments by setting the desired fields of the filter
object.
-
Store the payment id you get on the initial creation of a payment.
-
You may query this payment by this id later for detecting the state of this payment and to continue the next required step:
Payment payment = PayPalConnector.getPaymentDetails(config, paymentId);
if (payment.getState() == State.CREATED) {
// Redirect the user to PayPal's payment process.
String redirectUrl = payment.getPayPalApprovalUrl();
response.sendRedirect(redirectUrl);
} else if (payment.getState() == State.APPROVED) {
// Payment is approved by the user. If not yet executed, try to execute this payment (again):
PayPalConnector.executePayment(config, paymentId, payerId);
} else if (payment.getState() == State.FAILED) {
// We have to re-create a new payment, if the user still wants to pay.
}
Keep your credentials (client_id
and secret
) secret! Never ever include any credential value in your web page!
If you need to do a PayPal call direct inside your web page, get an access token from the server first and then use this
temporarily valid access token for authentification:
// Gets a temporarily access token to use instead of secret credentials e. t. in your web page code:
AccessTokenResponse accessTokenResponse = PayPalConntector.getAccessToken(payPalConfig);
String accessToken = accessTokenResponse.getAccessToken();
The object AccessTokenResponse
holds also the expire time. An AccessToken is initially valid for 9h. If you try to get
a new access token during this time you will receive the same token.
The BrainTree SDK seems to be behind the API. I wasn’t able to set the flag NO_SHIPPING
and the BrainSDK doesn’t care about
any field restrictions (such as minimum and maximum field length or supported field values).
If you miss some functionality feel free to extend this module. It’s very easy to extend calls and POJOs.
It took only less than an effort of one day to replace BrainSDK by an own implementation for the whole payment process.
This integration let PayPal do the payment approval. The advantage of this approach is that you
don’t have to care about your customers credit cards etc. You never get any credit card or payment credentials from
your customers.
The customers trust more in PayPal. Especially if your application is a new one, your customers maybe don’t trust in your
system and they don’t want to enter their credit card number etc. in your application.
In Europe this approach is more friendly regarding the GDPR (General Data Protection Regulation) or the German DSGVO
(Datenschutzgrundverordnung) established in 2018.
If you want to embed the whole payment process inside your application later, simply use the BrainTree SDK because PayPal has some restrictions in its API when you don’t use the BrainTree SDK.
This PayPal library is designed with a minimal set of dependencies for a light weight integration in your own app:
Library | Version | Usage |
---|---|---|
org.slf4j:slf4j-api |
1.7.25 |
Common logging wrapper for compatibility with your logging framework (java logger, log4j etc.) |
com.fasterxml.jackson.core:jackson-core |
2.9.7 |
Needed for json serialization and deserialization. |
com.fasterxml.jackson.core:jackson-annotations |
2.9.7 |
ibid. |
com.fasterxml.jackson.core:jackson-databind |
2.9.7 |
ibid. |
Jackson is used because Gson seems not to be enough flexible for serializing and deserializing synthetic fields (such
as calculated amounts in transactions). Gson works only on field level, Jackson as well on getter methods level.
Jackson also supports annotations to name serialized fields different from the Java
convention: e. g. field returnUrl
→ return_url
.