Java SDK
To create payments, you need to link your server to our platform via one of our integration methods.
Our Java SDK library is the ideal solution to connect to our platform if you prefer to do so with your own stand-alone system using Java language.
Choosing the Java SDK, you can:
- Access all functionalities of our RESTful API in a compact, convenient and customisable way.
- Use all server-sided integration methods of our platform (Hosted Checkout Page / Hosted Tokenization Page / Server-to-server).
- Make all payment processing-related API calls (i.e. CreateHostedCheckout, CreatePayment, RefundPayment and many more).
To take full advantage of this SDK, make sure you meet these requirements:
- Java 8 or higher
- Maven/Gradle
Download the newest version of Java library and follow the installation instructions. You can download and install the latest version of the Java SDK by:
- Using Maven Repository
Make sure to select the latest version. - Using Gradle
Make sure to select the latest version. - Downloading the source code of the SDK from GitHub and installing our library manually on your system.
Find more details on GitHub. Also, check out all available SDK objects and properties in our Full API Reference. Once you are all set, read the next chapters on how to prepare and use the SDK.
This guide provides a general overview on the SDK’s functionalities. To see how they precisely work for the different integration methods, see the dedicated guides explaining every step with full code samples:
Initialisation
To connect your system to our platform by using the SDK, you need to initialise it at first.
Initialising requires you to:
- Create test/live account.
- Create properties file:
onlinePayments.api.integrator=CompanyName onlinePayments.api.endpoint.host=ProperApiEndpoint # The properties below are optional and use the given values by default onlinePayments.api.endpoint.scheme=https onlinePayments.api.endpoint.port=-1 onlinePayments.api.connectTimeout=10000 onlinePayments.api.socketTimeout=10000 onlinePayments.api.maxConnections=10 onlinePayments.api.https.protocols=TLSv1.2 onlinePayments.api.authorizationType=V1HMAC
- Create an API Key and API Secret for the PSPID you wish to use for transaction processing.
- Initialise an instance of Client using the API Key / API Secret to set up the connection to our test/live platform.
After initialisation, you can start processing transactions via your PSPID. Learn how this works in the dedicated chapter.
Have a look at code samples of two connection methods covering the steps mentioned above:
- By using created properties file
private ClientInterface client; private MerchantClientInterface merchantClient; public void initialiseSdk () { URI propertiesUri = getClass().getClassLoader().getResource("paymentprovider.properties").toURI(); client = Factory.createClient(propertiesUri, "apiKey", "apiSecret"); merchantClient = client.merchant("PSPID"); }
- By using CommunicatorConfiguration
CommunicatorConfiguration communicatorConfiguration = new CommunicatorConfiguration() .withApiKeyId("apiKey") .withSecretApiKey("apiSecret") .withApiEndpoint(URI.create("apiEndpoint")) .withIntegrator("integrator") .withAuthorizationType(AuthorizationType.V1HMAC); client = Factory.createClient(communicatorConfiguration); clientMerchant = client.merchant("PSPID");
The following table provides an overview of the arguments accepted by the individual instances:
Properties |
---|
|
You can re-use a Client instance for different calls. You can use:
- The MerchantClient class object initialised in the example for all calls for that PSPID.
- The Client instance to create MerchantClients for different (or the same) PSPIDs.
After you have initialised the SDK, you can send requests to our platform via your PSPID. Learn how to do this in the next chapter .
As our SDKs always implement the latest version of our API, you can leave out "v2" in your code as shown in the example above.
Remember to pay attention to the environment you get the key set from. API Key and API Secret are different for test and live environments.
The full path of the of API endpoint for test/live environment is
- https://payment.preprod.payone.com/v2/
- https://payment.payone.com/v2/
respectively. If you are ready to switch to the live environment, substitute the endpoint link apiEndpoint = 'https://payment.preprod.payone.com/' for the live environment apiEndpoint = 'https://payment.payone.com/'
For transactions with no financial impact, use TEST-URL. The transactions will be sent to our test environment, thereby to your test account.
For transactions with a financial impact, use the LIVE-URL. The transactions will be sent to our live environment, thereby to your live account.
Use SDK
After the successful initialisation of the Client instance, you gain full access to our RESTful API. It enables you to:
- Send requests for new transactions for any of our server integration methods.
- Get your transactions’ current status.
- Perform maintenance requests (i.e., captures, refunds) on existing transactions.
Make sure that the payment method you would like to use is active in your test/live account. Check this in the Merchant Portal via Business > Payment methods.
Check out our test cases in GitHub, including full code samples, and our Full API Reference to learn what is possible.
IClient implements the IDisposable interface, allowing you to use it in using statements. This will release resources when they are no longer needed. Alternatively, we strongly suggest closing the connection manually.
ClientInterface extends the java.io.Closable interface, allowing you to use it in try-with-resources statements. This will release resources when they are no longer needed. Alternatively, we strongly suggest closing the connection manually:
client.closeIdleConnections(30, TimeUnit.MINUTES);
Below you may find some of the most common actions you can perform:
Create new transactions
To create a new transaction, you can use either the Client or MerchantClient instance for any of our integration methods to create a new transaction. It can be done through:
- Routing the request to your PSPID on our platform (for Client).
- Creating a request for the respective integration method.
The SDK instance only keeps track of the data used to initialise it. It does not track neither active sessions nor previous requests. Your system is responsible for managing PAYONE E-Payment sessions and payments.
Sessions and payments do not impact other sessions and payments.
Below you can find code samples related to particular integration methods:
Hosted Checkout Page
To use this integration method, you need to create a CreateHostedCheckoutRequest call. It must contain at least an Order object.
/*
*… Initialisation....
*/
CreateHostedCheckoutRequest checkoutRequest = new CreateHostedCheckoutRequest();
// The request with an example object of the AmountOfMoney
checkoutRequest.withOrder(new Order()
.withAmountOfMoney(new AmountOfMoney()
.withAmount(100L)
.withCurrencyCode("EUR")));
CreateHostedCheckoutResponse response = hostedCheckoutClient.createHostedCheckout(checkoutRequest);
You can specify an optional returnUrl, which will be used to redirect your customer back to your website.
This call returns a CreateHostedCheckout response. Store the hostedCheckoutId and RETURNMAC it contains, as well as any other information relevant for you. You will need these for steps described in the following chapters.
This response also contains a partialRedirectURL.
You have to concatenate the base URL "https://payment." with partialRedirectURL according to the formula
https://payment. + partialRedirectURL
and perform redirection of your customer to this URL. Once the customer visits the Hosted Checkout Page, the payment process continues there.
Hosted Tokenization Page
To use this integration method, you need to
- Create and upload a template as described in our Hosted Tokenization Page guide
CreateHostedTokenizationRequest hostedTokenizationRequest = new CreateHostedTokenizationRequest();
CreateHostedTokenizationRequest createHostedTokenizationRequest = hostedTokenizationRequest.withVariant("YourTemplate.html");
CreateHostedTokenizationResponse hostedTokenizationResponse = merchantClient.hostedTokenization()
.createHostedTokenization(createHostedTokenizationRequest);
From CreateHostedTokenizationResponse retrieve hostedTokenizationId and partialRedirectUrl. Use the partialRedirectUrl for the iframe and the hostedTokenizationId or tokenId (see infobox) to create the actual payment via Server-to-server integration method.
You can send either the tokenID or the hostedTokenizationId in your CreatePayment request. Learn more about using either option in the dedicated chapters of our Hosted Tokenization Page guide:
GetHostedTokenizationResponse getHostedTokenizationResponse = initializer.getClientMerchant().hostedTokenization().getHostedTokenization(hostedTokenizationId);
String tokenId = getHostedTokenizationResponse.getToken().getId();
// The example object of the AmountOfMoney
AmountOfMoney amount = new AmountOfMoney()
.withAmount(100L)
.withCurrencyCode("EUR");
Order order = new Order().withAmountOfMoney(amount);
CardPaymentMethodSpecificInput paymentInput = new CardPaymentMethodSpecificInput().withToken(tokenId);
CreatePaymentRequest requestBody = new CreatePaymentRequest()
.withCardPaymentMethodSpecificInput(paymentInput)
.withOrder(order);
CreatePaymentResponse response = initializer.getClientMerchant().payments().createPayment(requestBody);
You can also send the tokenID instead of the hostedTokenizationId in your CreatePayment request. Learn more about using either option in the dedicated chapters of our Hosted Tokenization Page guide:
Server-to-server
A minimum paymentResponse requires you to set at least an Order object and a payment method:
// The example object of the AmountOfMoney
AmountOfMoney amountOfMoney = new AmountOfMoney()
.withAmount(100L)
.withCurrencyCode("EUR");
Order order = new Order().withAmountOfMoney(amountOfMoney);
// To get more test card data visit the website: Find more test data here
Card card = new Card()
.withCvv("123")
.withCardNumber("5399999999999999")
.withCardholderName("Test Name")
.withExpiryDate("1236");
int paymentProductId = 3;
PaymentsClientInterface paymentClient = merchantClient.payments();
CreatePaymentRequest createPaymentRequest = new CreatePaymentRequest();
CardPaymentMethodSpecificInput cardPaymentMethodSpecificInput = new CardPaymentMethodSpecificInput();
cardPaymentMethodSpecificInput.setCard(card);
cardPaymentMethodSpecificInput.setPaymentProductId(paymentProductId) ;
createPaymentRequest.setCardPaymentMethodSpecificInput(cardPaymentMethodSpecificInput);
createPaymentRequest.setOrder(order);
CreatePaymentResponse createPaymentResponse = paymentClient.createPayment(createPaymentRequest);
We have dedicated guides for each of the aforementioned integration methods:
The documents contain all crucial details you need to profit from the integration methods full potential, including full transaction flows, code samples and other useful features.
Get transaction status
Our RESTful API allows you to request a transaction’s status anytime by one of our GET calls:
A GetPaymentDetails request looks like this:
PaymentResponse paymentResponse = merchantClient.payments().getPaymentDetails(paymentId);
Properties |
---|
string paymentId: The unique reference of your transaction on our platform. This reference can be retrieved from the CreatePaymentResponse or createHostedCheckoutResponse created in the previous section. |
For more information about statuses visit the status documentation page.
Perform maintenance operation
To perform follow-up actions on existing transactions (i.e. captures or refunds), use our CapturePayment or RefundPayment API call respectively:
CapturePayment
Make sure to use the following classes:
- CapturePaymentRequest
/*
*… Initialisation....
*/
MerchantClientInterface merchantClient;
// Here you get paymentId you can use in further code
String paymentId = createPaymentResponse.getPayment().getId();
CapturePaymentRequest capturePaymentRequest = new CapturePaymentRequest();
capturePaymentRequest.withAmount(amount);
capturePaymentRequest.setIsFinal(true);
merchantClient.payments().capturePayment(paymentId, capturePaymentRequest);
RefundPayment
Make sure to use the following classes:
- RefundRequest
- AmountOfMoney
/*
*… Initialisation....
*/
MerchantClientInterface merchantClient;
String paymentId;
RefundRequest refundRequest = new RefundRequest();
// The example object of the AmountOfMoney
AmountOfMoney amountOfMoney = new AmountOfMoney()
.withAmount(100L)
.withCurrencyCode("EUR");
refundRequest.setAmountOfMoney(amountOfMoney);
// Get RefundResponse object
RefundResponse refundResponse = merchantClient.payments().refundPayment(paymentId, refundRequest);
Properties |
---|
string paymentId: The unique reference of your transaction on our platform. This reference can be retrieved from the CreatePaymentResponse or createHostedCheckoutResponse created in the previous section. |
Handle exceptions
If a transaction is rejected, our platform provides detailed information with an Exception instance. The affiliated HTTP status code also help you troubleshoot the error.
You can encounter two types of exceptions: transaction exceptions and HTTP exceptions.
Transaction exceptions
This kind of exception refers to transaction requests that are technically correct but were rejected by your customer’s issuer or your acquirer. If the transaction is returned in the exception, it means that it was created in our systems but not successfully processed.
The following code samples use implicit methods provided as an example. You are expected to provide your own implementation for these or replace them with similar logic:
- isNotSuccessful: Check if the transaction is successful according to GetPayment properties status /statusOutput.statusCategory/status.statusCode
- handleError: Process the transaction according to its status.
Exception type / HTTP status code |
Code Sample |
---|---|
Rejected transactions / Various(see PaymentResponse object) |
|
Rejected Refund / Various(see PaymentResponse object) |
|
HTTP exceptions
This kind of exception refers to various problems caused by technical errors in the API call or payment request.
You can combine any of the following code snippets with this standard CreatePayment request:
- ApiException
/*
*…. Initialisation....
*/
CreatePaymentRequest createPaymentRequest = new CreatePaymentRequest();
// The example object of the AmountOfMoney
AmountOfMoney amountOfMoney = new AmountOfMoney()
.withAmount(100L)
.withCurrencyCode("EUR");
Order order = new Order().withAmountOfMoney(amountOfMoney);
CardPaymentMethodSpecificInput cardPaymentMethodSpecificInput = new CardPaymentMethodSpecificInput();
// The example object of the Card – you can find test cards on
// /documentation/test-cases/
Card card = new Card()
.withCvv("123")
.withCardNumber("5399999999999999")
.withCardholderName("Test Name")
.withExpiryDate("1236");
cardPaymentMethodSpecificInput.setCard(card);
cardPaymentMethodSpecificInput.setPaymentProductId(3);
createPaymentRequest.setCardPaymentMethodSpecificInput(cardPaymentMethodSpecificInput);
try {
CreatePaymentResponse createPaymentResponse = paymentClient.createPayment(createPaymentRequest);
}
catch (ApiException e) {
// Refer to the list below to see how specific implementations of ApiException can be handled.
}
Exception type / HTTP status code |
Code Sample |
---|---|
ValidationException / 400 |
|
AuthorizationException / 403 |
|
IdempotenceException / 409 |
|
ReferenceException / 404/409/410 |
|
DirectException / 500/502/503 |
|
ApiException / Any other codes |
|
CommunicationException / 300 codes without a body or non-JSON response |
|
HTTP status codes
All our exceptions are linked to one or more HTTP status codes, indicating the root cause for many possible errors.
Status code | Description | Exception type |
---|---|---|
200 | Successful |
- |
201 | Created |
- |
204 | No content |
- |
Various paymentResult key is in the response |
Payment Rejected |
DeclinedPaymentException |
Various payoutResult key is in the response |
Payout Rejected |
DeclinedPayoutException |
Various |
Refund Rejected |
DeclinedRefundException |
400 | Bad Request |
ValidationException |
403 | Not Authorised |
AuthorizationException |
404 | Not Found |
ReferenceException |
409 | Conflict
|
|
410 | Gone |
|
500 | Internal Server Error |
|
502 | Bad Gateway Our platform was unable to process a message from a downstream partner/acquirer |
|
503 | Service Unavailable The service that you are trying to reach is temporarily unavailable. Please try again later |
|
Other | Unexpected error An unexpected error has occurred |
|
Additional Features
The SDK has a lot more to offer. Have a look at the following features, as they will help you build the perfect solution.
- Get available payment methods
- Send idempotent requests
- Use logging
- Connection pooling
- Customise communication
- Webhooks
Get available payment methods
Before you initiate the actual payment process, you send a GetPaymentProducts request to our platform. The response contains a list of available payment methods in your PSPID. Depending on your customers’ preferences, you can offer a selection on our Hosted Checkout Page or on your own webshop environment using subsequent CreatePayment requests.
- GetPaymentProductsParams
/*
*…. Initialisation....
*/
// Prepare the request to get all active payment methods in your PSPID
var queryParams = new GetPaymentProductsParams()
.withCountryCode("FR")
.withCurrencyCode("EUR");
// Send the request and get the response
GetPaymentProductsResponse paymentProductResponse = merchantClient.products().getPaymentProducts(queryParams);
Send idempotent requests
One of the main REST API features is its ability to detect and prevent sending requests (i.e. payment requests) accidentally twice. The SDK makes it very easy for you to ensure that you send only unique – idempotent – requests to our platform.
Use the additional argument paymentContext and set its property named idempotence to a CreatePayment request. The SDK will send an X-GCS-Idempotence-Key header with the idempotence key as its value.
If you send requests this way to our platform, we will check the following
- If you send subsequent request with the same idempotence key, the response contains an X-GCS-Idempotence-Request-Timestamp header. The SDK will set the idempotenceRequestTimestamp property of the paymentContext argument.
- If the first request is not finished yet, the RESTful Server API returns a 409 status code. Then the SDK throws an IdempotenceException with the original idempotence key and the idempotence request timestamp.
/*
*…. Initialisation....
*/
CreatePaymentRequest createPaymentRequest = new CreatePaymentRequest();
String idempotenceKey = "YourKeyForThePayment";
var callContext = new CallContext();
callContext.withIdempotenceKey(idempotenceKey);
try {
var createPaymentResponse = merchantClient.payments().createPayment(createPaymentRequest, callContext);
} catch (IdempotenceException e) {
// a request with the same idempotenceKey is still in progress, try again after a short pause
// e.getIdempotenceRequestTimestamp() contains the value of the
// X-GCS-Idempotence-Request-Timestamp header
} finally {
Long idempotenceRequestTimestamp = callContext.getIdempotenceRequestTimestamp();
// idempotenceRequestTimestamp contains the value of the
// X-GCS-Idempotence-Request-Timestamp header
// if idempotenceRequestTimestamp is not empty, this was not the first request
}
If an idempotence key is sent for a call that does not support idempotence, the RESTful Server API will ignore the key and treat the request as a first request.
Use logging
The SDK supports logging of requests, responses, and exceptions of the API communication. These can be helpful for troubleshooting or tracing individual steps in the payment flow.
To use this logging feature, you should implement the CommunicatorLogger interface.
The SDK offers two implementations of the logging feature:
- System.out (SysOutCommunicatorLogger)
- java.util.logging.Logger (JdkCOmmunicatorLogger)
- ResourceLogger
You can enable/disable the logging by calling the enableLogging method on a ClientInterface object and provide the logger as an argument. You can subsequently disable the logger by calling the disableLogging method:
ClientInterface client = Factory.createClient(propertiesUrl.toURI(), "apiKeyId", "secretApiKey");
CommunicatorLogger logger = new JdkCommunicatorLogger(Logger.getLogger(...), Level.INFO);
client.enableLogging(logger);
//... Do some calls
client.disableLogging();
The SDK obfuscates sensitive data in the logger.
Connection pooling
You can manage your network resources by limiting the number of possible connections the SDK creates and maintains. The Client instances created as discussed in the Initialise SDK chapter will have their own connection pool. The Client instances created with the same Communicator object share a connection pool.
If you use multiple Client instances to share a single connection pool, make sure to follow these steps:
- Create a shared Communicator . You can use the com.onlinepayments.Factory class.
- Create Client instances with that Communicator.
/*
*…. Initialisation....
*/
/* Initialisation... */
// Communicator instance
Communicator communicator = Factory.createCommunicator(propertiesUrl.toURI(), "apiKeyId", "secretApiKey");
// create one or more clients using the shared communicator
ClientInterface client = Factory.createClient(communicator);
Customise communication
A ClientInterface uses a Communicator to communicate with our platform. Communicator implementations transform a request object to a HTTP request and a HTTP response to a response object. If needed, you can extend this class. To instantiate a ClientInterface that uses your own implementation of Communicator, you can use the following code snippet:
Communicator communicator = new YourCommunicator();
ClientInterface client = Factory.createClient(communicator);
Providing your own implementation is not necessary for most cases. The functionality of the com.onlinepayments.defaultimpl.DefaultCommunicator is built on classes: Authenticator, Connection, Marshaller and MetaDataProvider. The implementation of these classes can easily be extended or replaced to fit your needs.
Marshaller is used to marshal / unmarshal request and response objects to and from JSON, which you should not change. The other modules needed to communicate with the our platform are:
- The RESTful Server API endpoint URI.
- A Connection for one or more HTTP connections to our server.
- An Authenticator, to sign your requests.
- A MetaDataProvider, constructing the header with your server’s meta data.
For your convenience, the CommunicatorBuilder class is provided to easily replace one or more of these modules. For example, to instantiate a ClientInterface that uses your own implementation of Connection, you can use the following code snippet:
/*
*…. Initialisation....
*/
Connection connection = new YourConnection();
Communicator communicator = Factory.createCommunicatorBuilder(propertiesUrl.toURI(), "apiKeyId", "secretApiKey").withConnection(connection).build();
ClientInterface client = Factory.createClient(communicator);
Webhooks
The part of the SDK that handles the webhooks support is called the webhooks helper. It transparently handles both validation of signatures against the event bodies sent by the webhooks system (including finding the secret key for key IDs - not to be confused with the API Key and API Secret), and unmarshalling of these bodies to objects. This allows you to focus on the essentials, without going through all the additional information and extracting the desired ones by yourself. To learn more about webhooks, read our dedicated guide.
Provide secret keys
Configure the "WebhooksKey" / "WebhooksKeySecret" and your server webhooks endpoints in the Merchant Portal:
String keyId = "WebhooksKey";
String secretKey = "WebhooksKeySecret";
Use InMemorySecretKeyStore.INSTANCE.storeSecretKey(keyId, secretKey) to store a secret key for a key ID.
You can add or remove keys using the following functions:
- InMemorySecretKeyStore.INSTANCE.getSecretKey(keyId)
- InMemorySecretKeyStore.INSTANCE.removeSecretKey(keyId) to remove the stored secret key for a key ID.
- InMemorySecretKeyStore.INSTANCE.clear() to remove all stored secret keys.
If you require more advanced storage, e.g. using a database or file system, we recommend writing your own implementation.
Initialise webhooks helper
Using an implementation of com.onlinepayments.webhooks.SecretKeyStore, create an instance of com.onlinepayments.webhooks.WebhooksHelper:
WebhooksHelper helper = Webhooks.createHelper(InMemorySecretKeyStore. INSTANCE);
Use Webhooks helper
To process events received in a webhook, first call the unmarshal method of the WebhooksHelper object. It takes the following arguments:
-
The body, as a string. This should be the raw body as received from the webhooks system.
String bodyOfRequest = "JSON_Body_Of_The_Request";
- A list of request headers as received from the webhooks system. Below you will find an example of creating a list of request headers. It should contain the two headers for the keyId and the signature:
// Retrieve the headers from the Webhook message, depends on your implementation. List<Header> webhookHeaders = request.getHeaders(); // Transform the received headers List<RequestHeader> requestHeaders = new ArrayList<RequestHeader>(); for (Header webhookHeader : webhookHeaders) { requestHeaders.add(new RequestHeader(webhookHeader.getName(), webhookHeader.getValue())); }
- Now you can use the webhook helper to unmarshal incoming events which allow you to process data in your application:
try { WebhooksEvent event = helper.unmarshal(bodyOfRequest, requestHeaders); } catch (SignatureValidationException e) { // Your code to handle error }