TrialKit API Basics

TrialKit's wBasics: Web Services and Endpoints, and Commonly Used Calls

This article covers the basics of TrialKit's API, but is not a comprehensive library of endpoints. If you cannot find what you need here, please submit a request for additional parts of the system that you need to connect to.

Table of Contents:

API Overview

Gaining Access to the API

REST Error Conditions

Signing In

Get a List of Hosts to which you belong

Get the Current Default Host and Study

Set or Change Default Host

Get List of Studies for Default Host

Set a Default Study

Get a List of Study Sites

Set a Default Site

Get a List of Site Subjects

Get All Records For a Subject

GET Form Data, Values, and Queries

Get User Preferences

Passing Different Field Type Values

Register a New Subject

Add or update subject records

Import a File Into An Existing Record

Getting Scheduled Visits and their Related Forms

Get Entire File Repository

Sign In Audit for the current host

Get a File from the repository

Getting Wearables Device data (HealthKit)


API Overview 

The TrialKit web API follows the REST standard entirely.

This knowledge content is intended for experienced Developers who have some experience with REST APIs and the system they will be using. The terms API, WebAPI and Web Service are used interchangeably throughout this help content.

The TrialKit API provides the necessary steps to do the following:

  • Authenticate

  • Make a standard Get Call

  • Make a standard Post Call

There is a call for every function within TrialKit. Every call does its own authentication by encoding the Email / Password of the TrialKit user and passing that encoded string to the web service call.

GET and POST calls are made in this format: <URL>/Controller/Method/Route

If a POST call is being made, the parameters are passed in the body. The body requirements are detailed

Accessing Data

There are two call types, TOC and Host Web Service. Both are web services. Sometimes you must call the TOC, especially when changing hosts. The TOC will return to you the  URL of the Host Web Service. Then, all calls you make for that host and its corresponding studies, you will use the Host Web Service URL. 

Prior to making any web service calls, you must gather two pieces of information that you will  use in the header of your REST calls: 

  • E-Mail / Password combination. This is assigned to you by your study administrator. You can (and should) download TrialKit and Sign In with these credentials. 

  • From Access Key. The From Access Key is assigned to you by CDS. It is a text string that allows access to pre-authorized APIs.

  • Optional: Pre-defined authorized IP address list. If an organization requires an additional layer of security, the access key can require that the Caller be coming from an authorized IP address.

Returned Data

All data returned by the web service comes in a standard Key/Value Dictionary. All modern languages use dictionaries to handle data and you should be at least familiar with how to access components within the dictionary. Much of the data returned by API calls is stored in arrays of dictionaries. Understanding key/value pairs is important.

It is recommend that you download the TrialKit app, sign in with your credentials and familiarize yourself with the system for a better understanding of the system structure and functions from the front end that you will be accomplishing through the API.

TrialKit Access

TrialKit is a cloud-based data collection and trial management system. A single sign-in can get you access to a host or multiple hosts across clouds, seamlessly. As a Developer, you should have a thorough understanding of the process involved with switching hosts. Especially when those hosts exist on different clouds. This section will detail that process.

The 'TOC'

This is a term used to refer to the central user library that directs all user membership and access across global servers.

The TOC keeps track of:

  • All servers ("Clouds")
  • All users across clouds in the system
  • All hosts across clouds in the system
  • Users by hosts across all clouds

The TOC has a table of servers that exist. Each server has an API URL for access. When you switch hosts, you should always query the TOC to get the API URL so that you can make the calls to the needed server.


Default Hosts and Studies

The possibility of having access to multiple Hosts and Studies requires that you set the given host and study as the default for your user account prior to making calls to accomplish something on that study. By doing so, you make subsequent calls to query data from the host and study by authenticating. Once authenticated, the system pulls the current host and/or study when servicing calls. This restricts developers to only accessing data for the hosts and studies to which they belong. 

To use the API on a host or study, you must set the host or study as the default first. If the API user only belongs to a single study, the default will always be the same and does not need to be set, but is still a good measure to take.


Additionally, Hosts can exist on different servers which have different URLs. Based on the server where the user’s current default host exists, the corresponding URL must be used when calling the API. That URL can be retrieved when getting the current host described further below.

