Android Developer Guide

Build an Android app with a PDA backend

Overview

In order to build an Android app that uses HAT APIs you first need to install the HAT API Android library from github. To do so you can either manually download the library and add it to your project or you can use maven.

Requirements

  • Android studio 3.2

  • Kotlin 1.3

  • In this guide there is no mention how to set up the UI, so you have to be able to design a basic UI in order to make everything work

Install manually

In order to manually install the library you have to download the repo from github and add it to your project via drag n drop.

Install via Gradle

Step 1

In the top-level gradle file, add the jitpack repository link

allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}

Step 2

In your app level gradle file , implement the library dependency

implementation 'com.hubofallthings.android.hatApi:hat:<latest-version>'

Step 3

Sync the project to download the library.

Step 4

Add internet permission into the AndroidManifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hubofallthings.myProject">
<uses-permission android:name="android.permission.INTERNET" />

Using the library

HAT-API-Android provides features that make your app to be able to authenticate with the PDA, read/write to the PDA, fetch and setup Data Plugs and Applications, fetch Data debits and use advanced features like Combinators and Bundles.

Authenticate with PDA

The PDA is an API-only service, meaning it does not enforce a specific Application or User Interface to expose the data to the user. Instead, authentication happens using the HAT APIs and the Javascript Web Token (JWT). Each PDA runs as a separate server and has a publicly-reachable address (such as https://postman.hubat.net). All calls in this documentation are therefore executed against an individual PDA.

Steps

The steps in logging in with a PDA are:

  1. You send the user to /hatlogin endpoint on their PDA, such as https://postman.hubat.net

  2. The PDA owner enters their login details in the login screen and verifies the service they are logging into

  3. User gets redirected back to the address you have provided with authentication token in a query parameter. You validate

    the token against the PDA’s public key and know that the user owns the specific PDA and log them in.

Step 1 - Redirect user to PDA Login

To log the user in with their PDA, you need to ask for their PDA address. Depending on the status of your app within the HAT ecosystem you may also have a specific application name, an allowed success redirect url and an allowed fallback redirect url for the user to be sent to complete authentication. If you do not have these details, you can put any application name, success redirect url and fallback redirect url, however the authentication token you will receive will not grant you any permissions to do any operations on the PDA but verify that the token really came from the PDA.

For an Android application that means asking user to type the PDA Address. Something very simple can be like the next image:

In the above image user is being asked to fill the HAT address, postman, and select a domain, .hubat.net. There can be other domains as well, e.g.: hubofallthings.net. We thought that splitting the address and the domain made for a better UX, but this is not a requirement for your app. You could have one EditText that the user will have to type the full address, postman.hubat.net

Having asked user to fill in the PDA address, e.g. postman.hubat.net, you have to send them to "https://$hatAddress/#/hatlogin?name=$applicationName&redirect=$redirectURL&fallback=$fallbackRedirectURL" endpoint of the PDA, where:

  • $hatAddress is the (fully qualified domain) address of the PDA, e.g. postman.hubat.net

  • $applicationName is the name of your application on the HAT. This is defined once when you complete the form to create a new application. e.g testing

  • $redirectURL is the URL where the user should be sent to after completing authentication. Optional. For an Android

    application that would probably be: $applicationName://success and has to be added in the AndroidManifest.xml file of

    the project in intent-filter of an Activity as a data with host="success" and scheme="$applicationName"

  • $fallbackRedirectURL is the URL where the user should be sent to in case the authentication has failed. Optional.

    For an Android application that would probably be: $applicationName://failed and has to be added in the AndroidManifest.xml

    file of the project in intent-filter of an Activity as a data with host="failed" and scheme="$applicationName"

In an Android application, in order to redirect the user to an existing PDA address and proceed to the next step, we have to use WebView to open the URL.

To achieve this with WebView you have to create an xml file with WebView element and an activity with the login address described above, "https://$hatAddress/#/hatlogin?name=$applicationName&redirect=$redirectURL&fallback=$fallbackRedirectURL", and then via a Activity present the WebView layout. e.g.:

<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/webView">
</WebView>
val mWebView = findViewById(R.id.webView)
mWebView.loadUrl(url)

That will launch WebView within the app and load the url specified.

Step 2 - Logging in the User

In the next step users will be asked to fill in the password for the particular PDA Address:

This screen cannot be modified in any way. Users have to insert the password for the specified PDA and tap LOGIN

Note that the complete address is served via SSL, contains the name of the PDA as well as the application parameters — application name, redirect url and fallback redirect url.

By tapping LOGIN the authentication process will begin. PDA will use one of the two redirect url that were included in the request, success redirect if everything went ok or fallbackRedirectURL if an error occurred. The application has to know how to respond in both scenarios.

In order to achieve that we have to add the success redirect and fallbackRedirectURL to the AndroidManifest file in the project.

In order to add them to the AndroidManifest file you have to add the Key URL Types as a data.

<activity name="MainActivity" >
<intent-filter>
<data
android:host="hatappfailed"
android:scheme="hatapp" />
</intent-filter>
</activity>

This will be the url scheme of your app. That means every time Android intercepts a URL starting with this value, like test://host will hand the process to your app and your app will be responsible to either launch or not.

Step 3 - Verifying the login

Success callback

If the user logs in, they get redirected to the URL provided, with token query parameter appended and containing a RS256-signed JWT token, e.g.:

dataswift-sandbox://dataswift-sandboxhost?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHBsaWNhdGlvblZlcnNpb24iOiIxLjIuNyIsInN1YiI6IjEtT0tRdm1TdGdCZ0lKdm9mNUN6NktsMnhaYjhXMUszQmZFR28xa2dZVERCQmdLeUR0ZDBqOXp6VWRaUmlRdFloaFY2VjQ5a1g1WUlmTzE0K3lEcm1GUlwvN1RkUW1iWXNMS3BDST0iLCJhcHBsaWNhdGlvbiI6ImhhdGFwcHN0YWdpbmciLCJpc3MiOiJ0ZXN0aW5nLmh1YmF0Lm5ldCIsImV4cCI6MTU0NDA4Nzc3MiwiaWF0IjoxNTQxNDk1NzcyLCJqdGkiOiI5ZjdlN2MyOTYwMjZkNmM4ODBmN2M2ZTk0MzIzOTQ3Yzg2YmI2OGEwZTIxN2YxZmZhYWE2ZTY3NGYwYWE1ODRmOWRiMzEwNDhiZmI1ZjI4N2Y5YzU4OGM4MGNmOTlmNzJjZTUyOTcxZjU3Y2NkNzVmODUzNTg3OTcwYWM5NWQzNDZhYWNmMzY5OWVkN2IyYmIyMDY5ZTJiMmM5YjE1OTg2Mjc5ZGNiYTNlMTMwYjRkMTdkNTI0ZTVkMmE5MTYyZTUzM2JjNWRlODJmNDBjNTg2ZDc2ODk2MTU0NDE3NzBkOGMwNDRlZjhhNjFlNWM3Y2JkZGQzOWFmYmQ1MDllMjU2In0.i4W_pbOVP9Qb-kkNaari-2U1eWfPSZ6QfYubb6r2SzN1VK0xRe_YT6Zm8gIuEoq8mf5p9wKPcsqzgJwLe27rGNTypCI9qZhVGqY0bNEC5GaXjH3YCXGI_hRKfHiqGbRD8XN1uhOlyWJg0pw_7DA4hdy1pGapw11Pu10y1-YMy6dlieAAU3ot87OGSr5bpXi3P3Wzgvv_QHRRn0ZVXHwp9p1UvG8LFkfzAg5lPqwQGZwMhqmp2NKSF_pStmzcKIsox_1ogrfam_3cm7p1iSRPMROYWxU9rwaOLQiXYXHuB1kO9Z62vxRJLySX_1PunWwXohbu4Rw7biBvpTdLI9D_DQ

The token will decode to something like this:

The Header:

{
"typ": "JWT",
"alg": "RS256"
}

The Payload:

{
"applicationVersion": "1.2.7",
"sub": "1-FgW7/lhAajlonnWAr7g3yB7eByYVkiV8O3UzsFPhEkoOYdr+bbeGeATwKyZUM6YenuUQb85G+PIijAxmP85GRnTIX6bdOdeJuuw=",
"application": "hatappstaging",
"iss": "postman.hubat.net",
"exp": 1543692303,
"iat": 1541100303,
"jti": "1c73175cd84624efb3ead7ea21fb055ae6f95a519722d314927f251dd13d19aac438861c441ef255a33dae1e1762ee914070251998cbc723a1e2f03f47784470cf70bb6aa003e582e0226d5d8a116af362d9e522a9b29b8281ab2014cc3ae4808e55a6e4752634b3f5b4c4a37e105f57695c6def44e77a2db8e5c9f36a768749"
}

The key parts of the Payload are:

  • The applicationVersion, the version of the app on HAT

  • The sub (subject), the subject of the token

  • The application, the application name that requested the token

  • The iss (issuer), which is the address of the PDA that has created the token and that you should be logging in

  • The exp (expiry) time of the token as a Unix timestamp, defining whether the token is still valid

  • The iat (issued at time) time that the token has been created as a Unix timestamp, defining whether the token

    is still valid. Token is expiring after 30 days of the issued at date no matter if a refreshed token has been received from PDA

  • The jti (JWT ID) the ID of the token

The Signature, which is generated from the token and the private key of the PDA. The signature must be verified to verify that the token has not been tampered with. A PDA’s public key can be accessed at the /publickey endpoint of the PDA (e.g. https://postman.hubat.net/publickey). The precise handling of tokens with asymmetric keys will depend on your library, however you need to make sure that your library supports RS256 keys.

jwt.io contains a very useful tool for token debugging while in development as well as listing all the major JWT libraries that you can use in your project.

When you have received a successful redirect from PDA you can check with HAT API Android and verity the user. To do so you simply have to call:

HATService().loginToHATAuthorization(
applicationName: Auth.serviceName,
url: url,
success: success,
failed: failed)
  • applicationName is the name of the application that sent the user to log in

  • url is the full url that returned from the PDA, like the example at the beginning of the step 3.

  • success is a callback to execute when the library have successfully authorized user. You can use this callback to dismiss

    WebView activity, save the values needed and navigate to the next Activity

  • failed is a callback to execute when the library couldn't authorize user. You can use this callback to dismiss WebView

    activity and show an error message to the user.

Having received the success callback you have to save the token, ALWAYS use Encryption to save the token. DO NOT save it in any non encrypted database. A good idea would be to also save the full PDA Address as well, as you are gonna need it many times in order to communicate with the PDA. You can store the values in SharedPreferences in Private mode.

As soon as you save the token you are free to navigate to your next Activity.

Fail callback

In case the authentication failed, you will redirected to the fallback url. In that case you should dismiss WebView Activity and then update the UI or show an error message back to the user.

In order to dismiss the browser you do it from the viewController that presented originally the Activity, like this:

finish()

PDA Data I/O

The PDA is a data store. That means that you can read and write any data you want. Be it a passport, your health records or any data you can think of.

HAT API Android has built in support for reading or writing data to your PDA

This section describes the mechanism of writing data. For reading, this is done through data-debits, a system of consented data exchange.

Writing Data to PDA

Make network requests

Hat API Android offers a general method to create network requests:

HATNetworkManager().postRequest(
url,
body: String,
headers: Map<String, String>,
completion: completionCallback)
  • url the URL to send the request to

  • method the HTTP method of the request, you can find the different methods here

  • contentType the content-type of the request, you can find more here

  • headers the additional headers of the request, this field can be an empty dictionary, mapOf("","")

  • completion a callback function to execute when the request has finished. The result type of the callback can either

    be isSuccess(var statusCode: Int?, var error: Error?, var json: Json?, var resultString: String?, var token: String?)

    if the request was successful or HasFailed(var statusCode: Int?, var error: Error?, var json: Json?, var resultString: String?, var token: String?)

    if the request has failed.

The result type is an enum. Depending if the request was a success or a failure it will have the right type. When the request was successful the result type will include:

  • A boolean value isSuccess, indicating if the request was successful. It may be that the request triggers the successful

    result type but the isSuccess is false, maybe the response was 404 for example

  • The statusCode of the request. Usually the 200..299 range is a success and 400..599 is failure. You can learn more

    about the different status codes here

  • The result is Json type of Fuel, can be found here

  • The token is a refreshed token returned from the PDA. It's optional and sometimes can be null or empty.

When the request has failed the result type will include:

  • The error that has occurred with the request, e.g. no internet connection or time out

  • The statusCode of the request. Usually the 200..299 range is a success and 400..599 is failure. You can learn more

    about the different status codes here

  • The result is JSON type of Fuel, can be found here. Usually it will hold more info about the failure.

Write data

Let's say we want to save the randomStructure below in our PDA:

{
"value 1": "random",
"Int value": 0
}

The URL that the data will be saved is https://$hatAddress/api/v2.6/data/$path

If the hatAddress is postman.hubat.net and the path is randomdata then the URL will be: https://postman.hubat.net/api/v2.6/data/dataswift-sandbox/randomdata.

The path is formed by your app name, dataswift-sandbox, and the rest of the path, randomdata. It can also be folder/something/data/random. How deep the path will be depends from the data structure that your app uses to navigate to different files.

One more thing that we need in order to write data to the PDA is the user's token in the headers of the request. The header you need to add is x-auth-token along with the token retrieved from the KeyStore. NEVER save the token in a not encrypted database.

Using the function from Hat API Android that will be

HATNetworkManager().postRequest(
"https://postman.hubat.net/api/v2.6/data/dataswift-sandbox/randomdata",
parameters: randomStructure,
headers: mapOf("x-auth-token" to token,"Content-Type" to "application/json"),
completion: completionCallback)

Based on the type of the completionCallback you might have gotten the data back or you might get an error. Your app should know how to react in both scenarios:

when (result){
is ResultType.IsSuccess->{
//do something....
}
is ResultType.HasFailed->{
//do something....
}
}

A successful response will have statusCode 201 and look like this:

{
"endpoint": "randomdata",
"recordId": "cf2c4ad5-bbb2-4a0e-8aaa-d3be8b76e115",
"data": {
"value 1": "random",
"Int value": 0
}
}
  • endpoint is the path that the file resides, https://$hatAddress/api/v2.6/data/$path

  • recordId is the record identifier in the PDA. It's useful for when want to delete the file for example.

  • data is the data structure that you have saved in the PDA

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Read data

If we want to read data we are going to use the same request again but method will be GET instead of POST:

HATNetworkManager().getRequest(
url,
parameters: List<Pair<"key", value?>>,
headers: Map<String, String>?,
completion: completionCallback)

If we make the same assumptions again, the hatAddress is postman.hubat.net, the path is randomdata and the x-auth-token in the headers includes the token then the call will look like below:

HATNetworkManager().getRequest(
"https://postman.hubat.net/api/v2.6/data/dataswift-sandbox/randomdata",
parameters: List<Pair<String, Any?>>,
headers: mapOf("x-auth-token" to token,"Content-Type" to "application/json"),
completion: completionCallback)

Notice that since we want to read data and not write, we don't include any parameters.

Based on the type of the completionCallback you might have gotten the data back or you might get an error. Your app should know how to react in both scenarios:

when (result){
is ResultType.IsSuccess->{
//do something....
}
is ResultType.HasFailed->{
//do something....
}
}

A successful response will have statusCode 200 and look like that:

{
"endpoint": "randomdata",
"recordId": "cf2c4ad5-bbb2-4a0e-8aaa-d3be8b76e115",
"data": {
"value 1": "random",
"Int value": 0
}
}
  • endpoint is the path that the file resides, https://$hatAddress/api/v2.6/data/$path

  • recordId is the record identifier in the PDA. It's useful for when want to delete the file for example.

  • data is the data structure that you have saved in the PDA

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Update data

Let's say that we want to change our original example:

{
"value 1": "random",
"Int value": 0
}

To something like this:

{
"value 1": "random",
"newValue": true,
"Int value": 1
}

In order to update the data the HTTP method has to change to PUT:

HATNetworkManager.putRequest(
url,
body: String,
headers: Map<String, String>,
completion: completionCallback)

If we make the same assumptions again, the hatAddress is postman.hubat.net and request and the x-auth-token in the headers includes the token then the call will look like below:

HATNetworkManager().putRequest(
"https://postman.hubat.net/api/v2.6/data",
body: body,
headers: ["x-auth-token" to token, "Content-Type" to "application/json"],
completion: completionCallback)

Where parameters is an array of Key-value pair of type Map<String: Any> representing the new structure that we want to update. Mind the brackets, it has to be an array even if it's just one element.

Based on the type of the completionCallback you might have gotten the data back or you might get an error. Your app should know how to react in both scenarios:

when (result){
is ResultType.IsSuccess->{
//do something....
}
is ResultType.HasFailed->{
//do something....
}
}

A successful response will have statusCode 201 and look like this:

{
"endpoint": "randomdata",
"recordId": "cf2c4ad5-bbb2-4a0e-8aaa-d3be8b76e115",
"data": {
"value 1": "random",
"newValue": true,
"Int value": 1
}
}
  • endpoint is the path that the file resides, https://$hatAddress/api/v2.6/data/$path

  • recordId is the record identifier in the PDA. It's useful for when want to delete the file for example.

  • data is the data structure that you have saved in the PDA

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Delete data

If now we want to delete the file we have just created we need to create a DELETE request:

HATNetworkManager().deleteRequest(
url,
body: String,
headers: Map<String, String>,
completion: completionCallback)

If we make the same assumptions again, the hatAddress is postman.hubat.net and request and the x-auth-token in the headers includes the token then the call will look like below:

HATNetworkManager().deleteRequest(
"https://postman.hubat.net/api/v2.6/data",
body: body,
headers: mapOf("x-auth-token" to token),
completion: completionCallback)

Where body in this case is the recordId of the entry we want to delete. We can also delete multiple entries with one request using more parameters. If the recordId is 5 then the body will be.

{
"records": 5
}

A successful response will have statusCode 200 and look like this:

{
"message": "All records deleted"
}

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Upload Files

Hat API Android allows you to also upload files in your PDA. You can read more about HAT File Storage here.

The uploading of a file is a multi step process:

  • Request from PDA a temporary URL to upload the file

  • Upload the file to the URL

  • Mark the file as complete

Step 1

To start a file upload you have to call the function below:

HATFileService().uploadFileToHAT(
fileName: name,
token: token,
userDomain: userDomain,
tags: tags,
completion: completionCallback,
errorCallback: failCallback
)
  • fileName is the desired name of the file. You can either randomize it or provide meaningful names, it's up to you

  • token is the user's token. This is needed to authenticate user with the PDA

  • userDomain is the user's PDA Address. This is need in order to form the URL to upload the file

  • tags is an array of String with useful tags to make searching for that file easier.

  • completion is an optional callback function of type ((FileUploadObject, String?) -> Unit)?, FileUploadObject

    is a custom object of HAT API Android describing the file upload object. The Optional String is the refreshed token

    returned from the PDA. This is executed on success and it includes the URL that you have to upload your file.

  • errorCallback is an optional callback that is executed when the request has failed. The type of the callback function

    is ((HATError) -> Unit)?. HATError is a custom object describing the errors that have occurred during the querying of the tables in the database.

So for the purpose of this example let's say that fileName is testfile, tags is just test-tag, userDomain is postman.hubat.net and token is token. That will translate to the request below:

HATFileService().uploadFileToHAT(
fileName: "testfile",
token: "token",
userDomain: "postman.hubat.net",
tags: arrayof("test-tag"),
completion: completionCallback,
errorCallback: failCallback
)

A successful request will result in a status code 200 and the response will look like the one below:

{
"fileId": "dataswift-sandboxtestfile",
"name": "testfile",
"source": "dataswift-sandbox",
"dateCreated": "2018-11-08T16:08:38.679Z",
"lastUpdated": "2018-11-08T16:08:38.679Z",
"tags": [
"test-tag"
],
"status": {
"status": "New"
},
"contentUrl": "https://hubat-net-hatservice-v3ztbxc9civz-storages3bucket-m0gs7co0oyi2.s3.eu-west-1.amazonaws.com/postman.hubat.net/dataswift-sandboxtestfile?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181108T160838Z&X-Amz-SignedHeaders=host%3Bx-amz-server-side-encryption&X-Amz-Expires=300&X-Amz-Credential=AKIAICFRCZUZIP4PQ64A%2F20181108%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=f868940fad6ad21085c19b62d4b940127808858e64e57dd44b4de452178e107d",
"contentPublic": false,
"permissions": [
{
"userId": "de35e18d-14wf-4664-8de7-409abf881754",
"contentReadable": true
}
]
}

The above response is described by FileUploadObject. The values are explained below:

  • fileId is the ID of the file on the PDA, it is formed by combining the source and name of the file.

  • name is the name of the file that we assigned. In case of a duplicate fileId, PDA will append an incremented number at the end

  • source is the source that requested to upload this file. It's good to have your app name as the source

  • dateCreated is the date that the file was created in ISO format

  • lastUpdated is the date that the file was last modified. You can change the name, status and make the file private or not.

  • tags is an array of String that allow for easier search of the file in the future. You can add multiple tags.

  • status is a Array<Pair<String, String>> Key-Value pair and it can be New, when you just requested the file upload,

    or Completed after the uploading has finished and you marked the file as Completed

  • contentUrl is the URL you will use to upload the file. This URL is short-lived and its use is just to provide a URL for your app that you can upload the file.

  • contentPublic is the flag that indicates if the file is private or public. You can mark a file as private or public after the file has been uploaded

  • permissions is an array of Key-Value pairs of type Array<Pair<String, Any>>. In the above example the permissions

    provide the user with that userId the ability to have access to the file even if the file is marked as private

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Step 2

The second step is to upload the actual file. There is no limitation on what type of file you can upload. You can upload images, videos, documents etc. It's up to the application to ensure that the file is uploaded correctly and that it can then download the file and read it without problems.

In order to upload a file you can use the function below included in HAT API Android:

HATNetworkHelper().uploadFile(
image: File,
url: contentURL,
completion: completionCallback,
error : errorCallBack
)
  • image is type of File. This function requires to convert your file into File type first. You can convert a Bitmap image to `File``

  • url us the URL to upload the file. As we said earlier this URL is the contentUrl provided by the PDA in the first step

  • completion is a callback function of type (_ r: HATNetworkHelper.ResultType) -> Unit). It can be either

    isSuccess(var statusCode: Int?, var error: Error?, var json: Json?, var resultString: String?, var token: String?) if the

    request was successful or HasFailed(var statusCode: Int?, var error: Error?, var json: Json?, var resultString: String?, var token: String?)

    if the request has failed for some reason. You can read more about it here

A successful request will look like almost exactly the same as the original one:

{
"fileId": "dataswift-sandboxtestfile",
"name": "testfile",
"source": "dataswift-sandbox",
"dateCreated": "2018-11-08T16:08:38.679Z",
"lastUpdated": "2018-11-08T16:08:40.235Z",
"tags": [
"test-tag"
],
"status": {
"status": "New"
},
"contentUrl": "https://hubat-net-hatservice-v3ztbxc9civz-storages3bucket-m0gs7co0oyi2.s3.eu-west-1.amazonaws.com/postman.hubat.net/dataswift-sandboxtestfile?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181108T160838Z&X-Amz-SignedHeaders=host%3Bx-amz-server-side-encryption&X-Amz-Expires=300&X-Amz-Credential=AKIAICFRCZUZIP4PQ64A%2F20181108%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=f868940fad6ad21085c19b62d4b940127808858e64e57dd44b4de452178e107d",
"contentPublic": false,
"permissions": [
{
"userId": "de35e18d-14wf-4664-8de7-409abf881754",
"contentReadable": true
}
]
}

The only thing that has now changed is the lastUpdated field.

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}

Step 3

When the file has finished uploading it's required to mark the file as completed, else the file will be deleted. To do so you have to make another request. To achieve that you have to call the next function:

HATFileService().completeUploadFileToHAT(
fileID: fileObject.fileID,
token: token,
tags: tags,
userDomain: userDomain,
completion: completionCallback,
errorCallback: failCallback
)
  • fileID is the file id that is to be marked as completed

  • token is the user's token. This is needed to authenticate user with the PDA

  • tags is an array of String with useful tags to make searching for that file easier. This is added before HAT API Android

    returns you the full file.

  • userDomain is the user's PDA Address. This is need in order to form the URL to mark the file as completed

  • completion is an optional callback function of type ((FileUploadObject, String?) -> Unit)?, FileUploadObject is

    a custom object of HAT API Android describing the file upload object. The Optional String is the refreshed token returned from the PDA.

  • errorCallback is an optional callback that is executed when the request has failed. The type of the callback function

    is ((HATError) -> Unit)?. HATError is a custom object describing the errors that have occurred during the querying of the tables in the database.

A successful request will look like almost exactly the same as the original one:

{
"fileId": "dataswift-sandboxtestfile",
"name": "testfile",
"source": "dataswift-sandbox",
"dateCreated": "2018-11-08T16:08:38.679Z",
"lastUpdated": "2018-11-08T16:08:43.157Z",
"tags": [
"test-tag"
],
"status": {
"size": 123,
"status": "Completed"
},
"contentUrl": "https://hubat-net-hatservice-v3ztbxc9civz-storages3bucket-m0gs7co0oyi2.s3.eu-west-1.amazonaws.com/postman.hubat.net/dataswift-sandboxtestfile?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181108T160838Z&X-Amz-SignedHeaders=host%3Bx-amz-server-side-encryption&X-Amz-Expires=300&X-Amz-Credential=AKIAICFRCZUZIP4PQ64A%2F20181108%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=f868940fad6ad21085c19b62d4b940127808858e64e57dd44b4de452178e107d",
"contentPublic": false,
"permissions": [
{
"userId": "de35e18d-14wf-4664-8de7-409abf881754",
"contentReadable": true
}
]
}

The only thing that has now changed is the lastUpdated field and the status field. The status is marked as Completed and includes the file size in bytes.

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Mark file as public

Be default the uploaded files are marked as private. You can change that by calling this function:

HATFileService().makeFilePublic(
fileID: file.fileID,
token: userToken,
userDomain: userDomain,
successCallback: completionCallback,
errorCallBack: errorCallBack)
  • fileID is the file id that is to be marked as public

  • token is the user's token. This is needed to authenticate user with the PDA

  • userDomain is the user's PDA Address. This is need in order to form the URL to mark the file as public

  • completion is an optional callback function of type (Boolean -> Unit) returns true

  • errorCallback is an optional callback that is executed when the request has failed. The type of the callback function is

    ((HATError) -> Unit)?. HATError is a custom object describing the general error that occurred on the PDA

A successful request will have a statusCode of 200 and look like almost exactly the same as the original one:

{
"fileId": "dataswift-sandboxtestfile",
"name": "testfile",
"source": "dataswift-sandbox",
"dateCreated": "2018-11-08T16:08:38.679Z",
"lastUpdated": "2018-11-08T16:04:45.689Z",
"tags": [
"test-tag"
],
"status": {
"size": 123,
"status": "Completed"
},
"contentUrl": "https://hubat-net-hatservice-v3ztbxc9civz-storages3bucket-m0gs7co0oyi2.s3.eu-west-1.amazonaws.com/postman.hubat.net/dataswift-sandboxtestfile?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181108T160838Z&X-Amz-SignedHeaders=host%3Bx-amz-server-side-encryption&X-Amz-Expires=300&X-Amz-Credential=AKIAICFRCZUZIP4PQ64A%2F20181108%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=f868940fad6ad21085c19b62d4b940127808858e64e57dd44b4de452178e107d",
"contentPublic": true,
"permissions": [
{
"userId": "de35e18d-14wf-4664-8de7-409abf881754",
"contentReadable": true
}
]
}

The only thing that has now changed is the lastUpdated field and the contentPublic field.

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Mark file as Private

Be default the uploaded files are marked as private. You can change that by calling this function:

HATFileService().makeFilePrivate(
fileID: file.fileID,
token: userToken,
userDomain: userDomain,
successCallback: completionCallback,
errorCallBack: errorCallBack)
  • fileID is the file id that is to be marked as private

  • token is the user's token. This is needed to authenticate user with the PDA

  • userDomain is the user's PDA Address. This is need in order to form the URL to mark the file as private

  • completion is an optional callback function of type (Boolean -> Unit) returns true

  • errorCallback is an optional callback that is executed when the request has failed. The type of the callback function is

    ((HATError) -> Unit)?. HATError is a custom object describing the general error that occurred on PDA

A successful request will have a statusCode of 200 and look like almost exactly the same as the original one:

{
"fileId": "dataswift-sandboxtestfile",
"name": "testfile",
"source": "dataswift-sandbox",
"dateCreated": "2018-11-08T16:08:38.679Z",
"lastUpdated": "2018-11-08T16:09:44.247Z",
"tags": [
"test-tag"
],
"status": {
"size": 123,
"status": "Completed"
},
"contentUrl": "https://hubat-net-hatservice-v3ztbxc9civz-storages3bucket-m0gs7co0oyi2.s3.eu-west-1.amazonaws.com/postman.hubat.net/dataswift-sandboxtestfile?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181108T160838Z&X-Amz-SignedHeaders=host%3Bx-amz-server-side-encryption&X-Amz-Expires=300&X-Amz-Credential=AKIAICFRCZUZIP4PQ64A%2F20181108%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=f868940fad6ad21085c19b62d4b940127808858e64e57dd44b4de452178e107d",
"contentPublic": false,
"permissions": [
{
"userId": "de35e18d-14wf-4664-8de7-409abf881754",
"contentReadable": true
}
]
}

The only thing that has now changed is the lastUpdated field and the contentPublic field.

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Search files

You can also search for files with Hat API Android. To do so you can use the next function:

HATFileService().searchFiles(
userDomain: userDomain,
token: userToken,
status: "Completed",
name: "",
tags: tags,
successCallback: receivedImages,
errorCallBack: receivedErrorGettingImages)
  • userDomain is the user's HAT PDAAddress. This is need in order to form the URL to fetch the files

  • token is the user's token. This is needed to authenticate user with the PDA

  • status is the status of the file. You can search for Completed files only or for New files.

  • name is the name of the file. You can search for a specific file or leave this as an empty String in case you want to

    fetch all the files that match the status and tags

  • tags is an array of String with useful tags to make searching for that file easier. You can search file with specific tags

  • completion is a callback function of type (List<FileUploadObject>, String?) -> Unit. The first parameter is an array

    of FileUploadObject, it contains all the files that the PDA found during the search. The second parameter is an optional

    String, it is a refreshed token returned from the PDA. It can be nil.

  • errorCallback is an optional callback that is executed when the request has failed. The type of the callback function

    is ((HATError) -> Unit)?. HATError is a custom object describing the general error that occurred on PDA

A successful request will have a statusCode of 200 and look like this:

[
{
"fileId": "rumpel1532526508004.jpg",
"name": "1532526508004.jpg",
"source": "rumpel",
"dateCreated": "2018-07-25T13:48:24.976Z",
"lastUpdated": "2018-07-25T13:48:24.976Z",
"tags": [
"android",
"image/jpeg"
],
"status": {
"size": 144332,
"status": "Completed"
},
"contentUrl": "https://hubat-net-hatservice-v3zbxc9civz-storages3bucket-m0gs7co0oyi2.s3.eu-west-1.amazonaws.com/postman.hubat.net/rumpel1532526508004.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181109T184507Z&X-Amz-SignedHeaders=host&X-Amz-Expires=299&X-Amz-Credential=AKIAICFRCZUZIP4PQ64A%2F20181109%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=3492955b3870ab6bd321f43ba18cb62cd538547b7e523a57c87e0355c29eb3c3",
"contentPublic": true,
"permissions": [
{
"userId": "de35e1ed-147f-4664-8de7-409abf881754",
"contentReadable": true
}
]
},
{
"fileId": "rumpelrumpelphoto-49",
"name": "rumpelPhoto",
"source": "rumpel",
"dateCreated": "2018-06-18T08:31:10.420Z",
"lastUpdated": "2018-06-18T08:31:10.420Z",
"tags": [
"iphone",
"notes",
"photo"
],
"status": {
"size": 2066062,
"status": "Completed"
},
"contentUrl": "https://hubat-net-hatservice-v3ztbxc9ciz-storages3bucket-m0gs7co0oyi2.s3.eu-west-1.amazonaws.com/postman.hubat.net/rumpelrumpelphoto-49?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181109T184507Z&X-Amz-SignedHeaders=host&X-Amz-Expires=299&X-Amz-Credential=AKIAICFRCZUZIP4PQ64A%2F20181109%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=2cd122df4cdf15be3e66889d5cc2e525880eb4f2c82012b6dcf00c601ad390da",
"contentPublic": true,
"permissions": [
{
"userId": "de35e1ed-147f-4664-8de7-409abf881754",
"contentReadable": true
}
]
}
]

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Delete files

You can also delete files from the PDA using the next function:

HATFileService().deleteFile(
fileID: fileID,
token: userToken,
userDomain: userDomain,
successCallback: fileDeleted,
errorCallBack: fileFailedToDelete)
  • fileID is the file id on the PDA

  • token is the user's token. This is needed to authenticate user with the PDA

  • userDomain is the user's HAT PDAAddress. This is need in order to form the URL to delete the file

  • completion is a callback function of type (Boolean, String?) -> Unit. The first parameter is true. The second parameter

    is an optional String, it is a refreshed token returned from the PDA. It can be nil.

  • errorCallback is an optional callback that is executed when the request has failed. The type of the callback function

    is ((HATError) -> Unit)?. HATError is a custom object describing the general error that occurred on PDA

A successful request will have a statusCode of 200 and look like almost exactly the same as the original one:

{
"fileId": "dataswift-sandboxtestfile",
"name": "testfile",
"source": "dataswift-sandbox",
"dateCreated": "2018-11-08T16:08:38.679Z",
"lastUpdated": "2018-11-08T16:09:44.247Z",
"tags": [
"test-tag"
],
"status": {
"status": "Deleted"
},
"contentUrl": "https://hubat-net-hatservice-v3ztbxc9civz-storages3bucket-m0gs7co0oyi2.s3.eu-west-1.amazonaws.com/postman.hubat.net/dataswift-sandboxtestfile?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181108T160838Z&X-Amz-SignedHeaders=host%3Bx-amz-server-side-encryption&X-Amz-Expires=300&X-Amz-Credential=AKIAICFRCZUZIP4PQ64A%2F20181108%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=f868940fad6ad21085c19b62d4b940127808858e64e57dd44b4de452178e107d",
"contentPublic": false,
"permissions": [
{
"userId": "de35e18d-14wf-4664-8de7-409abf881754",
"contentReadable": true
}
]
}

The only thing that has now changed is the status to Deleted

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Data Debits

PDA Data Debits are the cornerstone of consented data exchange. It is the only way data can be retrieved from the PDA by anyone else than the owner and enforces a strictly-defined format defining the specific data requested for the user to review and approve.

Fetch Data Debits

You can fetch the available Data Debits by using the next function:

HATDataDebitsService().getAvailableDataDebits(
userToken: userToken,
userDomain: userDomain,
succesfulCallBack: gotDataDebits,
failCallBack: failedGettingDataDebits)
  • userToken is the user's token in order to authenticate with the PDA.

  • userDomain is the user's PDA address in order to form the url to fetch the available Data Debits.

  • succesfulCallBack is a callback. Is called when the request was successful with a type of (List<DataDebitObject>, String?) -> Unit).

    The first parameter is a list of DataDebitObject. This is the structure of Data Debits. More on that in the next section.

    The second parameter is an optional String, the refreshed user token that the PDA returns.

  • failCallBack is a callback that is called when the request has failed. They type of the function is ((HATError) -> Unit). HATError

    is a custom object describing the errors that have occurred during the querying of the PDA.

A successful response will have statusCode 200 and look like this:

[
{
"dataDebitKey": "97a0748f-bf81-4aaa-8f39-97ac2557d920",
"dateCreated": "2018-01-02T15:22:42+0000",
"permissions": [
{
"dateCreated": "2018-01-02T15:22:42+0000",
"purpose": "This Data Debit is in a legacy format, and the HAT App is unable to display all the information associated with it fully. This may include a logo, title and full description",
"start": "2018-01-02T15:23:02.000Z",
"period": 86400000,
"cancelAtPeriodEnd": true,
"termsUrl": "",
"bundle": {
"name": "97a0748f-bf81-4aaa-8f39-97ac2557d920",
"bundle": {
"iphone/locations": {
"endpoints": [
{
"endpoint": "iphone/locations",
"mapping": {
"accuracy": "accuracy",
"latitude": "latitude",
"longitude": "longitude",
"timestamp": "timestamp",
"lastUpdated": "lastUpdated",
"locations.accuracy": "locations.accuracy",
"locations.latitude": "locations.latitude",
"locations.longitude": "locations.longitude",
"locations.timestamp": "locations.timestamp"
},
"filters": []
}
]
},
"rumpel/locations/ios": {
"endpoints": [
{
"endpoint": "rumpel/locations/ios",
"mapping": {
"speed": "speed",
"course": "course",
"altitude": "altitude",
"latitude": "latitude",
"longitude": "longitude",
"dateSynced": "dateSynced",
"dateCreated": "dateCreated",
"dateCreatedLocal": "dateCreatedLocal",
"verticalAccuracy": "verticalAccuracy",
"horizontalAccuracy": "horizontalAccuracy"
},
"filters": []
}
]
}
}
},
"accepted": false,
"active": false,
"end": "2018-01-03T15:23:02.000Z"
}
],
"requestClientName": "Data Exchange",
"requestClientUrl": "https://dex.hubofallthings.com/",
"requestClientLogoUrl": "https://dex.hubofallthings.com/assets//images/dex.png",
"active": false,
"accepted": false,
"start": "2018-01-02T15:23:02.000Z",
"end": "2018-01-03T15:23:02.000Z",
"permissionsActive": null,
"permissionsLatest": {
"dateCreated": "2018-01-02T15:22:42+0000",
"purpose": "This Data Debit is in a legacy format, and the HAT App is unable to display all the information associated with it fully. This may include a logo, title and full description",
"start": "2018-01-02T15:23:02.000Z",
"period": 86400000,
"cancelAtPeriodEnd": true,
"termsUrl": "",
"bundle": {
"name": "97a0748f-bf81-4aaa-8f39-97ac2557d920",
"bundle": {
"iphone/locations": {
"endpoints": [
{
"endpoint": "iphone/locations",
"mapping": {
"accuracy": "accuracy",
"latitude": "latitude",
"longitude": "longitude",
"timestamp": "timestamp",
"lastUpdated": "lastUpdated",
"locations.accuracy": "locations.accuracy",
"locations.latitude": "locations.latitude",
"locations.longitude": "locations.longitude",
"locations.timestamp": "locations.timestamp"
},
"filters": []
}
]
},
"rumpel/locations/ios": {
"endpoints": [
{
"endpoint": "rumpel/locations/ios",
"mapping": {
"speed": "speed",
"course": "course",
"altitude": "altitude",
"latitude": "latitude",
"longitude": "longitude",
"dateSynced": "dateSynced",
"dateCreated": "dateCreated",
"dateCreatedLocal": "dateCreatedLocal",
"verticalAccuracy": "verticalAccuracy",
"horizontalAccuracy": "horizontalAccuracy"
},
"filters": []
}
]
}
}
},
"accepted": false,
"active": false,
"end": "2018-01-03T15:23:02.000Z"
}
}
]
  • dataDebitKey is the data debit key, defined when creating the Data Debit, it's unique across PDA

  • dateCreated is the date that this Data Debit was created. The date is in ISO format as String

    • permissions is the permissions info for this Data Debit. What URLs it has access, from which date to which date, etc.: 1. dateCreated is the date that this Data Bundle was created. The date is in ISO format as String 2. purpose is a short description for the Data Bundle explaining its purpose. optional 3. start is the start date that this Data Bundle has become active. The date is in ISO format. Optional 4. end is the start date that this Data Bundle will surpass the assigned duration stated in period. The date is in ISO format. Optional 5. cancelAtPeriodEnd is a flag indicating if the permissions will auto cancel when the Data Debit will end 6. termsUrl is a URL to show to the user the terms and conditions for this Data Bundle 7. period the duration that the Data Bundle can be active. Value in seconds 8. active is indicating if the Data Bundle is active 9. accepted is indicating if the Data Bundle has been accepted 10. bundle is the part where the permissions are defined. Like what endpoints this Data Debit will have access to, which fields from that endpoint, a name, under what circumstances etc.: 1. name is name of the bundle. This has to be unique. 2. bundle is a Dictionary of typeDictionary<String, DataOfferRequiredDataDefinitionBundleKeyV2>, it allows to define multiple different endpoints by giving a different name. This means that you can combine multiple and different endpoints each with it's own requirements: 1. endpoints is an array of DataOfferRequiredDataDefinitionBundleKeyEndpointsV2 containing the PDA URLs to include, a desired mapping or filtering for the fields: 1. endpoint the actual endpoint that you would like access to, for example rumpel/profile 2. mapping is the selected fields from this endpoint that you would like to have in the Data Debit 3. filters lets you filter a field by some requirements. For example, you can define something like age between 18 and 35. Optional: 1. field is the field that you would like to apply filtering to 2. transformation is the transformation type to be done on the field. There are 4 different options: Optional 1. identity keep the value as-is, effect is the same as if transformation was not defined 2. datetimeExtract with part — extract part of a date from an ISO 8601 formatted date field 3. timestampExtract with part — extract part of a date from a UNIX timestamp date field 4. searchable convert the field to searchable text. Must be used together with the find operator below 3. operator is the type of the filtering. There are 4 different types with different structure each. You can read more into it be checking out Operator class in HAT API Android here. Optional: 1. find it allows you to search a particular String, field name: search. Also, you can nest more operators, field name: operator 2. contains it allows you to search if a particular substring is contained into a String, field name: value of type Bool 3. between it allows you to search if an Int is between 2 values named upper and lower 4. in together with value field set to check if field is in (is contained by) value 4. links each endpoint can contain other endpoint objects. Optional 2. orderBy lets you define the field to order the data. Optional 3. ordering lets you define the ordering of the data. ascending or descending. Optional 4. limit is an Int which lets you define how many data points you like from this endpoint. Optional 11. conditions check bundle for the structure. The purpose is that the Data Bundle can have some conditions, that

      have to be fulfilled first, attached to it in order to become `active`. _**Optional**_
  • requestClientName is the name of the client that created this Data Debit

  • requestClientUrl is the URL to the website of the client

  • requestClientLogoUrl is a URL for the logo of the client

  • requestDescription is a description for the Data Debit. Optional

  • requestApplicationId If the Data Debit is tied to an Application this will be the application id. Else it's nil. Optional

  • active is indicating if the Data Debit is active

  • accepted is indicating if the Data Debit has been accepted

  • start is the date that this Data Debit has started. The date is in ISO format as String. Optional

  • end is the date that this Data Debit will end. The date is in ISO format as String. Optional

  • permissionsActive Latest active permissions. Look at permissions. Optional

  • permissionsLatest Latest permissions. Look at permissions

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Create Data Debit

You can also create a Data Debit by using the function below:

val endpoint = DataOfferRequiredDataDefinitionBundleKeyEndpointsV2(endpoint: "rumpel/profile")
val bundle = DataOfferRequiredDataDefinitionObjectV2(
name: "test1",
bundle: arrayList(rumpel/profile" to DataOfferRequiredDataDefinitionBundleKeyV2(endpoints: arrayList(endpoint))))
val dataDebitToCreate = DataDebitCreationObject(
dataDebitKey: "test1",
purpose: "none",
start: "2018-11-14T23:51:40+0000",
period: 432000000,
termsUrl: "none",
cancelAtPeriodEnd: false,
requestClientName: "none",
requestClientUrl: "none",
requestClientLogoUrl: "none",
bundle: bundle)
HATDataDebitService().createDataDebit(
dataDebitID: dataDebitID,
bundle: dataDebitToCreate,
userToken: userToken,
userDomain: userDomain,
succesfulCallBack: dataDebitCreated,
failCallBack: dataDebitCreationFailed)
)
  • endpointis the PDA endpoint you would like access to. DataOfferRequiredDataDefinitionBundleKeyEndpointsV2 also allows

    you to setup mapping and filtering if you wish. The minimum requirement is to specify the endpoint you want to use

  • bundle we can say it is a grouping of different endpoints under one category. You can define one category, with the name

    parameter, but you can have multiple endpoints in the bundle section. Note that name has to be unique

  • dataDebitKey is a key to the specific Data debit. This has to be unique

  • purpose is a small description of the purpose for this Data Debit

  • start is the start date that this Data Debit can become available. The date is in ISO format

  • period is the duration that the Data Debit will be active in seconds

  • termsUrl is the URL for the terms and conditions for this Data Debit

  • cancelAtPeriodEnd is a bool flag for if the Data Debit should be cancelled with the period passes

  • requestClientName is the name of the client that created this Data Debit

  • requestClientUrl is the URL to the website of the client

  • requestClientLogoUrl is a URL for the logo of the client

  • bundle is the description of what endpoints we want to have access to

A successful response will have statusCode 201 and look like this:

{
"dataDebitKey": "test1",
"dateCreated": "2018-11-14T23:51:40+0000",
"permissions": [
{
"dateCreated": "2018-11-14T23:51:40+0000",
"purpose": "none",
"start": "2018-11-14T23:51:40+0000",
"period": 432000000,
"cancelAtPeriodEnd": false,
"termsUrl": "none",
"conditions": {
"name": "data-debit-id-test-name",
"bundle": {
"test": {
"endpoints": [
{
"endpoint": "rumpel/profile"
}
]
}
}
},
"bundle": {
"name": "data-debit-id-test1",
"bundle": {
"test": {
"endpoints": [
{
"endpoint": "rumpel/profile"
}
]
}
}
},
"accepted": false,
"active": false,
"end": null
}
],
"requestClientName": "none",
"requestClientUrl": "none",
"requestClientLogoUrl": "none",
"requestDescription": "none",
"active": false,
"accepted": false,
"start": "2018-04-18T09:26:57.000Z",
"end": null,
"permissionsActive": null,
"permissionsLatest": {
"dateCreated": "2018-11-14T23:51:40+0000",
"purpose": "none",
"start": "2018-11-14T23:51:40+0000",
"period": 432000000,
"cancelAtPeriodEnd": false,
"termsUrl": "none",
"conditions": {
"name": "data-debit-id-test-name",
"bundle": {
"test": {
"endpoints": [
{
"endpoint": "rumpel/profile"
}
]
}
}
},
"bundle": {
"name": "data-debit-id-test1",
"bundle": {
"test": {
"endpoints": [
{
"endpoint": "rumpel/profile"
}
]
}
}
},
"accepted": false,
"active": false,
"end": null
}
}

For explanation of what the above structure means you can read here.

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Approve Data Debits

Approving Data Debits is something that not all the apps can do directly. This has to do with the permissions of the apps. Currently, only HAT App and web Rumpel cad approve Data Debits. Due to the restrictions this guide will explain how to use the generic way of doing it, that will work on all the apps. In order to approve a Data Debit you have to open in a browser, if you aren't sure how to do it you can read here, the URL below:

"https://$hatAddress/#/data-debit/$dataDebitID/quick-confirm?redirect=$appScheme://$dataDebitHost&fallback=$appScheme/dataDebitFailure"
  • hatAddress is the (fully qualified domain) address of the PDA, e.g. postman.hubat.net

  • dataDebitID is the data debit id that you want to approve

  • appScheme is the URL where the user should be sent to after completing authentication. Optional. For an Android

    application that would probably be: $applicationName://success and has to be added in the AndroidManifest file of the

    project in Xml as data host and scheme. You can read more here

  • dataDebitHost is a string after the :// part in the app url Scheme. For example dataswift-sandbox://dataDebitHost. With the

    dataswift-sandbox:// Android will launch your app. With the dataDebitHost you will know that this URL is specifically for the Data Debits

The process is the same as when logging user in. Browser will open, user will have to complete their password, and then one of the 2 redirect URL will be called depending if the request was successful or has failed for some reason. The app should know how to handle both scenarios. You can read more here.

Get Data Debit values

You can fetch the values of a specific Data Debit by using the next function:

HATDataDebitsService().getDataDebitValues(
dataDebitKey: dataDebitKey,
userToken: userToken,
userDomain: userDomain,
succesfulCallBack: gotDataDebits,
failCallBack: failedGettingDataDebits)
  • dataDebitKey is the data debit key that we want the values from.

  • userToken is the user's token in order to authenticate with the PDA.

  • userDomain is the user's PDA address in order to form the url to fetch the values of the Data Debit.

  • succesfulCallBack is a callback function, that is called when the request was successful, with a type of

    ((HATDataDebitValuesObject, String?) -> Unit). This is the structure of Data Debit Values. More on that in the next section.

    The second parameter is an optional String, the refreshed user token that the PDA returns.

  • failCallBack is a callback that is called when the request has failed. They type of the function is ((HATError, String?) -> Unit). HATError

    is a custom object describing the errors that have occurred during the querying of the PDA. The second parameter is the dataDebitKey.

A successful response will have statusCode 200 and look like this:

{
"bundle": {
"profile": [
{
"endpoint": "rumpel/profile",
"recordId": "137e0409-effc-454f-b1f0-56fe87ad7762",
"data": {
"name": "",
"nick": "",
"photo_url": "https://postman.hubat.net/api/v2.6/files/content/rumpel1537454603415.jpg"
}
}
],
"notables": [
{
"endpoint": "rumpel/notablesv1",
"recordId": "d1d26a7d-0c7f-4ba2-8caa-13a4b5671444",
"data": {
"kind": "note",
"author": {
"name": "",
"phata": "postman.hubat.net",
"nickname": "",
"photo_url": ""
},
"shared": true,
"message": "oooo",
"shared_on": [
"phata"
],
"created_time": "2018-11-08T11:24:58Z",
"updated_time": "2018-11-08T11:24:58Z"
}
}
]
}
}

Inside the bundle there are 2 different values. profile and notables. Those 2 values are Arrays that contain the actual data for each endpoint specified when this Data Debit was created. In this example the 2 structures are the profile and notables.

A request that has failed will look like this:

{
"error": "Not Authenticated",
"message": "Not Authenticated"
}
  • error is the error that has occurred.

  • message a more descriptive message about the error that has occurred

Data Plugs

In the HAT ecosystem, a Data Plug aka Data Plugin is a minimal API-to-API web service with the primary purpose of fetching data from 3rd party API and pushing it to an individual’s PDA. Due to the security considerations and limited scope of required functionality, each data plug is granted a write-only access to any particular PDA.

Fetch Data Plugs and Applications

HAT API Android provides an API call for you to fetch all the available Data Plugs:

HATExternalAppsService().getExternalApps(
userToken: userToken,
userDomain: userDomain,
completion: availablePlugsReceived,
failCallBack: errorRetrievingDataPlugs)

As you would have probably noticed, the function name is getExternalApps. Applications and Data Plugs are not only represented by the same structure but they have the same API as well.

  • userToken is the user's token in order to authenticate with the PDA.

  • userDomain is the user's PDA address in order to form the url to fetch the Data Plugs.

  • completion is a callback function that is called when the request was successful with a type of ((List<HATApplicationObject>, String?) -> Unit).

    The first parameter is an array of HATApplicationObject. This is the structure of Data Plugs and Applications. More on that in the next section.

    This array contains all the Data Plugs and Applications on the PDA. The second parameter is an optional String,

    the refreshed user token that the PDA returns.

  • failCallBack is a callback that is called when the request has failed. They type of the function is ((HATError) -> Unit). HATError

    is a custom object describing the errors that have occurred during the querying of the tables in the database.

A successful response will have statusCode 200 and look like this:

[
{
"application": {
"id": "hatapp",
"kind": {
"url": "https://rumpel.hubofallthings.com",
"iosUrl": "https://itunes.apple.com/app/id1303181222?mt=8",
"kind": "App"
},
"info": {
"version": "1.2.5",
"updateNotes": {
"header": "We’ve made some improvements to the user experience and made clear your legal rights over your data so that you can access new services on your HAT app. Please accept our updated [terms of service](https://hatdex.org/terms-of-service-hat-owner-agreement) and [privacy policy](https://hatdex.org/privacy-notice-hat-owner-services-and-hat-accounts) to continue using HAT.",
"notes": [
"We made clear the difference between “your data” in your HAT microserver and “HATDeX account data” which we need to create your HAT microserver",
"We made clear the relationship between HAT permissions and instructions that you control within the HAT versus HATDeX platform services and third party services that others control (when you give permission) to help you easily view, manage and organise the data within the HAT",
"We made clear the way data debits and data plugs operate based on the permissions and instructions you control and the services we control to execute your instructions",
"We updated the way we use your information for HATDeX account data in accordance with GDPR",
"We updated the way apps, plugs and tools are rated to give HAT owners full transparency on services and apps \"Powered by HAT\". Find more info [here](https://www.hatcommunity.org/hat-dex-rating)"
]
},
"published": true,
"name": "HAT App",
"headline": "The HAT Dashboard",
"description": {
"text": "\n Your digital life is made up of hundreds of day to day interactions on the Internet: liking and sharing content, booking train tickets, tracking your activity. It's time to see them all come together, in one place, so you can benefit from analysis, insights and self-discovery on your personal data.\n\n CONNECT DATA PLUGS\n Link your Twitter, Facebook, Spotify, FitBit, Google Calendar and iPhone GPS locations to your HAT, and pull in all that data in real time. Your data is kept in an entirely private space, owned by you – we don't see it, third parties don't see it, no-one sees it but you.\n\n YOUR DIGITAL LIFE\n View your data in a live feed where you can experience and engage with it as it arrives into your HAT. Facebook posts, workouts recorded by FitBit, photos you've shared – see it all in one integrated feed. Search your data by date range to know exactly where you were and what digital actions you took at any given time.\n\n PUBLIC PROFILE\n Save your personal information privately, and customise exactly which parts you want to share publicly on your Personal HAT Address – your own public URL. Think of it as the front door to your HAT, and use it to display the information you'd like.\n\n ME, MYSELF AND AI\n We will be releasing the Smart HAT Engine (SHE) soon – this engine on your HAT will enable you to subscribe to different types of analytics and machine learning functions to give you daily insights and help you make better decisions with your data, completely in your private space. Start claiming your data for yourself so that you can better use AI in your life.\n\n One HAT, so many possibilities: our HAT Community of startups and app makers is creating a new generation of Internet applications sitting on your HAT. With all the data in the account, you can donate your data to research, spend it, match it and exchange it for services. Join the community to be part of the movement to change the Internet at https://hatcommunity.org\n\n ",
"markdown": "\n Your digital life is made up of hundreds of day to day interactions on the Internet: liking and sharing content, booking train tickets, tracking your activity. It's time to see them all come together, in one place, so you can benefit from analysis, insights and self-discovery on your personal data.\n\n ### Connect Data Plugs\n\n Link your Twitter, Facebook, Spotify, FitBit, Google Calendar and iPhone GPS locations to your HAT, and pull in all that data in real time. Your data is kept in an entirely private space, owned by you – we don't see it, third parties don't see it, no-one sees it but you.\n\n ### Your Digital Life\n\n View your data in a live feed where you can experience and engage with it as it arrives into your HAT. Facebook posts, workouts recorded by FitBit, photos you've shared – see it all in one integrated feed. Search your data by date range to know exactly where you were and what digital actions you took at any given time.\n\n ### Public Profile\n\n Save your personal information privately, and customise exactly which parts you want to share publicly on your Personal HAT Address – your own public URL. Think of it as the front door to your HAT, and use it to display the information you'd like.\n\n ### Me, Myself and AI\n\n We will be releasing the Smart HAT Engine (SHE) soon – this engine on your HAT will enable you to subscribe to different types of analytics and machine learning functions to give you daily insights and help you make better decisions with your data, completely in your private space. Start claiming your data for yourself so that you can better use AI in your life.\n\n One HAT, so many possibilities: Our HAT Community of startups and app makers is creating a new generation of Internet applications sitting on your HAT. With all the data in the account, you can donate your data to research, spend it, match it and exchange it for services. Join the community to be part of the movement to change the Internet at https://hatcommunity.org\n ",
"html": "\n <p>Your digital life is made up of hundreds of day to day interactions on the Internet: liking and sharing content, booking train tickets, tracking your activity. It's time to see them all come together, in one place, so you can benefit from analysis, insights and self-discovery on your personal data.</p>\n\n <h3>Connect Data Plugs</h3>\n\n <p>Link your Twitter, Facebook, Spotify, FitBit, Google Calendar and iPhone GPS locations to your HAT, and pull in all that data in real time. Your data is kept in an entirely private space, owned by you – we don't see it, third parties don't see it, no-one sees it but you.</p>\n\n <h3>Your Digital Life</h3>\n\n <p>View your data in a live feed where you can experience and engage with it as it arrives into your HAT. Facebook posts, workouts recorded by FitBit, photos you've shared – see it all in one integrated feed. Search your data by date range to know exactly where you were and what digital actions you took at any given time.</p>\n\n <h3>Public Profile</h3>\n\n <p>Save your personal information privately, and customise exactly which parts you want to share publicly on your Personal HAT Address – your own public URL. Think of it as the front door to your HAT, and use it to display the information you'd like.</p>\n\n <h3>Me, Myself and AI</h3>\n\n <p>We will be releasing the Smart HAT Engine (SHE) soon – this engine on your HAT will enable you to subscribe to different types of analytics and machine learning functions to give you daily insights and help you make better decisions with your data, completely in your private space. Start claiming your data for yourself so that you can better use AI in your life.</p>\n\n <p>One HAT, so many possibilities: Our HAT Community of startups and app makers is creating a new generation of Internet applications sitting on your HAT. With all the data in the account, you can donate your data to research, spend it, match it and exchange it for services. Join the community to be part of the movement to change the Internet at https://hatcommunity.org</p>\n "
},
"termsUrl": "https://hatdex.org/terms-of-service-hat-owner-agreement-2018-10-01",
"dataUsePurpose": "The HAT App only uses your data to display it back to you. It does not share your data with any third-parties or store it outside of your personal HAT.",
"supportContact": "contact@dataswift.io",
"rating": {
"score": "Z***"
},
"dataPreview": [
{
"source": "she",
"date": {
"iso": "2018-10-31T08:54:26.303Z",
"unix": 1540976066
},
"types": [
"note"
],
"title": {
"text": "HAT Private Micro-server created"
},
"content": {