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.
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.
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.
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.
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 datadyskinetic
-- Dyskinesia datametadata
-- Assorted metadataAuthentication is required for all API requests. There are several authentication methods:
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 IDX-Rune-Client-Access-Key
- client access key (secret)Note that each client may only fetch data for its associated patient.
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).
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 IDX-Rune-User-Access-Token-Secret
- access token secretX-Rune-Patient-Id
- patient ID for the data being accessedIt 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.
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
- JWTX-Rune-Patient-Id
- patient ID for the data being accessedStandard 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
}
}
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:
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.
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 |
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 ( |
{- "dataset_id": "dataset-37a2a3dc70c825d9ed1dc5bfcc3137b7c63c84f42c89b075975fb99bfb81c105",
- "upload_urls": {
}, - "expiration_time": 1662688618.7129576,
- "max_file_size": 2147483648
}
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.
dataset_id required | string Example: 37a2a3dc70c825d9ed1dc5bfcc3137b7c63c84f42c89b075975fb99bfb81c105 ID of the dataset |
{- "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": {
- "tremor": 34108,
- "dyskinetic": 35905,
- "metadata": null
}, - "tags": null
}
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.
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 ( |
{- "device_id": "exampledeviceid",
- "schema_id": "exampleschemaid",
- "stream_data": {
- "streamfoo": "dGVzdCBmaWxlIGNvbnRlbnRzIGZvbw==",
- "streambar": "dGVzdCBmaWxlIGNvbnRlbnRzIGJhcg=="
}
}
{- "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": {
- "tremor": 34108,
- "dyskinetic": 35905,
- "metadata": null
}, - "tags": null
}
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:
An event is an item that occurs at a moment in time, which is associated with a payload.
time required | float Unix timestamp when the event occurred. |
classification required | string A string with 2 or 3 period-delimited elements, in the form The three elements form a hierarchical classification:
|
created_time | float Time that the event was created. If this is present, it is
added to the payload, under the key |
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 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. |
{- "time": 1593124523.389,
- "classification": "patient.test_event",
- "device_id": "wwxBBbbD",
- "device_version": "0.0",
- "payload": {
- "hello": "world"
}
}
{- "success": true,
- "client_id": "12342342342342342342342",
- "patient_id": "134132513513513251351"
}
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
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
-- 2pmend_time
-- 3pmend_time_max
-- 4pmstart_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 The three elements form a hierarchical classification:
|
created_time | float Time that the span was created. If this is present, it is
added to the payload, under the key |
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. |
{- "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": {
- "hello": "world"
}
}
{- "success": true,
- "client_id": "12342342342342342342342",
- "patient_id": "134132513513513251351"
}
Query patient upload statistics per schema_id
which include:
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.
patient_id required | string Example: patient-123456789 The ID of the patient. |
schema_id | string Example: schema_id=medtronic-percept-1 Dataset schema ID. See Key Concepts for details about valid schema IDs. |
{- "success": true,
- "data": {
- "statistics": {
- "medtronic-percept-1": {
- "bytes_uploaded": 2913131,
- "first_upload_created_at": 1661799353.3680818,
- "last_upload_created_at": 1661799453.3680818,
- "number_of_uploads": 1
}, - "strivestudy-healthkit-2": {
- "bytes_uploaded": 67694947,
- "first_upload_created_at": 1661799200.3680818,
- "last_upload_created_at": 1661799453.3680818,
- "number_of_uploads": 12
}, - "strivestudy-applewatch-1": {
- "bytes_uploaded": 94847584,
- "first_upload_created_at": 1661799200.3680818,
- "last_upload_created_at": 1661799453.3680818,
- "number_of_uploads": 21
}
}
}
}