Integration

The Gini Pay Bank SDK has two main features: capturing invoices for information extraction and handling payment requests. Both can be used independently and you may opt to use only one or both in your app.

Capturing Invoices

The capture feature uses our Gini Capture SDK to provide Activities and Fragments to capture invoices and prepare them for upload to the Gini Pay API. It also allows documents to be imported from other apps. The captured images can be reviewed and are optimized on the device to provide the best results when used with the Gini Pay API.

Android Manifest

The capture feature of the SDK uses the camera therefore the camera permission is required:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="...">

    <uses-permission android:name="android.permission.CAMERA" />

</manifest>

Note

Make sure you request the camera permission before starting the SDK.

Requirements Check

We recommend running our runtime requirements check first before launching the Gini Capture SDK to ensure the device is capable of taking pictures of adequate quality.

Simply run GiniPayBank.checkCaptureRequirements() and inspect the returned RequirementsReport for the result:

Note

On Android 6.0 and later the camera permission is required before checking the requirements.

final RequirementsReport report = GiniPayBank.checkCaptureRequirements((Context) this);
if (!report.isFulfilled()) {
    final StringBuilder stringBuilder = new StringBuilder();
    report.getRequirementReports().forEach(requirementReport -> {
        if (!requirementReport.isFulfilled()) {
            stringBuilder.append(requirementReport.getRequirementId());
            stringBuilder.append(": ");
            stringBuilder.append(requirementReport.getDetails());
            stringBuilder.append("\n");
        }
    });
    Toast.makeText(this, "Requirements not fulfilled:\n" + stringBuilder,
            Toast.LENGTH_LONG).show();
}

Configuration

Configuration and interaction is done using CaptureConfiguration. To set the configuration use the GiniPayBank.setCaptureConfiguration() static method.

Important

The configuration is immutable and make sure to call GiniPayBank.releaseCapture() before setting a new configuration.

You should call GiniPayBank.releaseCapture() after the SDK returned control to your application and your app has sent feedback to the Gini Pay API and is not using the capture feature anymore.

To view all the configuration options see the documentation of CaptureConfiguration.

Information about the configurable features are available on the Capture Features page.

Tablet Support

The Gini Pay Bank SDK can be used on tablets, too. Some UI elements adapt to the larger screen to offer the best user experience for tablet users.

Many tablets with at least 8MP cameras don’t have an LED flash. Therefore we don’t require flash for tablets. For this reason the extraction quality on those tablets might be lower compared to smartphones.

On tablets landscape orientation is also supported (smartphones are portrait only). We advise you to test your integration on tablets in both orientations.

In landscape the camera screen’s UI displays the camera trigger button on the right side of the screen. Users can reach the camera trigger more easily this way. The camera preview along with the document corner guides are shown in landscape to match the device’s orientation.

Other UI elements on all the screens maintain their relative position and the screen layouts are scaled automatically to fit the current orientation.

Networking

The Gini Pay Bank SDK allows you to use the default networking implementation of our Gini Capture SDK to communicate with the Gini Pay API. You may also implement your own networking layer.

Note

You should have received Gini Pay API client credentials from us. Please get in touch with us in case you don’t have them. Without credentials you won’t be able to use the Gini Pay API.

Default Implementation

The capture feature is not aware of any networking implementations and requires you to set them in the CaptureConfiguration.

The default networking implementations are the GiniCaptureDefaultNetworkService and GiniCaptureDefaultNetworkApi. We provide you with two helper methods to create them with the minimal configuration:

val networkService = getDefaultNetworkService(
    context = this,
    clientId = myClientId,
    clientSecret = myClientSecret,
    emailDomain = myEmailDomain,
    documentMetadata = myDocumentMetadata
)

val networkApi = getDefaultNetworkApi(networkService)

GiniPayBank.setCaptureConfiguration(
    CaptureConfiguration(
        networkService = networkService,
        networkApi = networkApi
    )
)

For all configuration options of the default networking implementation see the documentation of GiniCaptureDefaultNetworkService.Builder and GiniCaptureDefaultNetworkApi.Builder.

Custom Implementation

You can also provide your own networking by implementing the GiniCaptureNetworkService and the GiniCaptureNetworkApi interfaces:

  • GiniCaptureNetworkService
    This interface is used to upload, analyze and delete documents. See the reference documentation for details.
  • GiniCaptureNetworkApi
    This interface is used to declare network tasks which should be called by you outside of the Gini Capture SDK (e.g., for sending feedback after the user saw and potentielly corrected the extractions). See the reference documentation for details.

