Skip to content

micromata/paypal

Repository files navigation

PayPal JAVA Integration

PayPal integration

This document describes all the steps you need to integrate PayPal payments in your own Java application.

  1. paypal-core contains the core classes you need for your own PayPal integration. It’s not there much magic.

  2. 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.

How does the PayPal integration work?

  1. You define a payment including prices, items etc.

  2. You create this payment by publishing it to PayPal with your PayPal credentials.

  3. PayPal returns an url where to redirect the customer for processing the payment.

  4. After an successful or cancelled payment PayPal will callback your server (on success as well as after cancellation by the user).

  5. You confirm/execute the payment by calling PayPal back.

  6. Enjoy the money!

You may also refer: PayPal flow diagram of a payment

Step 1: Create PayPal credentials for your app

First you need credentials for testing and preparing your going-live.

  1. On the My Apps & Credentials page, click Log into Dashboard.

  2. 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 (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, see [get-access-token].

Step 2: Configuration of your app

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
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.

Step 3: Create PayPal sandbox account

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.

Step 4: Run PayPal server for some tests

You may start the Paypal server in your IDE or from your command line.

Starting the server from your IDE

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).

Starting the server from your command line

  1. Run gradle distZip for a ready to run server (including Unix, MacOS and Windows start scripts).

  2. Unpack the zip file (located in paypal-server/build/distributions/)

  3. Start the server in your terminal: bin/paypal-server or bin/paypal-server -f <config file>

Testing PayPal transactions

  1. After starting the server:

  2. Open your web browser: http://localhost:8142.

  3. Create some transactions by filling out the form and test the redirect to PayPal.

Step 5: Run the server on a public available host

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:

~/.paypal
...
# 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

Step 6: Do live tests

After successfully testing against PayPal’s sandbox your may want to connect to the real world by adding the following lines:

~/.paypal
# 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:

~/.paypal
# 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: ln -s .paypal-sandbox .paypal

Writing your own app

Configuration

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);

Including jar

maven:

pom.xml
<dependency>
  <groupId>de.micromata.paypal</groupId>
  <artifactId>paypal-core</artifactId>
  <version>0.2</version>
</dependency>

gradle:

gradle.build
  compile 'de.micromata.paypal:paypal-core:0.2'

Java code for payments

Step 1: Create a payment

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:
new Payment().setShipping(...).addTransaction(...)

Step 2: Add the call-backs for PayPal after the user’s payment process

See PaymentReceiveServlet and PaymentCancelServlet of module paypal-server as an example and configure these both urls in your PayPalConfig.

Step 3: Confirm/execute a payment

Place this code in your servlet which PayPal calls after a user’s successful payment:

PaymentReceiveServlet.java
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.
}

Further Java functionality

List of payments

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.

Recovering payment processes

  1. Store the payment id you get on the initial creation of a payment.

  2. 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.
}

Get an access token

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.

Miscellaneous

Why do not use BrainTree SDK?

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.

Why not do the payment in our application?

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.

Project dependencies

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 returnUrlreturn_url.