It's recommended to have a dedicated user account that makes api calls for a given study. This prevents the risk of calling the api on an unintended study. For example, user study1apiuser@company.com and study2apiuser@company.com are users on separate studies making the same api calls, but without a chance of calling the other study.

 


API Authentication

API calls get individually authenticated, so the calling user must have access to the host and study similar to regular users. Additionally, the user's role within the study must have the necessary permissions to accomplish the tasks being conducted via the API. A Study Administrator can add the user and manage its permissions as needed.

Tips for Study Administrator:

  • Create a generic API user and role, so API calls are not made from an individual's user account.
  • To mitigate risk, it's normally best to configure a unique API user role and grant it with only the permissions it needs based on the API activities being utilized. For example, if the API is being used to insert data into a form, the API user role does not need access to other forms or to other permissions like creating or closing queries.

Once the API user credentials are setup, you will use the those credentials, along with an access key supplied by CDS, to authenticate each call to the API.

The data that can be accessed will be restricted based on your role and its corresponding permissions granted by the Study Administrator. Additionally, for security reasons, the access key supplied by CDS is restricted to specific endpoints required based on the scope of integration. 

 


REST Errors

There are two ways that the REST standard can report errors. There are standard web service errors such as 401 and 404. Those errors mean you probably have an error in the URL being used to call the web service.  

The second and most important error condition sends back a 200 code (success), but the return dictionary contains the key: "error". The value of the key is the actual error message. The call failed any time that the "error" key appears in the return dictionary. Your code should always check for an "error" key first on any 200 return condition. Here is a quick snippet of how Objective C  handles this condition: 

// Get data from the web service

2NSError *e = nil; 3id jsonObject = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e]; 4NSDictionary *u = (NSDictionary *)jsonObject; 5 6[General stopActivity:self.aivc]; 7 8

// Check for error here

9NSString *errTxt = [General getStringFromDict:u :@"error"]; 10if (![errTxt isEqual: @""]) 11{ 12 NSString *body = [NSString stringWithFormat:@"%@ %@. %@", NSLocalizedString(@"webservice_returns_error", @""), errTxt, NSLocalizedString(@"email_sent_to_CLSDS", @"")]; [General showAlert:NSLocalizedString(@"set_new_study_failed", @"") :body :NSLocalizedString(@"ok", @"") :self]; 13 return; 14} 15


Signing In

TrialKit is a multi-cloud platform. Basically, that means that  TrialKit data is stored across clouds. In order to access that data, you must first Sign In. That gives you information about your user account, but also it tells you the server that your current host resides on. That server has a Host Web service URL and you will collect that and use it to access data from that host, including all study and patient data. 

Simply enter the TOC URL as a POST: https://toc.clinicalstudio.com/api/toc/11

Next set the following headers similar to what you see: 

You should have been assigned an Access Key. That is an email address that is used to authenticate your developer account. That key should be used in the FROM header.

Next, click the SEND button to send your request to the server. You should receive a 200 code in return. The following is the documentation for the Sign-In method:

In your code, you will want to store this data. The server_webservice_url is of particular importance. You will use it to access all your study and patient data from the current host. All of the REST calls are made in a similar fashion. You just need to distinguish between a call to the  TOC and a call to the Host Webservice. 

Get a List of Hosts to which you belong

GET: https://toc.clinicalstudio.com/api/toc/9

If you will be accessing data across different hosts by a single API user, then this method is very important. 

Get the Current Default Host and Study

GET: https://toc.clinicalstudio.com/api/toc/10

This will get the host and study the user is currently set on. It’s an important check to make if the API user belongs to multiple studies, to be sure subsequent calls made are being done in the intended study.

Set or Change Default Host

It is possible you may need to set another host as the default. 

Most operations work on the default host and default study so setting the default host is very important if any user calling the web service has access to multiple hosts and studies.


This is a very simple call. The list of hosts you belong to can be gathered from a separate call. To change a host, you must use one of those host IDs you belong to. The system will prevent setting a host that the calling user is not a part of.

POST: https://toc.clinicalstudio.com/api/toc/1

Body:

{
    "host_id" : "8000"
}

Get List of Studies for Default Host

