Contracted PDA API

Understanding & implementing Contracted PDAs.

Contracted PDAs Implementation Guide

The Contracted PDA feature allows an application developer to gain short-lived read-and-write access to PDAs that have given prior permissions for such access.

You must apply to gain access to the Contracted PDA feature. The process to do this is outside the scope of this document. Please contact your Dataswift account manager or product@dataswift.io for more information.

Once access to the Contracted PDA feature is granted, the application developer will be assigned a Contract which defines the namespaces for which read and/or write access are requested. The contract will be tied to the application designed by the developer. When the PDA owner signs on to the application, the HMI screen presented will ask for permissions to have the PDA join the Contract.

This document will show you how to read and write data to the PDA using the Contracted PDA feature. You need to be given access credentials to the Contracted PDA feature by Dataswift.

Access Credentials

The access credentials include 2 pieces of information:

  1. Contract Id - <contract_id>

  2. Long-Lived Token - <long_lived_token>

    • This is the private key that must be kept safe and unexposed.

    • This key is required to obtain a Short-Lived token which can then be used to access all the PDAs that have joined the Contract.

Getting the Short-Lived Access Token

The Long-Lived Token is required to obtain the Short-Lived Access Token which can then be used to perform data i/o operations on the associated PDAs. The API call to do so is:

GET https://contracts.hubat.net/v1/contracts/keyring
    headers: {
        ‘Authorization: Bearer <long_lived_token>
    }

The response to the above API call will be in JSON similar to

{
"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiIsImtpZCI6IjNhMzlhZDMzLTAzNGMtNDE0Ny1hNTMwLTZmNmRlMjYyZGM1ZSJ9.eyJpc3MiOiJkYXRhc3dpZnRhZGp1ZGljYXRpb24iLCJleHAiOjE1OTMyNzkzMDQsImNvbnRyYWN0SWQiOiIyMWEzZWVkNy01ZDMyLTQ2YmEtYTg4NC0xZmRhZjcyNTk3MzAifQ.KDFqJAgrMJiKq67acaHKPZ7iRjkyxP_ZFCGZwoKX1rNMBHW5TxY7OSPkDa0bbOM7rLsmM4FrZxicUzOGErBd7nJ_T3pCj6AO3xgklkTaTiU59LLVwVktOBGk7G82EtJ5i_wy-2HqCRGOILvVmWt47Liw5tx5H0masoqVBMFZ4ZQ",
"associatedHats": [
  "bobtheplumber",
  "jillthecarpenter",
  "johnthebuilder",
]
}
  • The token node is the Short-Lived Access Token. <short_lived_access_token>

  • The associatedHots contains the PDAs that have joined the contract.

  • To form the fully qualified domain of the associated PDAs, append the domains hubat.net and hubofallthings.net respectively for sandbox and production environments.

Reading and Writing Data via Contracted PDA API

Both the APIs for reading and writing data via Contracted PDAs are POST commands. The API calls are made to the individual PDAs. Unlike conventional PDA data calls, the ApplicationToken is no longer required in the headers.

To write data:

POST https://<fully_qualified_pda_domain>/api/v2.6/contract-data/create/<contract_namespace>/<data_endpoint>

To read data:

POST https://<fully_qualified_pda_domain>/api/v2.6/contract-data/read/<contract_namespace>/<data_endpoint>

The Data Body

For both the above API calls, a data body is expected. The structure of the data body is as follows:

{
   "token":"<short_lived_access_token>",
   "contractId":"<contract_id>",
   "hatName":"bobtheplumber",
   <existing_body>
}

Generally speaking, the data body is the same as that of the PDA Direct Data API with the addition of 3 parameters – token, contractId and hatName.

Data Body for Data Writes

For write data, the existing_body is the same as what would be posted in the PDA Direct Data API -> Create Data. For example, if the PDA Direct Data API data body is

{
    "something": "Normal JSON",
    "nested_data": {
         "nested": "no problem",
         "value": true,
         "id": 3
    }
}

Then the body for data creation using the Contracted PDA would be

{
        "token":"<short_lived_access_token>",
        "contractId":"<contract_id>",
        "hatName":"bobtheplumber",
        "something": "Normal JSON",
        "nested_data": {
                "nested": "no problem",
                "value": true,
                "id": 3
   }
}

Data Body for Data Reads

For reading data, the original GET parameters of orderBy, ordering, skip and take are now part of the POST body. For example:

{
   "token":"<short_lived_access_token>",
   "contractId":"<contract_id>",
   "hatName":"bobtheplumber",
   "orderBy": "timestamp",
   "ordering": "ascending",
   "skip": 100
}

Exceptions

The Contracted PDA API would throw the same exceptions as the Direct Data API under the same scenario, such as:

  • 404 thrown for invalid namespace and/or data endpoint

  • 403 thrown for valid but unauthorised namespace and/or data endpoint

Additionally,

  • 403 would be thrown if the Short-Lived Access Token has expired

  • 403 if the Contracted PDA API is used against a PDA that has not joined the associated Contract

Data Body for Data Updates

To update data within a Contracted namespace the same process defined for Rich Data is used. The simplest way to start is to read the data first and use the response from the read as a starting point.

If we use the following read as an example:

POST https://<HAT_USER>/api/v2.6/contract-data/read/<contract_namespace>/<endpoint_root>/<endpoint_part>
{
   "token":"<short_lived_access_token>",
   "contractId":"<contract_id>",
   "hatName":"bobtheplumber",
}

You will get the response of the form:

[
  {
    "endpoint": <contract_namespace>/<endpoint_root>/<endpoint_part>,
    "recordId": "8dbaf954-c13a-46da-9c92-be3e822b6a0d",
    "data": {
      "nested_data": {
        "id": 11111,
        "value": true,
        "variable_string": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUz"
      }
    }
  }
]

We can update it using the following request:

PUT https://<HAT_USER>/api/v2.6/contract-data/update/<contract_namespace>
{
   "token":"<short_lived_access_token>",
   "contractId":"<contract_id>",
    "hatName":"<hat_name>",
    "body": [
      {
        "endpoint": <contract_namespace>/<endpoint_root>/<endpoint_part>,
        "recordId": "8dbaf954-c13a-46da-9c92-be3e822b6a0d",
        "data": {
          "nested_data": {
            "id": 22222,
            "value": false,
            "variable_string": "zUSJiOicGbhJCLiQ1VKJiOiAXe0Jye"
          }
        }
      }
    ]
}

Last updated