Adyen Java API Library

repository·main·Indexed 40 days ago

https://github.com/adyen/adyen-java-api-library

The official Java client library for integrating with Adyen's payment and financial services APIs. Supports Java 11 or later and is available on Maven Central (version 43.1.0). Provides tools for initializing clients via API keys or Basic Auth, handling API errors with ApiException, parsing and validating notification webhooks using HMACValidator, and integrating in-person payments via the Cloud Device and Terminal APIs.

Tokens
22.8K
Snippets
37
Records
45
Agent score
50%

What's inside Adyen

  1. Cloud device API model package and naming conventions

    main

    The Cloud device API uses models generated from OpenAPI specifications located in the com.adyen.model.tapi package, whereas the Terminal (Cloud) API uses hand-crafted models in com.adyen.model.nexo.

    Key changes include:

    • Enum Naming: Most enums in the Cloud device API drop the Type suffix (e.g., MessageCategoryType becomes MessageCategory).
    • Model Renaming: Some classes are renamed to match OpenAPI specs (e.g., TransactionIdentification becomes TransactionIDType).
    • Setter/Getter Naming: Accessors for attributes starting with acronyms like POI change casing (e.g., getPOITransactionID() becomes getPoITransactionID()).
  2. Use Jackson serialization and fluent setters in Cloud device API

    main

    The Cloud device API (tapi models) uses Jackson annotations (@JsonProperty) instead of Gson. The models include built-in fromJson() and toJson() methods for easy serialization. Additionally, the tapi models support a fluent API for object construction, which is not available in the older nexo models.

    // Serialization/Deserialization
    String json = saleToPOIRequest.toJson();
    SaleToPOIRequest request = SaleToPOIRequest.fromJson(jsonString);
    
    // Fluent API for building objects
    MessageHeader messageHeader = new MessageHeader()
        .protocolVersion("3.0")
        .messageClass(MessageClass.SERVICE)
        .messageCategory(MessageCategory.PAYMENT)
        .messageType(MessageType.REQUEST)
        .saleID("001")
        .serviceID("001");
  3. Use the Local Terminal API with Encryption

    main

    For Local Terminal API integrations, you must provide encryption details and handle SSL/TLS.

    1. Setup SSL: Load the Adyen root certificate into a KeyStore, initialize a TrustManagerFactory, and create an SSLContext.
    2. Configure Client: Set the terminalApiLocalEndpoint (the terminal's IP) and provide the SSLContext and a TerminalLocalAPIHostnameVerifier to the Config object.
    3. Security Key: Create a SecurityKey object with your keyIdentifier and passphrase.
    4. Initialize Service: Use TerminalLocalAPI(client, securityKey) to make requests.
    // Import the required classes
    import com.adyen.Client;
    import com.adyen.Config;
    import com.adyen.enums.Environment;
    import com.adyen.httpclient.TerminalLocalAPIHostnameVerifier;
    import com.adyen.service.TerminalLocalAPI;
    import com.adyen.model.terminal.security.*;
    import com.adyen.model.terminal.*;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManagerFactory;
    import java.security.KeyStore;
    import java.security.SecureRandom;
    
    // Create a KeyStore for the terminal certificate
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, null);
    keyStore.setCertificateEntry("adyenRootCertificate", adyenRootCertificate);
    
    // Create a TrustManagerFactory that trusts the CAs in our KeyStore
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(keyStore);
    
    // Create an SSLContext with the desired protocol that uses our TrustManagers
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
    
    // Configure a client for TerminalLocalAPI
    Config config = new Config();
    config.setEnvironment(Environment.TEST);
    config.setTerminalApiLocalEndpoint("https://" + terminalIpAddress); // IP address of your terminal
    config.setSSLContext(sslContext);
    config.setHostnameVerifier(new TerminalLocalAPIHostnameVerifier(Environment.TEST));
    Client client = new Client(config);
    
    // Create your SecurityKey object used for encrypting the payload
    SecurityKey securityKey = new SecurityKey();
    securityKey.setKeyVersion(1);
    securityKey.setAdyenCryptoVersion(1);
    securityKey.setKeyIdentifier("keyIdentifier");
    securityKey.setPassphrase("passphrase");
    
    // Use TerminalLocalAPI
    TerminalLocalAPI terminalLocalAPI = new TerminalLocalAPI(client, securityKey);
    TerminalAPIResponse terminalAPIResponse = terminalLocalAPI.request(terminalAPIRequest);
  4. Migrate from Terminal (Cloud) API to Cloud device API

    main

    When migrating from the legacy TerminalCloudAPI to the new CloudDeviceApi, several key changes in the service layer, model packages, and data types must be addressed.

    Key Changes

    • Service Class: Replace TerminalCloudAPI with CloudDeviceApi.
    • Model Package: Move from com.adyen.model.nexo.* to com.adyen.model.tapi.*.
    • Request Structure: The CloudDeviceApi.sync() method now requires merchantAccount and deviceId as explicit parameters, rather than setting the POIID inside the MessageHeader.
    • Data Types: Many fields have transitioned from legacy types (like XMLGregorianCalendar) to modern Java types like OffsetDateTime and LocalDate.

    Implementation Example

    import com.adyen.Client;
    import com.adyen.enums.Environment;
    import com.adyen.service.clouddevice.CloudDeviceApi;
    import com.adyen.model.clouddevice.CloudDeviceApiRequest;
    import com.adyen.model.clouddevice.CloudDeviceApiResponse;
    import com.adyen.model.tapi.*;
    
    Client client = new Client("Your X-API-KEY", Environment.TEST);
    CloudDeviceApi cloudDeviceApi = new CloudDeviceApi(client);
    
    SaleToPOIRequest saleToPOIRequest = new SaleToPOIRequest();
    
    MessageHeader messageHeader = new MessageHeader()
        .protocolVersion("3.0")
        .messageClass(MessageClass.SERVICE)
        .messageCategory(MessageCategory.PAYMENT)
        .messageType(MessageType.REQUEST)
        .saleID("001")
        .serviceID("001");
    saleToPOIRequest.setMessageHeader(messageHeader);
    
    PaymentRequest paymentRequest = new PaymentRequest();
    SaleData saleData = new SaleData();
    TransactionIDType transactionIDType = new TransactionIDType()
        .transactionID("001")
        .timeStamp(OffsetDateTime.now(ZoneOffset.UTC));
    saleData.setSaleTransactionID(transactionIDType);
    
    PaymentTransaction paymentTransaction = new PaymentTransaction();
    AmountsReq amountsReq = new AmountsReq()
        .currency("EUR")
        .requestedAmount(BigDecimal.ONE);
    paymentTransaction.setAmountsReq(amountsReq);
    
    paymentRequest.setSaleData(saleData);
    paymentRequest.setPaymentTransaction(paymentTransaction);
    saleToPOIRequest.setPaymentRequest(paymentRequest);
    
    CloudDeviceApiRequest cloudDeviceApiRequest = new CloudDeviceApiRequest();
    cloudDeviceApiRequest.setSaleToPOIRequest(saleToPOIRequest);
    
    // Note: POIID is set automatically from the deviceId parameter
    CloudDeviceApiResponse response = cloudDeviceApi.sync(
        "myMerchant", "P400Plus-123456789", cloudDeviceApiRequest);
  5. Troubleshoot HMAC signature calculation with HMAC Tools

    main

    The tools/hmac directory contains scripts to calculate the HMAC signature of a webhook payload. These tools are useful for troubleshooting signature mismatches.

    Important: Ensure you use the specific HMAC key that was used to generate the signature associated with the payload in your JSON file.

    To ensure compatibility, check tools/hmac/pom.xml to confirm which version of the Adyen Java API library the tools are using.

  6. Install the Adyen Java API Library via Maven

    main

    To use the Adyen Java API library in your project, add the following dependency to your pom.xml file. Ensure you are using Java 11 or later.

    Prerequisites

    <dependency>
      <groupId>com.adyen</groupId>
      <artifactId>adyen-java-api-library</artifactId>
      <version>43.1.0</version>
    </dependency>
  7. Integrate In-person payments

    main

    To build in-person payment integrations that accept global and local payment methods, you can use either the Cloud Device API or the Terminal API.

    For In-Person Payments, the recommended approach is using the Cloud device API. Detailed usage instructions can be found in the doc/CloudDeviceApi.md file within this repository.

    Terminal API

    The Terminal API allows you to send and receive messages via two communication methods:

    • Local communications: Your POS system sends requests directly to the terminal's IP address over your local network, receiving results synchronously.
    • Cloud communications: Uses the internet to access cloud /sync and /async endpoints.

    Note: It is recommended to adopt the Cloud device API instead of using the Terminal API's cloud communication endpoints. Detailed instructions for the Terminal API are available in doc/TerminalApi.md.

  8. Secure Cloud device communication with EncryptedCloudDeviceApi

    main

    To protect communication between your integration and the cloud, use EncryptedCloudDeviceApi. This class encrypts request and response payloads.

    1. Setup: Obtain EncryptionCredentialDetails from your Terminal configuration in the Adyen Customer Area.
    2. Usage: Instantiate EncryptedCloudDeviceApi with your Client and the credentials. Use it exactly like the standard CloudDeviceApi (e.g., calling .sync()).
    3. Decryption: For asynchronous integrations, use the decryptNotification(payload) method to decrypt the JSON payload of event notifications.
    // Encryption credentials from the Terminal configuration on CA
    EncryptionCredentialDetails encryptionCredentialDetails = 
        new EncryptionCredentialDetails()
            .adyenCryptoVersion(1)
            .keyIdentifier("CryptoKeyIdentifier12345")
            .keyVersion(1)
            .passphrase("p@ssw0rd123456");
    
    // Use EncryptedCloudDeviceApi instead of CloudDeviceApi
    EncryptedCloudDeviceApi encryptedCloudDeviceApi = 
        new EncryptedCloudDeviceApi(client, encryptionCredentialDetails);
    
    CloudDeviceApiResponse response = 
        encryptedCloudDeviceApi.sync(
            "TestMerchantAccount",
            "V400m-123456789",
            cloudDeviceApiRequest);
    
    System.out.println(response);
    
    // Decrypting an async notification payload
    var payload = "...";
    var decryptedPayload = encryptedCloudDeviceApi.decryptNotification(payload);
    System.out.println(decryptedPayload);
  9. Configure a Proxy connection

    main

    To use a proxy, inject a custom AdyenHttpClient into your Client instance. If your proxy requires authentication, it is recommended to set the proxy settings as system properties rather than mixing approaches.

    // Set http proxy
    AdyenHttpClient adyenHttpClientWithProxy = new AdyenHttpClient();
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("PROXY_HOST", PROXY_PORT));
    adyenHttpClientWithProxy.setProxy(proxy);
    client.setHttpClient(adyenHttpClientWithProxy);
    
    // For authenticated proxies, use system properties:
    System.setProperty("https.proxyHost", "129.0.0.1");
    System.setProperty("https.proxyPort", "3128");
    System.setProperty("https.proxyUser", "squid");
    System.setProperty("https.proxyPassword", "ward");
    // Import the required classes
    import com.adyen.httpclient.AdyenHttpClient;
    import java.net.InetSocketAddress;
    import java.net.Proxy;
    
    // Set http proxy
    AdyenHttpClient adyenHttpClientWithProxy = new AdyenHttpClient();
    
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("PROXY_HOST", PROXY_PORT));
    adyenHttpClientWithProxy.setProxy(proxy);
    
    client.setHttpClient(adyenHttpClientWithProxy);
  10. Parse and validate Notification Webhooks

    main

    To process incoming webhooks, use the WebhookHandler to parse the JSON payload into a NotificationRequest. For security, always validate the HMAC signature using HMACValidator and the HMAC key from your Adyen Customer Area.

    Standard Webhook Parsing

    import java.util.List;
    import com.adyen.util.HMACValidator;
    import com.adyen.notification.WebhookHandler;
    import com.adyen.model.notification.NotificationRequest;
    import com.adyen.model.notification.NotificationRequestItem;
    
    // YOUR_HMAC_KEY from the Customer Area
    String hmacKey = "YOUR_HMAC_KEY";
    // The webhook payload
    String notificationRequestJson = "NOTIFICATION_REQUEST_JSON";
    
    HMACValidator hmacValidator = new HMACValidator();
    WebhookHandler webhookHandler = new WebhookHandler();
    NotificationRequest notificationRequest = webhookHandler.handleNotificationJson(notificationRequestJson);
    
    // fetch first (and only) NotificationRequestItem
    var notificationRequestItem = notificationRequest.getNotificationItems().stream().findFirst();
    
    if (notificationRequestItem.isPresent()) {
      var item = notificationRequestItem.get();
      // validate the HMAC signature
      if (hmacValidator.validateHMAC(item, hmacKey)) {
        // Process the notification based on the eventCode
        // ...
      } else {
        throw new RuntimeException("Invalid HMAC signature");
      }
    }

    Banking or Management Webhooks

    For Banking or Management webhooks, validate the signature using the hmacsignature header and the raw payload, then use the specific handler (ConfigurationWebhooksHandler or ManagementWebhooksHandler) to extract the event data.

    // Import the required classes
    import java.util.List;
    import com.adyen.util.HMACValidator;
    import com.adyen.notification.WebhookHandler;
    import com.adyen.model.notification.NotificationRequest;
    import com.adyen.model.notification.NotificationRequestItem;
    
    // YOUR_HMAC_KEY from the Customer Area
    String hmacKey = "YOUR_HMAC_KEY";
    // The webhook payload
    String notificationRequestJson = "NOTIFICATION_REQUEST_JSON";
    
    HMACValidator hmacValidator = new HMACValidator();
    
    WebhookHandler webhookHandler = new WebhookHandler();
    NotificationRequest notificationRequest = webhookHandler.handleNotificationJson(notificationRequestJson);
    
    // fetch first (and only) NotificationRequestItem
    var notificationRequestItem = notificationRequest.getNotificationItems().stream().findFirst();
    
    if (notificationRequestItem.isPresent()) {
      var item = notificationRequestItem.get();
      // validate the HMAC signature
      if (hmacValidator.validateHMAC(item, hmacKey)) {
        // Process the notification based on the eventCode
        log.info("Received webhook with event {} : \n" +
          "Merchant Reference: {}\n" +
          "Alias : {}\n" +
          "PSP reference : {}", 
          item.getEventCode(), 
          item.getMerchantReference(),
          item.getAdditionalData().get("alias"),
          item.getPspReference());
      } else {
        // Non valid NotificationRequest
        throw new RuntimeException("Invalid HMAC signature");
      }
    }
  11. Initialize the Client using Basic Authentication

    main

    You can initialize the Client using a username and password for Basic Auth. You can optionally provide a prefix and an application name.

    // Setup Client and Service passing prefix  
    Client client = new Client("YOUR_USERNAME", "YOUR_PASSWORD", Environment.LIVE, "mycompany123");
    
    // Or setup Client and Service passing prefix and application name 
    //Client client = new Client("YOUR_USERNAME", "YOUR_PASSWORD", Environment.LIVE, "mycompany123", "YOUR_APPLICATION_NAME");
    
    PaymentLinksApi paymentLinksApi = new PaymentLinksApi(client);
    // Setup Client and Service passing prefix  
    Client client = new Client("YOUR_USERNAME", "YOUR_PASSWORD", Environment.LIVE, "mycompany123");
    // Or setup Client and Service passing prefix and application name 
    //Client client = new Client("YOUR_USERNAME", "YOUR_PASSWORD", Environment.LIVE, "mycompany123", "YOUR_APPLICATION_NAME");
    
    PaymentLinksApi paymentLinksApi = new PaymentLinksApi(client);