GET: <URL>/study/12 

All previous listed calls have called the TOC web service to gather information. Once the user has signed in and set the default host, a default study must be set. To do that a list of the studies is needed from the default host.

We must first capture the web service URL for the default host. This can be done in a variety of ways, but when you set the default host, this URL was returned. Depending on the cloud you are working on it will look something like this:

https://webapi.trialkit.com/api

We will use this web service now to retrieve host, study, and patient information.

The first step is to get a list of studies, this is another very simple operation. Remember it operates on the default host. We will be calling the study controller to get a list of studies that belong to the default host. The call should look something like this:

https://webapi.trialkit.com/api/study/12

Set a Default Study

POST: <URL>/user/2

Body:

{
    "st_id" : "8310"
}

This service returns nothing if it works. Like all other services, if it does not work it will return "error" as a key in the dictionary. Services do not have to return anything. The 200 status is enough for some services. 200 along with an empty dictionary means the call succeeded and you can move on. 

Get a List of Study Sites

GET: <URL>/site/1

Each study contains a list of sites that can contribute content to the study. That content is usually in the form of patient data across various sites which are entering data in the study. Users can belong to one or more sites depending on their role. Administrative users usually belong to all sites in the study.

To get a list of all the sites to which we belong, the site controller must be called.

Set a Default Site

POST: <URL>/site/9

Body:

{
    "curr_site_id" : "18"
}

Get a List of Site Subjects

GET: <URL>/subject/1/<site_id>

This is the first GET service where you are passing two parameters in the URL above. The two parameters tell  REST how to route the call. Once routed the first parameter routes the call within the controller. In this case, you are saying route this call to the Subject Controller. From there, find the get procedure that requires 2 header parameters. Once there, check the first parameter for the route within the subject controller. In this case, get all subjects for the passed site.

The site ID is obtained from another call.

By retrieving a list of subjects for any given site to which you belong, you are now ready to access the subject data.

Get All Records For a Subject

GET: <URL>/subject/3/<sub_id>/<form_id>

With the list of subjects previously retrieved, it is time to ask the web service to return all the completed records for a given subject. Optionally, you can pass a specific form_id and filter by just that form. If you do not want to filter by form, simply pass a -1.

This call returns a list of records that belong to the sub_id that you passed.

Usually, the important factor being retrieved from this information is the trans_id of each record. With the trans_id, it will be possible to then get the data from that record next.

Get Form Data, Values, and Queries

GET: <URL>/form/11/<trans_id>

The trans_id was received in the prior call to get all subject records. Simply passing that to this method returns all of the data required to read a record.  

Records are dynamic in TrialKit. That means that forms are created by Study Builders on the fly. There are no hard-coded form layouts. In order to make sense of the data you actually need to parse the form data dictionary, which is returned in the method.


GET User Preferences

<URL>/user/11

It is very important to verify that the correct date format is being passed later on when doing any data updates on date or time fields.

In order to send receive dates to the API, we must know the date and time format for our user account. This can all be hardcoded, but if you want to be to able freely change those formats, and still have your code work, you will need to retrieve those formats from the User Preferences.

Date Format options are listed below.

Pay particular attention to the ID column in the above tables. That ID is what the API will pass to you when retrieving the user preferences.

Date Formats:

ID 

Format 

Display

MM-DD-YYYY 

10-16-2013

Mon-DD-YYYY 

Oct-16-2013

DD-MM-YYYY 

16-10-2013

DD-Mon-YYYY 

16-Oct-2013

YYYY-MM-DD 

2013-16-10

Time Formats:

ID 

Format 

Display

HH:MI AM 

02:00 pm

HH24:MI 

14:00

Passing Different Field Type Values

This section provides examples of how data should be passed into the various data types (fields on forms):

Date/Time

The example assumes user preference is dd-mon-yyyy (4) hh:mi24 (2)

Alpha characters in date are not case-sensitive


"fld_id": "99", 
"fld_value": "18-Oct-2001 17:01", 
"fld_name": "dateandtime" 

String

{
"fld_id": "99",
"fld_value": "Hello World",
"fld_name": "string_field" 
}

Memo