You may also use the Gini Pay API Library for Android or implement communication with the Gini API yourself.

Sending Feedback

Your app should send feedback for the extractions the Gini Pay API delivered. Feedback should be sent only for the extractions the user has seen and accepted (or corrected).

For addition information about feedback see the Gini Pay API documentation.

Default Implementation

The example below shows how to correct extractions and send feedback using the default networking implementation:

val networkApi: GiniCaptureDefaultNetworkApi // Provided

val extractions: Map<String, GiniCaptureSpecificExtraction> // Provided

// Modify the amount to pay extraction's value.
GiniCaptureSpecificExtraction amountToPay = extractions["amountToPay"];
amountToPay.value = "31.00:EUR"

// You should send feedback only for extractions the user has seen and accepted.
// In this example only the amountToPay was wrong and we can reuse the other extractions.
 val feedback = mapOf<String, GiniCaptureSpecificExtraction>(
     "iban" to mExtractions["iban"],
     "amountToPay" to amountTopay,
     "bic" to mExtractions["bic"],
     "senderName" to mExtractions["sencerName"]
 )

 networkApi.sendFeedback(feedback, object : GiniCaptureNetworkCallback<Void, Error> {
     override fun failure(error: Error) {
         // Handle the error.
     }

     override fun success(result: Void?) {
         // Feedback sent successfully.
     }

     override fun cancelled() {
         // Handle cancellation.
     }
 })
Custom Implementation

If you use your own networking implementation and directly communicate with the Gini Pay API then see this section in its documentation on how to send feedback.

In case you use the Gini Pay API Library then see this section in its documentation for details.

Capture Flow

The capture flow can be used in two ways, either by using the Screen API or the Component API:

  • The Screen API provides activities for easy integration that can be customized in a limited way. The screen and configuration design is based on our long-lasting experience with integration in customer apps.
  • In the Component API we provide fragments for advanced integration with more freedom for customization.

Screen API

This is the easiest way to use the capture flow. You only need to:

  1. Request camera access,
  2. Configure the capture feature using the CaptureConfiguration,
  3. Register an activity result handler with the CaptureFlowContract(),
  4. Start the capture flow.

Note

Check out the Screen API example app to see how an integration could look like.

The following example shows how to launch the capture flow using the Screen API and how to handle the results:

// Use the androidx's Activity Result API to register a handler for the capture result.
val captureLauncher = registerForActivityResult(CaptureFlowContract()) { result: CaptureResult ->
    when (result) {
        is CaptureResult.Success -> {
            handleExtractions(result.specificExtractions)
        }
        is CaptureResult.Error -> {
            when (result.value) {
                is ResultError.Capture -> {
                    val captureError: GiniCaptureError = (result.value as ResultError.Capture).giniCaptureError
                    handleCaptureError(captureError)
                }
                is ResultError.FileImport -> {
                    // See the File Import section on the Capture Features page for more details.
                    val fileImportError = result.value as ResultError.FileImport
                    handleFileImportError(fileImportError)
                }
            }
        }
        CaptureResult.Empty -> {
            handleNoExtractions()
        }
        CaptureResult.Cancel -> {
            handleCancellation()
        }
    }
}

fun launchGiniCapture() {
    // Make sure camera permission has been already granted at this point.

    // Check that the device fulfills the requirements.
    val report = GiniCaptureRequirements.checkRequirements((Context) this)
    if (!report.isFulfilled()) {
        handleUnfulfilledRequirements(report)
        return
    }

    // Instantiate the networking implementations.
    val networkService: GiniCaptureNetworkService  = ...
    val networkApi: GiniCaptureNetworkApi = ...

    // Cleanup to make sure everything is reset.
    GiniPayBank.releaseCapture(this)

    // Configure the capture feature.
    GiniPayBank.setCaptureConfiguration(
        CaptureConfiguration(
            networkService = networkService,
            networkApi = networkApi,
            ...
        )
    )

    // Launch and wait for the result.
    GiniPayBank.startCaptureFlow(captureLauncher)
}

Component API

This is the more complicated way of using the capture flow. The advantage is that it is based on fragments and you have full control over how these are shown in your UI.

Note

Check out the Component API example app to see how an integration could look like.

Before launching the first fragment you need to:

  1. Request camera access,
  2. Configure the capture feature using the CaptureConfiguration.

The Component API is exposed as-is from the Gini Capture SDK and you can follow it’s guide to learn how to integrate it.

