Rune Labs Data API

The Rune Labs data API allows patient datasets to be uploaded to the Rune platform from a mobile device, or any other environment. Data can be uploaded directly and securely via HTTPS from anywhere, given proper authentication. It also allows read access to patient upload statistics.

Each endpoint is documented in detail, below.

Overview

Key Concepts

Patient

The person about whom data was measured. This may include a StrivePD user, a person with a neural implant, etc. Each patient has a unique identifier ("patient ID"). Patient IDs are generated by Rune and cannot be changed.

Device

The sensor serving as the data source (e.g. a DBS implant, iOS application, wearable device, etc.). A patient may have multiple devices: each one has a unique identifier ("device ID"). Device IDs are generated by Rune and cannot be changed. They do not correspond to any identifier or information from the device itself.

Client

Refers to the patient-facing app itself. A client accesses data programmatically, on behalf of a patient.

A client is associated with exactly one patient. Patients may have multiple clients, depending on how many apps are sending or accessing data. Patients and clients are resources in the Rune platform with unique identifiers, and they are used to control access to patient data.

Dataset

A dataset is a collection of files containing data recorded by a patient's device, over some period of time.

Each dataset has a schema that broadly identifies its contents. The schema_id serves as a typing system for datasets. Supported schema IDs include:

  • medtronic-percept-1
  • medtronic-rcs-1
  • strivestudy-applewatch-1
  • strivestudy-applewatch-md-1
  • strivestudy-healthkit-1
  • strivestudy-healthkit-2
  • strivestudy-spiraltest-1

Schemas specify the number of files that each dataset of a particular type contains, as well as the semantics of each of those files (i.e. what the file is expected to contain). This is used to parse and ingest data after upload.

For example, the strivestudy-applewatch-md-1 dataset schema is used for data collected by the StrivePD app, from the Apple Watch Movement Disorder Kit. Per the schema definition, 3 files must be uploaded for each dataset:

  • tremor - Tremor data
  • dyskinetic -- Dyskinesia data
  • metadata -- Assorted metadata

Authentication

Authentication is required for all API requests. There are several authentication methods:

Client Keys

Client keys provide read and write access to one patient.

To use a client key pair for authentication, the HTTP request must include two headers:

  • X-Rune-Client-Key-Id - client key ID
  • X-Rune-Client-Access-Key - client access key (secret)

Note that each client may only fetch data for its associated patient.

Register a New Client

  1. Log in to the Rune web app as an admin user.
  2. Find the patient you want to access data for, and open Patient Settings.
  3. Open the Clients section.
  4. Create a new client. You can name it anything, though typically it is named after your app.
  5. A default client key pair will be created with the new client. Copy the key ID and the access key before closing the page. The access key will never be shown again.

Create New Client Keys

You can create any number of client keys for a given client, through the Rune web app. If you forget a key, you can always create a new key pair and disable the old.

