# Using OpenAPI for BPS End to End
source: https://developer.mastercard.com/mastercard-buyer-payment-agent/documentation/tutorials_guides/tutorials/connect-to-the-bps-using-open-api/index.md

## Overview {#overview}

This tutorial explains how to generate a simple client application to consume the BPS API. This tutorial also includes steps to integrate with Mastercard's OAuth 1.0 authentication and authorization flow.

### You will learn how to {#you-will-learn-how-to}

* Generate a REST client from an OpenAPI/Swagger specification
* Sign requests using our OAuth 1.0a signer libraries
* Encrypt and decrypt the payload using Mastercard libraries

### What you will need {#what-you-will-need}

Before starting this tutorial, ensure that you have completed the following:

* Supplied your Mastercard representative with your Buyers.
* Created your project and retrieved the required credentials by following this [guide](https://developer.mastercard.com/mastercard-buyer-payment-agent/documentation/tutorials_guides/guides/impl-guide/index.md).
* Shared your consumer key with your Mastercard representative and received confirmation that you were onboarded to MTF.

## Steps {#steps}

### 1. Download the BPS OpenAPI/Swagger File {#1-download-the-bps-openapiswagger-file}

Open the Buyer Payment Agent Swagger definition [here](https://developer.mastercard.com/mastercard-buyer-payment-agent/documentation/api-reference/index.md).

Download the swagger definition file in YAML format.

### 2. Generate the client {#2-generate-the-client}

Mastercard has provided a generic tutorial that you can follow to generate an Open API client. Refer to
[Generating an Open API Client](https://developer.mastercard.com/platform/documentation/generating-and-configuring-a-mastercard-api-client/).

The tutorial is based on Java but you can find further tutorials for all six supported languages on [Github](https://github.com/Mastercard/mastercard-api-client-tutorial).
For more information about swagger-codegen and more options, please refer to the official page on [GitHub](https://github.com/OpenAPITools/openapi-generator).

### 3. Set up your Maven Dependencies {#3-set-up-your-maven-dependencies}

Your pom.xml file will have two entries:
* JAVA

```JAVA
<dependencies>

  <dependency>
    <groupId>com.mastercard.developer</groupId>
    <artifactId>oauth1-signer</artifactId>
    <version>1.4.0</version>
  </dependency>
  <dependency>
    <groupId>com.mastercard.developer</groupId>
    <artifactId>client-encryption</artifactId>
    <version>1.4.0</version>
  </dependency>
  <dependency>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-cli</artifactId>
    <version>4.3.1</version>
  </dependency>
  <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.1.0</version>
  </dependency>
  <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.4</version>
  </dependency>
  <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>logging-interceptor</artifactId>
    <version>3.11.0</version>
  </dependency>
  <dependency>
    <groupId>io.gsonfire</groupId>
    <artifactId>gson-fire</artifactId>
    <version>1.8.0</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.1</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.11.1</version>
  </dependency>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
  </dependency>

  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>3.8.1</version>
    <scope>test</scope>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
      </configuration>
    </plugin>
    <plugin>
      <groupId>org.openapitools</groupId>
      <artifactId>openapi-generator-maven-plugin</artifactId>
      <version>4.3.1</version>
      <executions>
        <execution>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>
            <inputSpec>${project.basedir}/src/main/resources/track_bps_bpa_service.yaml</inputSpec>
            <generatorName>java</generatorName>
            <library>okhttp-gson</library>
            <generateApiTests>false</generateApiTests>
            <generateModelTests>false</generateModelTests>
            <generateApiTests>false</generateApiTests>
            <configOptions>
              <sourceFolder>src/gen/java/main</sourceFolder>
              <groupId>com.mastercard.developer</groupId>
              <artifactId>track-bps-bpa-client</artifactId>
              <invokerPackage>com.mastercard.developer.track-bps-bpa-client</invokerPackage>
              <apiPackage>com.mastercard.developer.track-bps-bpa-client.api</apiPackage>
              <modelPackage>com.mastercard.developer.track-bps-bpa-client.model</modelPackage>
              <dateLibrary>java8</dateLibrary>
              <java8>true</java8>
            </configOptions>
          </configuration>
        </execution>
      </executions>
    </plugin>

  </plugins>
</build> 

```

Note: Make sure to configure ${project.basedir}/src/main/resources/track_bps_bpa_service.yaml

To generate the data models, ensure you have the following configuration setup in the Maven pom file:
* JAVA

```JAVA
<configuration>
            <inputSpec>${project.basedir}/src/main/resources/track_bps_bpa_service.yaml</inputSpec>
            <generatorName>java</generatorName>
            <library>okhttp-gson</library>
            <generateApiTests>false</generateApiTests>
            <generateModelTests>false</generateModelTests>
            <generateApiTests>false</generateApiTests>
            <configOptions>
              <sourceFolder>src/gen/java/main</sourceFolder>
              <groupId>com.mastercard.developer</groupId>
              <artifactId>track-bps-bpa-client</artifactId>
              <invokerPackage>com.mastercard.developer.track-bps-bpa-client</invokerPackage>
              <apiPackage>com.mastercard.developer.track-bps-bpa-client.api</apiPackage>
              <modelPackage>com.mastercard.developer.track-bps-bpa-client.model</modelPackage>
              <dateLibrary>java8</dateLibrary>
              <java8>true</java8>
            </configOptions>
          </configuration>
```

### 4. Configure and call the Buyer Payment Agent APIs {#4-configure-and-call-the-buyer-payment-agent-apis}

#### Configurations Class {#configurations-class}

Update your configuration.
* JAVA

```JAVA
public class BPSConfig {

    public static String SERVICE_BASE_URL="https://sandbox.api.mastercard.com/track/bps";
    
    // OAUTH Signing Key configurations
    public static String SIGNING_P12_PATH = "./src/main/resources/<REPLACE-ME>.p12";
    public static String SIGNING_CONSUMER_KEY = "<REPLACE-ME>";
    public static String SIGNING_KEY_ALIAS = "<REPLACE-ME>";
    public static String SIGNING_KEY_STORE_PASSWORD = "<REPLACE-ME>";

    // Client Encryption (For encrypting payload)
    public static String CLIENT_ENCRYPTION_CERTIFICATE = "./src/main/resources/<REPLACE-ME>.pem";

    // Mastercard Encryption Key configuration (For Decrypting payload)
    public static String MASTERCARD_ENCRYPTION_P12_PATH="./src/main/resources/<REPLACE-ME>.p12";
    public static String MASTERCARD_ENCRYPTION_KEY_ALIAS="<REPLACE-ME>";
    public static String MASTERCARD_ENCRYPTION_KEY_STORE_PASSWORD="<REPLACE-ME>";

    // Configure CardPayment Request - INVOICE
    public static String INVOICE_CUSTOMER_NUMBER="<REPLACE-ME>";
    public static String INVOICE_ADJUSTMENT_AMOUNT="<REPLACE-ME>";
    public static String INVOICE_ADJUSTMENT_CODE="<REPLACE-ME>";
    public static String INVOICE_AMOUNT="<REPLACE-ME>";
    public static String INVOICE_DATE="<REPLACE-ME>";
    public static String INVOICE_REFERENCE_ID="<REPLACE-ME>";

    // Configure CardPayment Request - CARD
    public static String CARD_NAME_ON_CARD="<REPLACE-ME>";
    public static String CARD_NUMBER="<REPLACE-ME>";
    public static String CARD_EXPIRY_MONTH="<REPLACE-ME>";
    public static String CARD_EXPIRY_YEAR="<REPLACE-ME>";
    public static String CARD_CVV="<REPLACE-ME>";

    // Configure CardPayment Request
    public static String BUYER_ID="<REPLACE-ME>@track";
    public static String SUPPLIER_ID="<REPLACE-ME>@track";
    public static String CURRENCY="<REPLACE-ME>";
    public static String TOTAL_AMOUNT="<REPLACE-ME>";

 
```

#### Call the API {#call-the-api}

Finally, the following code shows how to call the Get Payment Instructions endpoint. If you have successfully connected, it will return the payment instruction details.

Follow the code level comments to get more details on OAuth signing and encryption.
* JAVA

```JAVA
public class BuyerPaymentAgentOpenApi {

    public static final Logger log = LoggerFactory.getLogger(BuyerPaymentAgentOpenApi.class);

    // Note : Enabling or disabling encryption.
    private static boolean enableEncryption = true;

    // Note : Please add jackson ObjectMapper dependency.
    private static ObjectMapper objectMapper = new ObjectMapper();

    public static void main(String[] args) throws Exception{

        try{
            buildObjectMapper();

            // Post Payment-Instruction
            PaymentResponse paymentResponse = postPaymentInstruction();
            log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(paymentResponse));
            // Uncomment below statement in case if you want see output on the console.
 //System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(paymentResponse));

            // Get Payment-Instruction
            CardPaymentResponse cardPaymentResponse =getPaymentInstruction(paymentResponse.getPaymentId());
            log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(cardPaymentResponse));
            // Uncomment below statement in case if you want see output on the console.
 //System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(cardPaymentResponse)); 
 
        }catch (Exception ex){
            handleException(ex);
        }

    }

    public static PaymentResponse postPaymentInstruction() throws Exception {
        CardPayment cardPayment = buildCardPayment();
        BuyerPaymentAgentsApi api = new BuyerPaymentAgentsApi(signRequest(enableEncryption));
        ApiResponse<PaymentResponse> responseWithHttpInfo = api.buyerAgentsPaymentInstructionsPostWithHttpInfo(cardPayment);
        return responseWithHttpInfo.getData();
    }

    public static CardPaymentResponse getPaymentInstruction(String paymentId) throws Exception{
        BuyerPaymentAgentsApi api = new BuyerPaymentAgentsApi(signRequest(enableEncryption));
        ApiResponse<CardPaymentResponse> responseWithHttpInfo = api.cardPaymentGetWithHttpInfo(paymentId);
        return responseWithHttpInfo.getData();
    }


    public static ApiClient signRequest(Boolean enableEncryption) throws Exception {
        ApiClient client = new ApiClient();
        client.setBasePath(BPSConfig.SERVICE_BASE_URL);

        if(enableEncryption){
            client.setHttpClient(
                    client.getHttpClient()
                            .newBuilder()
                            .addInterceptor(new OkHttpFieldLevelEncryptionInterceptor(getEncryptionConfig()))
                            .addInterceptor(new OkHttpOAuth1Interceptor(BPSConfig.SIGNING_CONSUMER_KEY, getSigningKey()))
                            .build()
            );
        }else{
            client.setHttpClient(
                    client.getHttpClient()
                            .newBuilder()
                            .addInterceptor(new OkHttpOAuth1Interceptor(BPSConfig.SIGNING_CONSUMER_KEY, getSigningKey()))
                            .build()
            );
        }
        return client;
    }

    // Getting OAuth1.0 signing key
    private static PrivateKey getSigningKey() throws Exception {
        return AuthenticationUtils.loadSigningKey(BPSConfig.SIGNING_P12_PATH,
                BPSConfig.SIGNING_KEY_ALIAS, BPSConfig.SIGNING_KEY_STORE_PASSWORD);
    }

    // Encryption configuration.
    private static FieldLevelEncryptionConfig getEncryptionConfig() throws Exception {
        Certificate encryptionCertificate = EncryptionUtils.loadEncryptionCertificate(BPSConfig.CLIENT_ENCRYPTION_CERTIFICATE);
        PrivateKey decryptionKey = EncryptionUtils.loadDecryptionKey(BPSConfig.MASTERCARD_ENCRYPTION_P12_PATH, BPSConfig.MASTERCARD_ENCRYPTION_KEY_ALIAS, BPSConfig.MASTERCARD_ENCRYPTION_KEY_STORE_PASSWORD);

        return FieldLevelEncryptionConfigBuilder.aFieldLevelEncryptionConfig()
                .withEncryptionCertificate(encryptionCertificate)
                .withDecryptionKey(decryptionKey)
                .withEncryptionPath("$.card", "$.encryptedCard")
                .withDecryptionPath("$.encryptedCard", "$.card")
                .withOaepPaddingDigestAlgorithm("SHA-256")
                .withEncryptedValueFieldName("encryptedValue")
                .withEncryptedKeyFieldName("encryptedKey")
                .withIvFieldName("iv")
                .withOaepPaddingDigestAlgorithmFieldName("oaepPaddingDigestAlgorithm")
                .withEncryptionKeyFingerprintFieldName("publicKeyFingerprint")
                .withFieldValueEncoding(FieldLevelEncryptionConfig.FieldValueEncoding.BASE64)
                .build();
    }

    private static CardPayment buildCardPayment() {
        Invoice invoice1 = new Invoice()
                .customerNumber(BPSConfig.INVOICE_CUSTOMER_NUMBER)
                .adjustmentAmount(BPSConfig.INVOICE_ADJUSTMENT_AMOUNT)
                .adjustmentCode(BPSConfig.INVOICE_ADJUSTMENT_CODE)
                .amount(BPSConfig.INVOICE_AMOUNT)
                .date(BPSConfig.INVOICE_DATE)
                .referenceId(BPSConfig.INVOICE_REFERENCE_ID);

        List<Invoice> invoiceList =  Arrays.asList(invoice1);

        Card card  = new Card()
                .nameOnCard(BPSConfig.CARD_NAME_ON_CARD)
                .number(BPSConfig.CARD_NUMBER)
                .expMonth(BPSConfig.CARD_EXPIRY_MONTH)
                .expYear(BPSConfig.CARD_EXPIRY_YEAR)
                .cvv(BPSConfig.CARD_CVV);

        return new CardPayment()
                .buyerId(BPSConfig.BUYER_ID)
                .supplierId(BPSConfig.SUPPLIER_ID)
                .currency(BPSConfig.CURRENCY)
                .totalAmount(BPSConfig.TOTAL_AMOUNT)
                .invoices(invoiceList)
                .card(card);
    }

    private static void buildObjectMapper() {
    objectMapper.registerModule(new JavaTimeModule());
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
    objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
    objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
    objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
}

    public static void handleException(Exception ex) throws Exception{
    if(ex instance of ApiException){
        ApiException apiException = (ApiException) ex;
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        Error error = gson.fromJson(apiException.getResponseBody(),Error.class);
        log.error(gson.toJson(error));

    }else {
        ErrorErrorsError standardError = getErrorErrorsError(ex);
        ErrorErrors standardErrorHeader = getErrorErrors(standardError);
        Error error = new Error();
        error.setErrors(standardErrorHeader);
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        log.error(gson.toJson(error));
    }
}

    private static ErrorErrors getErrorErrors(ErrorErrorsError standardError) {
        List<ErrorErrorsError> errorList = new ArrayList<>();
        errorList.add(standardError);
        ErrorErrors standardErrorHeader = new ErrorErrors();
        standardErrorHeader.error(errorList);
        return standardErrorHeader;
    }

    private static ErrorErrorsError getErrorErrorsError(Exception ex) {
        ErrorErrorsError standardError = new ErrorErrorsError();
        standardError.setSource("REFERENCE_IMPLEMENTATION");
        standardError.setReasonCode("UNKNOWN");
        standardError.setDescription(ex.getMessage());
        standardError.setDetails(ExceptionUtils.getStackTrace(ex));
        standardError.setRecoverable(false);
        return standardError;
    }
}
 
```

To encrypt or decrypt the payload, set the configuration to:
* JAVA

```JAVA
// Encryption configuration.
    private static FieldLevelEncryptionConfig getEncryptionConfig() throws Exception {
        Certificate encryptionCertificate = EncryptionUtils.loadEncryptionCertificate(BPSConfig.CLIENT_ENCRYPTION_CERTIFICATE);
        PrivateKey decryptionKey = EncryptionUtils.loadDecryptionKey(BPSConfig.MASTERCARD_ENCRYPTION_P12_PATH, BPSConfig.MASTERCARD_ENCRYPTION_KEY_ALIAS, BPSConfig.MASTERCARD_ENCRYPTION_KEY_STORE_PASSWORD);

        return FieldLevelEncryptionConfigBuilder.aFieldLevelEncryptionConfig()
                .withEncryptionCertificate(encryptionCertificate)
                .withDecryptionKey(decryptionKey)
                .withEncryptionPath("$.card", "$.encryptedCard")
                .withDecryptionPath("$.encryptedCard", "$.card")
                .withOaepPaddingDigestAlgorithm("SHA-256")
                .withEncryptedValueFieldName("encryptedValue")
                .withEncryptedKeyFieldName("encryptedKey")
                .withIvFieldName("iv")
                .withOaepPaddingDigestAlgorithmFieldName("oaepPaddingDigestAlgorithm")
                .withEncryptionKeyFingerprintFieldName("publicKeyFingerprint")
                .withFieldValueEncoding(FieldLevelEncryptionConfig.FieldValueEncoding.BASE64)
                .build();
    }
 
```

To sign the payload using the Oauth signer library, configure the following:
* JAVA

```JAVA
 public static ApiClient signRequest(Boolean enableEncryption) throws Exception {
        ApiClient client = new ApiClient();
        client.setBasePath(BPSConfig.SERVICE_BASE_URL);

        if(enableEncryption){
            client.setHttpClient(
                    client.getHttpClient()
                            .newBuilder()
                            .addInterceptor(new OkHttpFieldLevelEncryptionInterceptor(getEncryptionConfig()))
                            .addInterceptor(new OkHttpOAuth1Interceptor(BPSConfig.SIGNING_CONSUMER_KEY, getSigningKey()))
                            .build()
            );
        }else{
            client.setHttpClient(
                    client.getHttpClient()
                            .newBuilder()
                            .addInterceptor(new OkHttpOAuth1Interceptor(BPSConfig.SIGNING_CONSUMER_KEY, getSigningKey()))
                            .build()
            );
        }
        return client;
    }

    // Getting OAuth1.0 signing key
    private static PrivateKey getSigningKey() throws Exception {
        return AuthenticationUtils.loadSigningKey(BPSConfig.SIGNING_P12_PATH,
                    BPSConfig.SIGNING_KEY_ALIAS, BPSConfig.SIGNING_KEY_STORE_PASSWORD);
    }
```

##### Submit Payment Instruction Response {#submit-payment-instruction-response}

At this point, you should have successfully integrated with BPS. If you integrated with BPS by initiating a payment instruction, our response could look something like this:
* JSON

```JSON
{
  "paymentId" : "T-C20-822-43A-C6B-3AH-UW6-O",
  "status" : "RECEIVED",
  "description" : null,
  "createdDate" : "2020-07-24T15:47:04.812Z",
  "updatedDate" : "2020-07-24T15:47:04.812Z"
}
 
```

##### Get Payment Instruction Response {#get-payment-instruction-response}

If you integrated with BPS by retrieving a payment instruction request, you should get a response similar to this:
* JSON

```JSON
{
  "paymentId" : "T-C20-822-43A-C6B-3AH-UW6-O",
  "status" : "NOTIFIED",
  "description" : null,
  "supplierId" : "xyz@track",
  "totalAmount" : 7000,
  "currency" : "USD",
  "invoices" : [ {
    "referenceId" : "INV-20185",
    "date" : "2020-01-02",
    "amount" : "10000",
    "adjustmentAmount" : "3000",
    "adjustmentCode" : "INCORRECT_AMOUNT",
    "customerNumber" : "test-19"
  } ],
  "messages" : [ ],
  "card" : {
    "number" : "5149612222222220",
    "nameOnCard" : "Virtual Card",
    "expMonth" : "11",
    "expYear" : "2025",
    "cvv" : "114"
  },
  "encryptedCard" : null,
  "createdDate" : "2020-07-24T15:47:04.812Z",
  "updatedDate" : "2020-07-24T15:47:05.017Z",
  "buyerId" : "abc.pay@track"
}
 
```