"fld_id": "99", 
"fld_value": "Hello World\n\nThis is a memo field.", 
"fld_name": "string_field"

Choice/Radio

fld_value_decode is an optional parameter


"fld_id": "99", 
"fld_value": "3", 
"fld_value_decode": "Female",
"fld_name": "gender" 

Number

Stored as Double Precision floating-point numbers


"fld_id": "99", 
"fld_value": "34.67", 
"fld_name": "age" 

Checkbox

fld_value_decode is an optional parameter


"fld_id": "99", 
"fld_value": "1", 
"fld_value_decode": "Checked",   <--Optional
"fld_name": "check" 

Partial Date

Assumes user preference is dd-mon-yyyy (4)


"fld_id": "99", 
"fld_value": "00-Oct-2001", 
"fld_name": "partialdate" 
}


Register a New Subject

POST: <URL>/form/16

When registering a new subject, you must complete the registration form. That form is created by the Study Builder and can be extremely simple or very complex. We generally encourage the registration process to be as simple as possible, usually collecting only subject ID, date, and consent.

This example will show a registration form with only two fields.

All that is required by TrialKit is to have a date of registration. Any other field data depends on how the form was designed. The first date is known as the Registration Start Date and is used to calculate visit intervals and other items based on rules created by the study builder. For us, when registering a new subject, this is the only data that we need to pass.

All that has to be passed is the actual form data for the registration form.  Optionally, you can pass another key/value pair to override the system-generated Subject Profile ID. The Subject  Profile ID is used to identify a subject. If, when registering a  new subject, you want to override the Subject Profile ID, you can pass that in the body of the call as well.

Here is a look at the body of the Post which is a JSON string: 

{
  "field_value_list": [
    {
      "fld_id": "5",
      "fld_value": "02-Jan-2020",
      "fld_name": "enrl_enrl_dt"
    },
    {
      "fld_id": "132",
      "fld_value": "Male",
      "fld_name": "gender"
    }
  ],
 "sub_profile_id" : "sub_0002"
}

Notice the last key/value pair is the sub_profile_id. This tells TrialKit to override the system and use the value of this key as the Subject Profile ID. 

 

The subject will be created in the default site, which is assumed to have already been set based on where the subject needs to be created.

 


Add or update subject records

POST: <URL>/form/17

Creating a New Record

The trans ID is kept empty ("-1")

Body:

{"sub_id" : "1",
"trans_id" : "-1",
"form_id": "258",
"int_id" : "15",
"vee_id" : "-1",

 "field_value_list": [
    {
      "fld_id": "37",
      "fld_value": "1",
      "fld_name": "ieyn"
    },
    {
       "fld_id": "463",
       "fld_value": "27-Jul-2020",
       "fld_name": "rfstdtc"
    },
       {
       "fld_id": "790",
       "fld_value": "treatmentarm",
       "fld_name": "ierand"
    }
]

If updating an existing record, the trans_id is needed. This is obtained from the subject/3 call. The trans_id is the primary key for all subject visit/event records. For example, an Adverse Event form is considered a subject visit/event record and uses the trans_id as its primary key. That visit/event record is related to the subject by the sub_id. In addition, records can be scheduled, unscheduled, or considered log forms. 

Updating an Existing Record

The only difference with updating a record is the trans_id being defined.

Body:

{"sub_id" : "1",
"trans_id" : "217",
"form_id": "258",
"int_id" : "15",
"vee_id" : "-1",

 "field_value_list": [
    {
      "fld_id": "37",
      "fld_value": "1",
      "fld_name": "ieyn"
    },
    {
       "fld_id": "463",
       "fld_value": "27-Jul-2020",
       "fld_name": "rfstdtc"
    },
       {
       "fld_id": "790",
       "fld_value": "treatmentarm",
       "fld_name": "ierand"
    }
]

When updating existing records, there is only a need to pass the data being updated. Other data fields will be left alone. This same behavior is not supported for updating normalized tables. Any pre-existing data you don’t want to change must also be passed.

There are a few rules with scheduled and unscheduled visits; the most important is you can only have a single form completed for a single interval.  If you want to update that form, you must first retrieve that form's trans_id. Log forms can have multiple records as they are just stored longitudinally. However, if your study builder restricts log forms to a single record and you try and save multiple records, the API will return an error.

 

Import a File Into An Existing Record

POST: <URL>/api/image/<level_id>/<form_id>/<field_id>/<trans_id>/<row_pk>/<sequence>

<level_id> = should always = 3 if uploading to the subject level
<form_id> = ID of the form to upload the file
<field_id> = ID of the field on the form above to upload the file
<trans_id> = Transaction ID of the saved subject form that the file should be uploaded to
<row_pk> = The record id (primary key) when uploading to a field that exists in a table control on the form. Set to -1 if using an upload field NOT in a table.
<seq> = Sequence number if uploading multiple files to the same field (ordering in display)

Sample cURL of call:
curl --location 'https://<your_base_url>/api/image/3/344/5/749/-1/1' \
--header 'From: <your_from_id>' \
--header 'Authorization: Basic <your authorization>' \
--form '=@"<file_to_upload>"'

Successful import will return a 200 response.

 

Get Scheduled Visits and their Related Forms

GET: <URL>/subject/4/<sub_id>

This retrieves the scheduled visits for a given subject ID. The visit schedule for subjects within a study can vary based on the Scheduled Visit Cohort that is currently assigned to a particular subject. 

This method retrieves the assigned cohort for the passed subject, and then goes and retrieves the scheduled visits for that cohort/patient. In addition, for each schedule visit interval, it also returns the list of forms and activities that have been assigned.

Get File Repository

GET: <URL>/study/17

The calling user’s role must be granted access to the file repository in order for this API to return any data. If the calling user does have access to the file repository, this call will return information for each file uploaded for the study for all sites. Below is a sample that shows the keys and values returned for each document. 

        {
            "doc_fld_id": "24",
            "doc_user_id": "126",
            "form_name": "Procedure",
            "doc_form_id": "281",
            "doc_date": "2021-11-17T16:27:40.921023",
            "doc_date_txt": "17-Nov-2021 16:27",
            "doc_id": "27",
            "doc_fn_ext": ".png",
            "doc_key_value": "395",
            "doc_type_txt": "Participant",
            "trans_date_txt": "29-Oct-2021",
            "doc_type": "3",
            "doc_key_value_txt": "42-001",
            "user_email": "studyadmin@someinstitution.com",
            "doc_level_id": "271",
            "doc_orig_name": "BaselineChestxray.png",
            "visit_type_txt": "Baseline",
            "doc_row_pk": "-1"
        },


Sign In Audit for the current host

POST: <URL>/report/20

Pass in "pageno" key to return chunks of 100, otherwise will return up to 10000 rows. 

Pass in key "getcountonly": true to get just a count of how many audit records there are

 


Get a File from the repository

GET: <URL>/doc/3/<doc_id>

API users can download specific documents that have been uploaded during the study. When downloading a specific document from the file repository the TrialKit system will ensure the calling user has access to the particular file by checking the site/form/field rights.  After the user’s access is authorized, the API will return the document in the body of the HTTP response object. The body in the API’s response will be the binary data that makes up the actual document. This data can be saved as JPG, PDF, or the specific type of the file that was requested. The Content-Disposition key of the returned HTTP response will contain the filename and will be set as follows: “attachment; filename=BaselineChestXray.png”

Downloading a Binary Object

GET: <URL>/image/3/<form_id>/<field_id>/<trans_id>/<row_pk>

Trialkit can collect many forms of binary data, including image, audio, av, pdf and more. Those binary objects are stored by field. For example you may have a signature field, where a user  must sign a form. To download the actual image, you must call the image controller. 

The TrialKit API, will stream the data down to your call. The data being streamed is the actual binary data that makes up the field object, such as a JPG file or PDF file. Any MIME type that can be entered into the content-type header, can be streamed to your code. 

Getting Wearables Device data (HealthKit)

POST: <URL>/activity/5  

Prerequisite: The study must be enabled by CDS for accessing wearable data.

Body:

{
"use_sleep": true,

"use_hrv" : true,

"hk_rhr" : true,

"hk_activity" : true,

"hk_oxygen" : true
}


The endpoints above is a very limited, but commonly used list of options. If any other capabilities are required, please reach out to the support desk.