It is highly recommended that you "rotate" keys for a patient every 3-6 months, by creating a new client key, configuring it in the client (e.g. the patient's app), then disabling the old key. You should do this immediately if you believe the key may have been compromised (e.g. stolen from the device, posted over any insecure/public communication channel, etc).

User Access Tokens

Access tokens are long-lived tokens that belong to a single user of the Rune platform, granting access to any patient in that user's active organization. Only admin users have access to the Data API.

To use an access token for authentication, the HTTP request must include the following headers:

  • X-Rune-User-Access-Token-Id - access token ID
  • X-Rune-User-Access-Token-Secret - access token secret
  • X-Rune-Patient-Id - patient ID for the data being accessed

Create a New Access Token

  1. Log in to the Rune web app
  2. Click on the profile icon in the top right corner.
  3. Click on User Settings.
  4. On the left sidebar, click on Access Tokens.
  5. Click CREATE ACCESS TOKEN.
  6. Copy the token ID and the token secret before closing the page. The secret will never be shown again.

It is highly recommended that you "rotate" user access tokens every 3-6 months, by creating a new token and deactivating the old one. Store your access tokens securely, and do not share them.

JWT

JWTs are generated by the Rune web app upon login. This is not a recommended authentication method for API users.

To use a JWT for authentication, the HTTP request must include two headers:

  • X-Rune-User-Access-Token - JWT
  • X-Rune-Patient-Id - patient ID for the data being accessed

Response Format

All endpoints return JSON-formatted data.

Errors

Standard HTTP status codes are used to indicate success or failure. In the event of most errors, the response body is JSON that includes additional information, with the following format:

{
  "success": false,
  "error": {
    "code": "EnumeratedErrorKind"
    "message": "Human-readable error description",
    "should_retry": false
  }
}

Dataset Upload

Endpoints to initiate a dataset upload or check on the status of an existing dataset.

Initiate Dataset Upload

Initiate uploading a dataset to the Rune platform.

A dataset may consist of one or multiple files. The schema_id is used to determine how many files each dataset contains. See Key Concepts for details about dataset schemas.

For a dataset upload to be considered complete, all files expected by a dataset schema must be uploaded. An empty file may be used as a placeholder.

A successful request contains an "upload_urls" key, with a set of pre-signed URLs: one for each file in the requested schema. For example, for a dataset with a strivestudy-applewatch-md-1 schema, the value would look something like this:

{
    "tremor": {
        "url": "https://...",
        "fields": {"key": "abc"}
    },
    "dyskinetic": {
        "url": "https://...",
        "fields": {"key": "def"}
    },
    "metadata": {
        "url": "https://...",
        "fields": {"key": "ghi"}
    }
}

To upload each file in the dataset, POST a Multipart-encoded file to the corresponding pre-signed "url". This request must include form fields, with the values of the "fields" key.

In addition to the pre-signed URLs, the response also contains:

  • The maximum size for each individual file (by default, 2GiB).
  • An expiration time (by default, 3h). After this time, uploads will not be accepted to the pre-signed URLs. If the URLs expire, the upload can be retried by making a new request to the endpoint, with the same inputs.

Please contact Rune Support if you need an exception to either of these constraints.

To check the status of an existing dataset upload, use the Dataset Status endpoint.

query Parameters
device_id
required
string
Example: device_id=wwxBBbbD

ID of the patient device that recorded this dataset.

schema_id
required
string
Example: schema_id=medtronic-percept-1

Dataset schema ID. See Key Concepts for details about valid schema IDs.

session_id
required
string [ 1 .. 512 ] characters

A string that uniquely identifies the recording session. Requests are considered duplicate if they have the same device_id, session_id, and schema_id. Duplicate requests will return new upload URLs if the upload is not complete. Once the upload is complete, however, a duplicate request will result in an error.

start_time
float

Optional Unix timestamp, when data collection began. This is only used for record-keeping; it is not validated or used during data parsing.

end_time
float

Optional Unix timestamp, when data collection ended. This is only used for record-keeping; it is not validated or used during data parsing.

tags
any

A map of key-value pairs describing the dataset as a whole. These values will be stored along with the raw data and used to annotate it for future use.

Tags should not be used to store configuration relevant to parsing or interpreting the dataset: that should be included in the file contents.

Tag keys are strings ([1..128] characters). Tag values may be numeric or strings ([1..1024] characters).

Responses

Response samples

Content type
application/json
{
  • "dataset_id": "dataset-37a2a3dc70c825d9ed1dc5bfcc3137b7c63c84f42c89b075975fb99bfb81c105",
  • "upload_urls": {
    },
  • "expiration_time": 1662688618.7129576,
  • "max_file_size": 2147483648
}

Dataset Status

Get the status of a dataset upload.

Once a dataset upload is complete, the status is only visible for 24h after the last file was uploaded. After this time, attempting to fetch the status of the dataset will result in a 404 response.

path Parameters
dataset_id
required
string
Example: 37a2a3dc70c825d9ed1dc5bfcc3137b7c63c84f42c89b075975fb99bfb81c105

ID of the dataset

Responses

Response samples

Content type
application/json
{
  • "created": 1662671373.139859,
  • "dataset_id": "dataset-37a2a3dc70c825d9ed1dc5bfcc3137b7c63c84f42c89b075975fb99bfb81c105",
  • "device_id": "wwxBBbbD",
  • "end_time": 1662664500.916,
  • "schema_id": "strivestudy-applewatch-md-1",
  • "session_id": "upload-session-1",
  • "start_time": 1662631000.151,
  • "status": "partial",
  • "status_reason": null,
  • "streams": {
    },
  • "tags": null
}

Upload Dataset In a Single Request

Upload all data for a dataset in a single request (AKA "single-shot dataset upload").

A dataset may consist of one or multiple files. The schema_id is used to determine how many files each dataset contains. See Key Concepts for details about dataset schemas.

For a dataset upload to be considered complete, all files expected by a dataset schema must be uploaded. An empty file may be used as a placeholder.

A successful request contains at least the schema ID, the device ID, and the file contents for each file (one for each "stream" associated with the schema). The file contents should be base64 encoded. This might look as follows:

{
    "device_id": "exampledeviceid",
    "schema_id": "exampleschemaid",
    "stream_data": {
        "streamfoo": "dGVzdCBmaWxlIGNvbnRlbnRzIGZvbw==",
        "streambar": "dGVzdCBmaWxlIGNvbnRlbnRzIGJhcg==",
    },
}

The response contains the generated dataset ID along with other metadata the dataset was created with.

Request Body schema: application/json
device_id
required
string

ID of the patient device that recorded this stream data.

schema_id
required
string

Dataset schema ID. See Key Concepts for details about valid schema IDs.

stream_data
required
object

File contents for each for each of the streams in the dataset schema. Keys are the stream name and values are the base64-encoded contents of the file.

start_time
float

Optional Unix timestamp, when data collection began. This is only used for record-keeping; it is not validated or used during data parsing.

end_time
float

Optional Unix timestamp, when data collection ended. This is only used for record-keeping; it is not validated or used during data parsing.

tags
object

A map of key-value pairs describing the dataset as a whole. These values will be stored along with the raw data and used to annotate it for future use.

Tags should not be used to store configuration relevant to parsing or interpreting the dataset: that should be included in the file contents.

Tag keys are strings ([1..128] characters). Tag values may be numeric or strings ([1..1024] characters).

Responses

Request samples

Content type
application/json
{
  • "device_id": "exampledeviceid",
  • "schema_id": "exampleschemaid",
  • "stream_data": {
    }
}

Response samples

Content type
application/json
{
  • "created": 1662671373.139859,
  • "dataset_id": "dataset-37a2a3dc70c825d9ed1dc5bfcc3137b7c63c84f42c89b075975fb99bfb81c105",
  • "device_id": "wwxBBbbD",
  • "end_time": 1662664500.916,
  • "schema_id": "strivestudy-applewatch-md-1",
  • "session_id": "3d2452cd634245039c1c40f499ddd16c",
  • "start_time": 1662631000.151,
  • "status": "uploaded",
  • "status_reason": null,
  • "streams": {
    },
  • "tags": null
}

Events and Spans

Create an event or span, which can later be queried via the Stream API.

These endpoints only accept Client Key authentication.

Events and spans cannot be deleted. However, they will be overwritten, if the following values are identical:

  • Patient ID (determined via authentication credentials)
  • Device ID
  • All timestamps (1 for events; 4 for spans)
  • Classification

Create an Event

An event is an item that occurs at a moment in time, which is associated with a payload.

Request Body schema: application/json
time
required
float

Unix timestamp when the event occurred.

classification
required
string

A string with 2 or 3 period-delimited elements, in the form <namespace>.<type> or <namespace>.<type>.<enum>.

The three elements form a hierarchical classification:

  • namespace -- the general source of the event. This must be one of:
    • clinical -- a clinical measure, e.g. a UPDRS result
    • device -- an event generated/detected by the device or sensor itself
    • patient -- an event reported by the patient
  • type -- the classification of the event, within the namespace.
  • enum (optional) -- a specific enumeration within the type.
created_time
float

Time that the event was created. If this is present, it is added to the payload, under the key "created_time".

ongoing
bool

Indicates if the event continues in time indefinitely. Typically, this is used for patient-reported items (e.g. if they log that they are currently experiencing a symptom). When this is true, "ongoing": true is set in the payload of the event.

For an item that lasts for a finite duration of time, create a span (which has a start and end time).

device_id
required
string

ID of the patient device that recorded this event.

device_version
required
string

A string that describes the version of the device that recorded the event (e.g. the Strive iOS app version).

This value is not currently used, though it may be in the future.

payload
required
object

A map to associate with the event. There is no validation.

Responses

Request samples

Content type
application/json
{
  • "time": 1593124523.389,
  • "classification": "patient.test_event",
  • "device_id": "wwxBBbbD",
  • "device_version": "0.0",
  • "payload": {
    }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "client_id": "12342342342342342342342",
  • "patient_id": "134132513513513251351"
}

Create a Span

A span is a special type of event, capturing something that occurred over a range of time. Like an event, each span is associated with a payload.

The time range of a span is described by 4 timestamps:

  • start_time_min -- The earliest time that the event could have started. This is an inclusive boundary.
  • start_time - The time when the event started (with high confidence). This is an inclusive boundary.
  • end_time - The time when the event ended (with high confidence). This is an exclusive boundary.
  • end_time_max -- The latest time that the event could have ended. This is an exclusive boundary.

In addition, the following constraints must hold:

  • start_time_min <= start_time < end_time <= end_time_max
    • Note that the start times may be the same, as may the end times.
  • The total duration of the span must be no more than 7 days

The 4 timestamps can be used to capture some uncertainty in the range of time. For example, if a patient indicated that they slept between 1-2 hours, starting at 2pm, a span could capture that with the following timestamps:

  • start_time -- 2pm
  • end_time -- 3pm
  • end_time_max -- 4pm
Request Body schema: application/json
start_time_min
float

Unix timestamp; the earliest time when the span could have started.

start_time
required
float

Unix timestamp, when the span started (with high confidence).

end_time
required
float

Unix timestamp, when the span ended (with high confidence).

end_time_max
float

Unix timestamp; the latest time when the span could have ended.

classification
required
string

A string with 2 or 3 period-delimited elements, in the form <namespace>.<type> or <namespace>.<type>.<enum>.

The three elements form a hierarchical classification:

  • namespace -- the general source of the span. This must be one of:
    • clinical -- a clinical measure, e.g. a UPDRS result
    • device -- a span generated/detected by the device or sensor itself
    • patient -- a span reported by the patient
  • type -- the classification of the span, within the namespace.
  • enum (optional) -- a specific enumeration within the type.
created_time
float

Time that the span was created. If this is present, it is added to the payload, under the key "created_time".

device_id
required
string

ID of the patient device that recorded this span.

device_version
required
string

A string that describes the version of the device that recorded the span (e.g. the Strive iOS app version).

This value is not currently used, though it may be in the future.

payload
required
object

A map to associate with the span. There is no validation.

Responses

Request samples

Content type
application/json
{
  • "start_time_min": 1593124500,
  • "start_time": 1593124599,
  • "end_time": 1593130000,
  • "end_time_max": 1593130099,
  • "classification": "patient.test_span",
  • "device_id": "wwxBBbbD",
  • "device_version": "0.0",
  • "payload": {
    }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "client_id": "12342342342342342342342",
  • "patient_id": "134132513513513251351"
}

Patient Upload Summary Statistics

Query patient upload statistics per schema_id which include:

  • Total bytes of raw data uploaded
  • Number datasets uploaded
  • Creation time of the latest dataset
  • Creation time of the earliest dataset

Patient Upload Summary Statistics

A successful request returns a JSON object, with a data key containing the upload summary statistics per schema_id uploaded.

The response can contain all upload summary statistics for a patient, or the upload summary statistics for a patient related to a single schema_id.

The patient_id is a path param in the url. The endpoint accepts a single query param: schema_id. See details below.

path Parameters
patient_id
required
string
Example: patient-123456789

The ID of the patient.

query Parameters
schema_id
string
Example: schema_id=medtronic-percept-1

Dataset schema ID. See Key Concepts for details about valid schema IDs.

Responses

Response samples

Content type
application/json
Example
{
  • "success": true,
  • "data": {
    }
}