Handling Payment Requests

The Gini Pay Bank SDK enables your app to handle payment requests started by the Gini Pay Business SDK in another app. You can retrieve the payment requests’s content, mark the payment request as payed and also return your user to the app that created the payment request.

Networking

The pay feature depends on the Gini Pay API Library, which provides an entry point through the Gini class.

Note

You should have received Gini Pay API client credentials from us. Please get in touch with us in case you don’t have them. Without credentials you won’t be able to use the Gini Pay API.

The Gini class can be built either with client credentials or with a SessionManager if you already have an authorization token. We provide helper methods for each case:

getGiniApi(context: Context, clientId: String, clientSecret: String,
           emailDomain: String)
getGiniApi(context: Context, sessionManager: SessionManager)

SessionManager is an interface which you need to implement to send the token.

For more details about the Gini class see the Gini Pay API Library’s documentation.

Once you have a Gini instance you need to pass it to GiniPayBank.setGiniApi():

val giniApi = getGiniApi(this, myClientId, myClientSecret, myEmailDomain)

GiniPayBank.setGiniApi(giniApi)

Android Manifest

To be able to receive payment requests you need to add an intent filter for the ginipay URI to your manifest. This also allows the Gini Pay Business SDK to detect if your app is installed:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />

    <data
        android:host="payment"
        android:scheme="ginipay" />
</intent-filter>

The intent filter can be added to the activity which will handle the payment flow of that payment request.

Package Name

You also need to tell us your app’s package name. It will be associated with the payment provider we create for your banking app in the Gini Pay API. The Gini Pay Business SDK will only open your banking app if it is installed and it has the same package name as the one known by the Gini Pay API.

If you have different package names for development and production then please share both of them with us so that we can use the right one for each environment.

Receive Payment Requests

Note

You can see an example implementation in the Screen API example app’s pay package.

When your activity is launched with an intent you should follow the steps below to receive and handle the payment request:

  1. Extract the payment request id from the intent with getRequestId():

    val requestId = getRequestId(intent)
    
  2. Retrieve the payment details set by the business app using GiniPayBank.getPaymentRequest():

    val paymentRequest: PaymentRequest = giniPayBank.getPaymentRequest(requestId)
    
  3. Show the payment details to your user:

    showPaymentDetails(
        paymentRequest.recipient,
        paymentRequest.iban,
        paymentRequest.bic,
        paymentRequest.amount,
        paymentRequest.purpose
    )
    
  4. After your user has initiated the payment mark the payment request as paid using GiniPayBank.resolvePaymentRequest():

    // The actual payment details used for the payment (as corrected and accepted by the user).
    val usedPaymentDetails = ResolvePaymentInput(
        recipient = "...",
        iban = "...",
        bic = "...",
        amount = "...",
        purpose = "..."
    )
    
    val resolvedPayment: ResolvedPayment = giniPayBank.resolvePaymentRequest(requestId, usedPaymentDetails)
    
  5. You can allow your user to return to the business app that started the flow using GiniPayBank.returnToBusiness():

    giniPayBank.returnToBusiness(context, resolvedPayment)
    

Testing

Testing the payment feature requires an app which uses the Gini Pay Business SDK to create payment requests and to forward them to your banking app to view and resolve those payment requests.

Requirements

Example business app

An example business app is available in the Gini Pay Business SDK’s repository.

You can use the same Gini Pay API client credentials in the example business app as in your app, if not otherwise specified.

Development Gini Pay API client credentials

In order to test using our example business app you need to use development client credentials. This will make sure the Gini Pay Business SDK will use a payment provider which will open your development banking app.

End to end testing

After you’ve set the client credentials in the example business app you can install it along with your banking app on your device.

Run the example business app and import an invoice or take a picture of one to start the payment flow.

After following the integration steps above your banking app will be launched and you’ll be able to fetch the payment request, show the payment information and resolve the payment after the transaction has been confirmed. At this point, you may redirect back to the business app.

With these steps completed you have verified that your app, the Gini Pay API, the Gini Pay Business SDK and the Gini Pay Bank SDK work together correctly.

Testing in production

The steps are the same but instead of the development client credentials you will need to use production client credentials. This will make sure the Gini Pay Business SDK receives real payment providers including the one which opens your production banking app.

For testing the flow using the example business app please make sure that the production client credentials are used before installing it.

You can also test with a real business app. Please contact us in case you don’t know which business app(s) to install for starting the payment flow.