Introduction
The Winterlight Platform API allows partners to submit audio samples of speech and get back features which can be used to detect and monitor neurodegenerative or psychiatric disease symptoms.
Concepts Overview
The following is a list of high-level concepts that are important to internalize before progressing further down the documentation.
Sensitive Data
Winterlight categorizes data that is associated with an individual as sensitive data and any resource that contains sensitive data as a sensitive data resource. For example, the participant and sample resources are considered to be sensitive data because they could contain personally identifiable information. When you create a sensitive data resource you will need to specify the geographic region (via a zone) in which it will be stored. Winterlight allows data to be stored in Canada or the USA. You are responsible for selecting the geographic region most appropriate to your contractual or legal obligations.
All resources that are not specifically annotated as sensitive data are categorized as generic resources and presumed to not contain sensitive data. Generic resources can be stored and/or transferred cross-regionally/internationally. You cannot select the geographic region of generic resources. Examples of generic resources include teams and projects.
More information can be found in Winterlight’s Privacy Policy.
Transcription Modes
Our speech pipeline analyzes two aspects of speech: the acoustic component (how words are said) and the linguistic component (what words are said). The acoustic component is extracted directly from the audio, while the linguistic component requires a transcript. We can obtain transcripts from human transcriptionists (this is referred as “manual” transcription) or using automatic speech recognition (this is referred as “asr” transcription). The mode of transcription you have access to is determined by your project.
Insights
An insight is any piece of data generated for the use of or as the result of Winterlight speech analysis. Examples of insights include transcripts, speech features or models.
Resources Overview
All of the following resources are defined in additional detail further down in this documentation. This list explains all the high-level concepts so you have a sense of familiarity when you later encounter it again.
Teams
The team resource represents your organization and contains all other resources (see below). Every user will belong to a team and there must be at least one admin user who will be able to create new users.
Your team is created by a Winterlight employee during your account creation.
Projects
A project is associated with a team.
The project resource defines the configuration for data collection and processing. It describes what kind of audio samples can be submitted and at what cost.
Projects are created by a Winterlight employee during your account creation. If a new configuration is requested, additional projects can be created upon request. Generally every time you sign a new agreement or need a different set of services, it will result in a new project being created.
Zones
A zone is associated with a project.
The zone resource determines where sensitive data resources are geographically stored. For example, all participants in a Canadian zone would have their data physically stored on servers in Canada. Depending on the zone’s region, you will need to call the API with a specific url. Note that since the zone points to where sensitive data is located and does not contain sensitive data itself, it is considered to be a generic resource.
It is also important to note that while data will be stored in the zone selected, it may be processed in another geographic zone. For example, data stored in the US zone will be processed in Canada if it is selected for manual transcription.
You can create any number of zones in a single project.
Participants
A participant is associated with a zone.
The participant resource represents the individual whose speech is being analyzed.
You can create any number of participants in a zone.
Samples
A sample is associated with a participant.
The sample resource represents a single instance of speech for a participant.
Each sample will have a task (such as “Picture Description”), a stimulus specific to that task (such as “Cookie Theft”) and language. The specific combination of task, stimulus and languages you can submit tasks for is determined by the project.
You will be provided resources on how to administer the Winterlight assessment on your application in a separate document.
You can submit any number of samples for any given participant, but you will be invoiced for them as outlined per your agreement if the participant belongs to a live zone.
A sample can have multiple reports sub-resource which contain insights from the analysis.
Example Workflow
The following is a high-level overview of what it takes to successfully submit a single audio sample to Winterlight API for analysis:
- You are assigned an administer API token that is associated with your team. Using that API token you can create more API tokens or if necessary, delete existing API tokens (e.g. if you want to rotate them every 90 days).
- Based on your agreement, a project will be created. This will determine what speech tasks are supported, what languages are supported, what feature version is used, what kind of transcription is used and so forth.
- You create zones for your project. You will likely create a sandbox zone while you initially integrate with this API. Once you have successfully submitted an audio sample, you can then confidently create training and live zones. The number of zones you will need to create will be based on your own use-case.
- You create participants for the zone. You can create them as they are registered to your application/study/clinical trial or just-in-time right before you submit the audio sample.
- The participant completes the Winterlight assessment in your application which will generate an audio file.
- You create a sample resource with the specifications of the assessment that was completed.
- Upload the audio file for the sample. Uploading the audio submits the sample for analysis. You will no longer be able to modify the sample after this point.
- You will receive the analysis to the callback defined in the zone. If the analysis could not be completed, you will receive a callback with the reason why.
There are a number of steps, but it is a fairly linear and uncomplicated process.
Making Requests
Authentication
When your team is created you will be provided with an API token. You must make requests to the endpoints described in this documentation by providing the API token in the request header. The header will look something like:
Authorization: Bearer wl.{your-api-token-id}.{you-api-token-secret}
Request Headers
If the accept
and content-type
headers are not provided, the API will use the default of application/json
. The content-type
only accepts either application/json
or multi-part/form-data
.
Response Wrapper
Successful Requests
Successful requests return JSON structured like this:
{
"ok": true,
"status": 200,
"data": {
"//": "..."
}
}
The standard response from the API is JSON with these fields:
field | type | description |
---|---|---|
ok | bool | True if the request was successful (i.e. 2XX). |
status | integer | The status code of the request. |
data | object | The requested resource. Will be an array of objects if multiple resources are requested. May be null or undefined. |
Failed Requests
Failed requests return JSON structured like this:
{
"ok": false,
"status": 404,
"error": "NOT_FOUND"
}
field | type | description |
---|---|---|
ok | bool | False if the request failed (i.e. 4XX or 5XX). |
status | integer | The status code of the request. |
error | string | A machine-readable cause for the error. |
reason | object | A verbose explanation in case of failed validation. |
Rate Limiting
Clients that make a large number of requests in a short period of time may be rate-limited, which will result in a response with status code 429: Too Many Requests
. Simply waiting before issuing new requests will expire the rate-limit.
The body of a rate-limited response will be HTML, not JSON. This can be an issue if your client always expect response to be JSON. It is recommended to check if the the status code is 429
before parsing the response.
We will change 429s to return a JSON body in future releases.
Rate-limited responses look like this:
<html>
<head>
<title>429 Too Many Requests</title>
</head>
<body>
<center><h1>429 Too Many Requests</h1></center>
<hr />
<center>nginx</center>
</body>
</html>
Resource Ids
All resource ids will have a 21-character guid with an alphabet of 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-
(see nanoid for more information). If you are storing this id in a SQL database, it is recommended to use the ascii
character set for column rather than utf8
to reduce the space used to 63 to 21 bytes.
Dates
All dates are in the UTC timezone. When you pass date values in the API they must be in one of the following formats:
Format | Description |
---|---|
2021-04-04T12:12:34.000Z | A ISO 8601 string. Default format for javascript. |
2021-04-04 | Date without time. The hours, minutes and seconds will be zero’ed out in the database. |
1617538354000 | Numeric value of the date as the number of milliseconds. Default format for javascript. |
Me Parameter Keyword
There are cases when the id
for a resource can be inferred based on your user and you can use the me
keyword. his saves the step of having to lookup value from your database when making the request.
For example, instead of having to specify the full id of your team (GET api-us.winterlightlabs.com/api/v1/teams/vyy5bHHXSbZ2PaNHz4c7f
) you can instead use the me
keyword (GET api-us.winterlightlabs.com/api/v1/teams/me
) to get your current team.
Meta Field
When creating a zone, participant or zone you can set a meta
field which allows you to store additional information about the resource. You can later access this value when requesting the resource and it will be returned to you in webhook callbacks. When the meta
value is returned in a webhook, you will receive the meta
values you set for the zone, participant and sample (if relevant).
There are two primary use cases for providing meta:
- You want to pass in your additional ids to allow for easier processing when you receive webhook callback.
- You are collaborating directly with Winterlight and want to provide additional information about the data that would be normally transferred via a spreadsheet.
Endpoint Special Properties
Each endpoint will have the following table specifying any of its special properties:
Property | Applicable? |
---|---|
Requires team admin permissions? | Yes/No |
Requires region-specific url due to sensitive data? | Yes/No |
Can result in invoice charges? | Yes/No |
Is activity recorded in audit logs? | Yes/No |
- Requires team admin permissions? If Yes, only team admins can call this endpoint. Usually endpoints that affect users, projects or zones require team admin permissions.
- Requires region-specific url due to sensitive data? If Yes, the endpoint requires to be called using the zone’s regional url. This is a good indication that the endpoint is interacting with sensitive data.
- Can result in invoice charges? If yes, calling this endpoint can result in you being charged based on the project configuration. Very few endpoints will result in charges and in general, only those that can trigger an analysis result being sent to you will do so.
- Is activity recorded in audit logs? If yes, calling this endpoint results in a audit log record. You can learn more in the Audit Logs section.
Country and Language Fields
A locale is made up of a language (e.g. en
) and a country (e.g. CA
). While you can write a locale as a single string en-CA
, within the platform they are represented as two separate fields: locale_country_code
and locale_language_code
. This is because we may have situations where the language is known for a participant, but the country (or dialect) is unknown. If you see a field with the prefix locale_
it usually refers to someone’s spoken language. If you see country_code
without the locale_
prefix, then that field is referring to the country only.
You can find the complete list of valid country codes and language codes in the reference section.
Difference between language_code and language_id
If the field suffix ends with _code
or _id
indicates its functionality. If it ends with _code
it will accept all possible values under its specification (e.g. language_code
will accept every possible language code). If it ends with _id
that indicates that it only accepts a subset of values (e.g. language_id
is the list of languages that Winterlight supports).
Teams
The team resource represents your organization. All resources you can access are direct or indirect children of your team.
Your team is created by a Winterlight employee during your account creation.
Fields
An example team resource:
{
"id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "Winterlight Labs",
"currency": "CAD",
"created_at": "2018-01-01T12:12:12.000Z"
}
Name | Type | Description |
---|---|---|
id | string | 21-character guid. |
name | string | The name of your team. Max length 64 characters. |
currency | string | The currency you are invoiced in. |
created_at | date | The date your team was created. |
Children Resources
Get a single Team
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
const teamId = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/teams/${teamId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves a specific team. In almost all cases you can only access your own team.
You can use the me
keyword to get your current team.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "Winterlight Labs",
"currency": "CAD",
"created_at": "2018-01-01T12:12:12.000Z"
}
}
GET {host}.winterlightlabs.com/api/v1/teams/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the team or me . |
Update a Team
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
const teamId = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/teams/${teamId}`,
method: 'PATCH',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
name: 'Summerdark Labs',
}),
});
This endpoint allows you to modify some properties of your team. Some properties, like the currency
, cannot be modified directly and requires contacting Winterlight support to make that change for you.
You can use the me
keyword to get your current team.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | Yes |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "Summerdark Labs",
"currency": "CAD",
"created_at": "2018-01-01T12:12:12.000Z"
}
}
PATCH {host}.winterlightlabs.com/api/v1/teams/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the team or me . |
name | string | The display name for the team. Max length 64 characters. |
API Tokens
An API Token is a user resource sub-type that allows you to programmatically call the API. An API token is associated with a team.
Security
The API token has an id
which is public information and secret
which needs to be stored securely. We use the id
to identify your API token and the secret
to confirm its identity by comparing it against a hashed value in the database. You can use the API token to make a request by setting the Authorization
header to be Bearer wl.{id}.{secret}
. For example, the following would be a valid header with for example API token: Bearer wl.DwP3qnDcHsaB4V6Ti-wb-.5wARAv5mh875E3NkVBxwDg4riqa7mTA7Fjb3QVa
.
Unlike tokens given directly to a person-type user which have a predetermined and limited session duration, API tokens are long-lived and are valid until they are explicitly deleted. As a result, it is highly recommended that you routinely rotate the token. The expires_at
field specifies when you should rotate the token (typically 90 days after creation). We will never automatically invalidate your token. You can rotate a token by creating a new token and then deleting the old one.
Fields
An example api token resource:
{
"id": "DwP3qnDcHsaB4V6Ti-wb-",
"prefix": "wl",
"secret": "5wARAv5mh875E3NkVBxwDg4riqa7mTA7Fjb3QVa",
"token": "wl.DwP3qnDcHsaB4V6Ti-wb-.5wARAv5mh875E3NkVBxwDg4riqa7mTA7Fjb3QVa",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "Develop",
"description": "Whatever additional notes you want here.",
"is_team_admin": false,
"created_at": "2020-01-01T12:12:12.000Z",
"last_used_at": null,
"expires_at": "2020-04-01T12:12:12.000Z"
}
Name | Type | Description |
---|---|---|
id | string | 21-character guid public key for the token |
prefix | string | identifies the type of api token being provided. |
secret | string | 42-character secret that authorizes the request. |
token | string | The combination of prefix, id and secret to be passed for requests. |
team_id | string | 21-character guid for your team. |
name | string | A human-readable name to identify the token. |
note | string | A human-readable description. |
is_team_admin | bool | Can call admin-level endpoints. |
created_at | date | The date your api token was created. |
last_used_at | date | The date your api token was last used. Null if never used. |
expires_at | date | The recommended date to delete this token. |
Create an API Token
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/api-tokens`,
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
name: 'Sandbox Token',
note: 'Please use for the Sandbox Zone only!',
is_team_admin: false,
}),
});
This endpoint creates a new API token. It will be automatically associated with your team. It is important to store the token
or secret
upon receiving the response. This is the only time the secret
and token
will be visible as plain-text!
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | Yes |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 201,
"ok": true,
"data": {
"id": "DwP3qnDcHsaB4V6Ti-wb-",
"prefix": "wl",
"secret": "5wARAv5mh875E3NkVBxwDg4riqa7mTA7Fjb3QVa",
"token": "wl.DwP3qnDcHsaB4V6Ti-wb-.5wARAv5mh875E3NkVBxwDg4riqa7mTA7Fjb3QVa",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "Sandbox Token",
"note": "Please use for the Sandbox Zone only!",
"is_team_admin": false,
"secret": "5wARAv5mh875E3NkVBxwDg4riqa7mTA7Fjb3QVa-tN",
"created_at": "2020-01-01T12:12:12.000Z",
"last_used_at": null,
"expires_at": "2020-04-01T12:12:12.000Z"
}
}
POST {host}.winterlightlabs.com/api/v1/api-tokens
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
name | string | Required. A human-readable name to identify the token. |
note | string | A human-readable description. |
is_team_admin | bool | Does the token have team admin permissions? Default false . |
Get a single API Token
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
const apiTokenId = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/api-tokens/${apiTokenId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves a specific API token.
You can use the me
keyword to get information about your current token. Only team admins can see all API tokens for the team.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | Maybe |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "DwP3qnDcHsaB4V6Ti-wb-",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "Sandbox Token",
"note": "Please use for the Sandbox Zone only!",
"is_team_admin": false,
"created_at": "2020-01-01T12:12:12.000Z",
"last_used_at": "2020-02-01T12:12:12.000Z",
"expires_at": "2020-04-01T12:12:12.000Z"
}
}
GET {host}.winterlightlabs.com/api/v1/api-tokens/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the API token or me . |
Get all API Tokens
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/api-tokens`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves all API tokens for your team.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | Yes |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": [
{
"id": "DwP3qnDcHsaB4V6Ti-wb-",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "Sandbox Token",
"note": "Please use for the Sandbox Zone only!",
"is_team_admin": false,
"created_at": "2020-01-01T12:12:12.000Z",
"last_used_at": "2020-02-01T12:12:12.000Z",
"expires_at": "2020-04-01T12:12:12.000Z"
},
{
"id": "eqSCtJOfNUihRUh7Zac0W",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "Production Token",
"note": null,
"is_team_admin": false,
"created_at": "2021-01-01T12:12:12.000Z",
"last_used_at": "2021-02-01T12:12:12.000Z",
"expires_at": "2021-04-01T12:12:12.000Z"
}
]
}
GET {host}.winterlightlabs.com/api/v1/api-tokens
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
Delete an API Token
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
const apiTokenId = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/api-tokens/${apiTokenId}`,
method: 'DELETE',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint deletes a specific API token. A token cannot delete itself and will instead return a 403 Forbidden
error.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | Yes |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true
}
DELETE {host}.winterlightlabs.com/api/v1/api-tokens/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the API token. |
Projects
The project resource defines the configuration for data collection and processing. It describes what kind of audio samples can be submitted, at what cost and what kind of analysis results you will receive as determined by your agreement. Projects could represent a clinical trial, a research study or an entire app.
Projects are cross-regional and do not directly have sensitive data associated with them. Instead you create zones which are region-specific to store sensitive data. Practically speaking, if a project would be a global clinical trial, then the zones would be the jurisdictions where the clinical trials are held.
Projects are created by a Winterlight employee during your account creation. Please contact your account manager to make changes to your projects or create new ones.
Fields
An example project resource:
{
"id": "DwP3qnDcHsaB4V6Ti-wb-",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "XYZ Clinical Trial",
"note": "The winterlight assessment will be administered on weeks 1, 4 and 12.",
"project_tasks": [
{
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_family_in_the_kitchen",
"transcription_modes": ["manual"],
"max_audio_duration": 300.0
},
{
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_living_room",
"transcription_modes": ["manual"],
"max_audio_duration": 300.0
}
],
"required_participant_fields": [
"external_id",
"birth_year",
"birth_month",
"birth_day"
],
"required_sample_fields": ["external_id", "sample_source"],
"region_ids": ["ca", "us"],
"is_sandbox_only": false,
"supported_insights": ["v1/features"],
"default_insights": ["v1/features"],
"can_specify_insights": false,
"created_at": "2020-01-01T12:12:12.000Z"
}
Name | Type | Description |
---|---|---|
id | string | 21-character guid. |
team_id | string | 21-character guid for your team. |
name | string | A human-readable name for the project. Max length 64 characters. |
note | string | A human-readable description. |
project_tasks | array | See “Project Tasks” section. |
required_participant_fields | array | See the “participant” resource. |
required_sample_fields | array | See the “sample” resource. |
region_ids | array | The supported zone regions for this project. |
is_sandbox_only | bool | If true, only “sandbox” zones can be created in this project. |
supported_insights | array | See the “Insights” section. |
default_insights | array | See the “Insights” section. |
can_specify_insights | bool | See the “Insights” section. |
created_at | date | The date your project was created. |
Project Tasks
The project task sub-resource defines what types of audio samples you can submit. Any sample submitted that is not the exact combination of language_id
, task_id
, stimulus_id
listed will result in a 400 UNSUPPORTED_TASK
error. Requesting a transcription mode that isn’t
supported by the language/task/stimulus combination in question will result in a 400 UNSUPPORTED_TRANSCRIPTION_MODE
error.
Name | Type | Description |
---|---|---|
language_id | string | 2-character ISO 639-1 language code (e.g. “en”). |
task_id | string | A machine-readable name for a supported speech task. |
stimulus_id | string | A machine-readable name for a speech task stimulus (if applicable). |
max_audio_duration | float | The largest audio sample that can be submitted (measured in seconds). |
transcription_modes | string | Available transcription methods. Valid options are “manual” and “asr”. |
Children Resources
Get a single Project
const axios = require('axios');
const subdomain = '...';
const project = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/projects/${projectId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves a specific project.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "DwP3qnDcHsaB4V6Ti-wb-",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "XYZ Clinical Trial",
"note": "The winterlight assessment will be administered on weeks 1, 4 and 12.",
"created_at": "2020-01-01T12:12:12.000Z",
"project_tasks": [
{
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_family_in_the_kitchen",
"transcription_modes": ["manual"],
"max_audio_duration": 300.0
},
{
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_living_room",
"transcription_modes": ["manual"],
"max_audio_duration": 300.0
}
],
"required_participant_fields": [
"external_id",
"birth_year",
"birth_month",
"birth_day"
],
"required_sample_fields": ["external_id", "sample_source"],
"region_ids": ["ca", "us"],
"is_sandbox_only": false,
"supported_insights": ["v1/features"],
"default_insights": ["v1/features"],
"can_specify_insights": false,
"created_at": "2020-01-01T12:12:12.000Z"
}
}
GET {host}.winterlightlabs.com/api/v1/projects/{id}
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
id | string | The id of the project. |
Get all Projects
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/projects`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves all projects for your team.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": [
{
"id": "DwP3qnDcHsaB4V6Ti-wb-",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "XYZ Clinical Trial",
"note": "The winterlight assessment will be administered on weeks 1, 4 and 12.",
"created_at": "2020-01-01T12:12:12.000Z",
"project_tasks": [
{
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_family_in_the_kitchen",
"transcription_modes": ["manual"],
"max_audio_duration": 300.0
},
{
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_living_room",
"transcription_modes": ["manual"],
"max_audio_duration": 300.0
}
],
"required_participant_fields": [
"external_id",
"birth_year",
"birth_month",
"birth_day"
],
"region_ids": ["ca", "us"],
"required_sample_fields": ["external_id", "sample_source"],
"is_sandbox_only": false,
"supported_insights": ["v1/features"],
"default_insights": ["v1/features"],
"can_specify_insights": false,
"created_at": "2020-01-01T12:12:12.000Z"
}
]
}
GET {host}.winterlightlabs.com/api/v1/projects
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
Update a Project
const axios = require('axios');
const subdomain = '...';
const projectId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/projects/${projectId}`,
method: 'PATCH',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
name: 'A different name',
}),
});
This endpoint allows you to modify some properties of your project.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | Yes |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "DwP3qnDcHsaB4V6Ti-wb-",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"name": "A different name",
"note": "The winterlight assessment will be administered on weeks 1, 4 and 12.",
"project_tasks": [
{
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_family_in_the_kitchen",
"transcription_modes": ["manual"],
"max_audio_duration": 300.0
},
{
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_living_room",
"transcription_modes": ["manual"],
"max_audio_duration": 300.0
}
],
"required_participant_fields": [
"external_id",
"birth_year",
"birth_month",
"birth_day"
],
"required_sample_fields": ["external_id", "sample_source"],
"region_ids": ["ca", "us"],
"is_sandbox_only": false,
"supported_insights": ["v1/features"],
"default_insights": ["v1/features"],
"can_specify_insights": false,
"created_at": "2020-01-01T12:12:12.000Z"
}
}
PATCH {host}.winterlightlabs.com/api/v1/projects/{id}
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
id | string | The id of the project. |
name | string | Required. A display name for the project. Max length 64 characters. |
note | string | A human-readable description. |
Zones
The zone resource stores and partitions participant data for any given project. You can create any number of zones in a single project. A zone, unlike a project, is associated with a specific geographic region. A Canadian zone would mean that the data (including sensitive data) in that zone would be physically stored on servers in Canada. You can have multiple zones in the same region.
There are two types of zones:
- Sandbox Zones: This zone holds test data. This zone type is meant to allow developers to safely test their integration with the API or clinicians, raters, and caregivers to practice administering our assessment with your application. Calling the Sandbox API is free but it will not trigger the analysis of audio. Instead, you will receive a fixed response.
- Live Zones: This zone holds production data. Any audio sent will be analyzed by us and you will be invoiced per your agreement.
Organization
While your application will have its own system to organize data, you will want to define separate zones for various operational reasons. The following are examples where you may want to or need to create additional zones.
- The data needs to be stored in a certain country.
- The ownership of the data differs. If you’re working on the behalf of someone else, you may want their data to be treated as one set for audit tracking.
- The access to the data needs to be restricted. For example, you may not want an integration testing sandbox API key to be able to access production data.
- The data is from a cohort of individuals with a specific disease. For example, this would make it easier to collaborate directly with Winterlight on analysis for a particular cohort.
- The data is handled differently on your servers. Since the webhook url is defined on the zone, you can send the results of the analysis to different servers. This is useful if you are setting up an experimental pipeline or have more complex data storage requirements.
You do not need to always divide your data into distinct zones. If you’re running a clinical trial, outside of geographic reasons you do not need to define a separate zone for each clinical site since you would want the data to be analyzed together. In this example, you could instead have a single project for the multinational clinical trial and a zone for each geographic region.
Regional Urls
Requesting data from the incorrect region will return the following error:
{
"ok": false,
"status": 400,
"error": "INCORRECT_REGION",
"location": "https://api-ca.winterlightlabs.com/api/v1/samples/tIZKtyZ_9_xb-z3sXsUzy"
}
Depending on the zone’s region, you will need to call the API with a specific url (the region_host
property of the zone). The transfer of sensitive data across jurisdictions can be regulated, so it is imperative to ensure you submit data to the correct region.
Region | Url |
---|---|
Canada | https://api-ca.winterlightlabs.com |
USA | https://api-us.winterlightlabs.com |
You can call any of the regional API urls for non-sensitive data data, but you must use the zone’s regional url when calling endpoints that may contain sensitive data. If you attempt to request sensitive data from the incorrect region, you will 400 INCORRECT_REGION
status code and response body will have a location
field with the correct regional url. Since this is not a 301
or 309
redirection, your request will not be automatically redirected.
Webhooks
When creating a zone you can pass a webhook_url
and webhook_secret
to receive callbacks to various events. The API will send POST callbacks to the webhook_url
with a x-winterlight-secret={webhook_secret}
header for authentication. You must ensure that the webhook_url
destination complies with the legal storage requirements of the data and your own contractual obligations.
When creating a zone you will also need to pass a webhook_secret
(at least 32 characters) which will be used to authenticate via a x-winterlight-secret
header in webhook_url
http requests. You cannot view the webhook_secret
once it is set (aside from the last 4 digits), but it can be overwritten. Currently, webhook callback is attempted only once.
The possible webhook events are defined in the Webhooks section.
Fields
An example zone resource:
{
"id": "JMW5IcFQ6rAJDbRAeuQXR",
"zone_type": "live",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "DwP3qnDcHsaB4V6Ti-wb-",
"region_id": "ca",
"region_host": "https://api-ca.winterlightlabs.com",
"country_codes": ["CA", "FR"],
"name": "Canadian and European Clinical Sites",
"note": "Includes EU data.",
"webhook_url": "https://example.com/v1/some-callback-url",
"webhook_secret": "04751888d21e47d1851a9b77a6a34d35",
"meta": {
"whatever_you_put_in_meta": "will_be_echoed_back"
},
"created_at": "2020-01-01T12:12:12.000Z"
}
Name | Type | Description |
---|---|---|
id | string | 21-character guid. |
zone_type | string | Either “sandbox” or “live”. |
team_id | string | 21-character guid for zone’s team. |
project_id | string | 21-character guid for zone’s project. |
region_id | string | 2-character id. Either “us” or “ca”. Determines where data is stored. |
region_host | string | Url to make requests against zone resources. |
country_codes | array | List of 2-character id based on ISO 3166-1 alpha-2. Used for compliance tracking. |
name | string | A human-readable name for the zone. Max length 64 characters. |
note | string | A human-readable description. |
webhook_url | string | The https url that will receive events for samples in the zone. |
webhook_secret | string | At least 32 characters. Authenticate callbacks via the x-winterlight-secret header. |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
created_at | date | The date your zone was created. |
Children Resources
Create a Zone
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/zones`,
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
zone_type: 'sandbox',
project_id: 'DwP3qnDcHsaB4V6Ti-wb-',
region_id: 'ca',
country_codes: ['CA', 'FR'],
name: 'Rater Training',
note: 'Meant to allow raters to practice administering tasks',
webhook_url: 'https://example.com/v1/some-callback-url',
webhook_secret: '04751888d21e47d1851a9b77a6a34d35',
meta: {
whatever_you_put_in_meta: 'will_be_echoed_back',
},
}),
});
This endpoint creates a new zone. Note that zone_type
and region_id
cannot be changed once set. The zone that the region is determined by the project’s region_ids
field; trying to create a zone in a unsupported region will result in a 400 INVALID_REGION_ID
error. Trying to create a non-sandbox zone in a project where is_sandbox_only=true
will result in a 400 SANDBOX_ONLY_PROJECT
error.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | Yes |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 201,
"ok": true,
"data": {
"id": "JMW5IcFQ6rAJDbRAeuQXR",
"zone_type": "sandbox",
"project_id": "DwP3qnDcHsaB4V6Ti-wb-",
"region_id": "ca",
"region_host": "https://api-ca.winterlightlabs.com",
"country_codes": ["CA", "FR"],
"name": "Rater Training",
"note": "Meant to allow raters to practice administering tasks",
"webhook_url": "https://example.com/v1/some-callback-url",
"webhook_secret": "****************************4d35",
"meta": {
"whatever_you_put_in_meta": "will_be_echoed_back"
},
"created_at": "2020-01-01T12:12:12.000Z"
}
}
POST {host}.winterlightlabs.com/api/v1/zones
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
zone_type | string | Required. Either “sandbox” or “live”. |
project_id | string | Required. 21-character guid for zone’s project. |
region_id | string | Required. 2-character id. Either “us” or “ca”. Determines where data is stored. |
country_codes | array | Required. List of 2-character id based on ISO 3166-1 alpha-2. Used for compliance tracking. |
name | string | Required. A human-readable name for the zone. Max length 64 characters. |
note | string | A human-readable description. |
webhook_url | string | (W) The https url that will receive events for samples in the zone. |
webhook_secret | string | (W) At least 32 characters. Authenticate callbacks via the x-winterlight-secret header. |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
All fields marked with a (W) are optional, but if one of the values is defined, all must be defined.
Get a single Zone
const axios = require('axios');
const subdomain = '...';
const zoneId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/zones/${zoneId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves a specific zone. The webhook_secret
value is hidden aside for the last four digits.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "JMW5IcFQ6rAJDbRAeuQXR",
"zone_type": "sandbox",
"project_id": "DwP3qnDcHsaB4V6Ti-wb-",
"region_id": "ca",
"region_host": "https://api-ca.winterlightlabs.com",
"country_codes": ["CA", "FR"],
"name": "Rater Training",
"note": "Meant to allow raters to practice administering tasks",
"webhook_url": "https://example.com/v1/some-callback-url",
"webhook_secret": "****************************4d35",
"meta": {
"whatever_you_put_in_meta": "will_be_echoed_back"
},
"created_at": "2020-01-01T12:12:12.000Z"
}
}
GET {host}.winterlightlabs.com/api/v1/zones/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the zone. |
Get all Zones
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/zones`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves all zones for your team. The webhook_secret
value is hidden aside for the last four digits.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": [
{
"id": "JMW5IcFQ6rAJDbRAeuQXR",
"zone_type": "sandbox",
"project_id": "DwP3qnDcHsaB4V6Ti-wb-",
"region_id": "ca",
"region_host": "https://api-ca.winterlightlabs.com",
"country_codes": ["CA", "FR"],
"name": "Rater Training",
"note": "Meant to allow raters to practice administering tasks",
"webhook_url": "https://example.com/v1/some-callback-url",
"webhook_secret": "****************************4d35",
"meta": {
"whatever_you_put_in_meta": "will_be_echoed_back"
},
"created_at": "2020-01-01T12:12:12.000Z"
}
]
}
GET {host}.winterlightlabs.com/api/v1/zones
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
Update a Zone
const axios = require('axios');
const subdomain = '...';
const zoneId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/zones/${zoneId}`,
method: 'PATCH',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
country_codes: ['CA', 'FR', 'DE'],
webhook_secret: '147981e1c1ad4d5c97d94802fdf2c23d',
meta: {
whatever_you_put_in_meta: 'will_be_echoed_back',
and_can_be: 'extended',
},
}),
});
This endpoint allows you to modify some properties of your zone.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | Yes |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "JMW5IcFQ6rAJDbRAeuQXR",
"zone_type": "sandbox",
"project_id": "DwP3qnDcHsaB4V6Ti-wb-",
"region_id": "ca",
"region_host": "https://api-ca.winterlightlabs.com",
"country_codes": ["CA", "FR", "DE"],
"name": "Rater Training",
"note": "Meant to allow raters to practice administering tasks",
"webhook_url": "https://example.com/v1/some-callback-url",
"webhook_secret": "****************************c23d",
"meta": {
"whatever_you_put_in_meta": "will_be_echoed_back",
"and_can_be": "extended"
},
"created_at": "2020-01-01T12:12:12.000Z"
}
}
PATCH {host}.winterlightlabs.com/api/v1/zones/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the zone. |
country_codes | array | List of 2-character id based on ISO 3166-1 alpha-2. Used for compliance tracking. |
name | string | A human-readable name for the zone. Max length 64 characters. |
note | string | A human-readable description. |
webhook_url | string | The https url that will receive events for samples in the zone. |
webhook_secret | string | At least 32 characters. Authenticate callbacks via the x-winterlight-secret header. |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
Participants
The participant represents a single person and their demographic information.
By default, some of the fields for the participant are marked as optional, but they can be flagged as required in the project’s required_participant_fields
property dependent on the nature of your project.
Fields
An example participant resource:
{
"id": "ggG305vkzYyAT3dL3yaOS",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"external_id": "external.123",
"external_label": "healthy_week_234",
"birth_year": 1989,
"birth_month": 11,
"birth_day": 6,
"sex": "male",
"education_in_years": 19,
"native_locale_country_code": "CA",
"native_locale_language_code": "en",
"meta": {
"whatever_you_want": "for_example_diagnosis_labels"
},
"created_at": "2021-07-13T07:29:49.000Z"
}
Name | Type | Description |
---|---|---|
id | string | 21-character guid. |
team_id | string | 21-character guid for participant’s team. |
project_id | string | 21-character guid for participant’s project. |
zone_id | string | 21-character guid for participant’s zone. |
external_id | string | Your system’s id for the participant. |
external_label | string | A label for the participant (e.g. healthy control). |
birth_year | integer | A valid birth year. |
birth_month | integer | A valid birth month (starting with 1 for January). |
birth_day | integer | A valid birth day (starting with 1). |
sex | string | One of “male”, “female” or “other”. |
education_in_years | integer | See the table below. |
native_locale_country_code | string | 2-character code for their native locale country (e.g. CA for Canada). |
native_locale_language_code | string | 2-character code for their native locale language (e.g. en for English). |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
created_at | date | The date your participant was created. |
The native_locale_country_code
and native_locale_language_code
fields are used to record the participant’s first spoken language. This may be different from the language they use to complete the assessments. It is possible to provide only native_locale_language_code
, but you cannot have native_locale_country_code
by itself.
Education
The education_in_years
property is calculated by looking at the furthest they have progressed when it comes to education. These values are normalized to the Canadian school system. Partial completion is still considered, so if a participant only completed two years of university, their total would be 14 years.
Years | Description |
---|---|
8 | Completed elementary school. |
12 | Completed high school. |
14 | Completed trade school/college/apprenticeship. |
16 | Completed undergraduate degree. |
18 | Completed masters degree. |
21 | Completed PhD. |
Children Resources
Create a Participant
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/participants`,
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
zone_id: 'YEV8qyUpIdcHWonkhau5E',
external_id: 'external.123',
external_label: 'healthy_week_234',
birth_year: 1989,
birth_month: 11,
birth_day: 6,
sex: 'male',
education_in_years: 19,
native_locale_country_code: 'CA',
native_locale_language_code: 'en',
meta: {
whatever_you_want: 'for_example_diagnosis_labels',
},
}),
});
This endpoint creates a new participant. A participant cannot be moved to a different zone once it is created.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 201,
"ok": true,
"data": {
"id": "ggG305vkzYyAT3dL3yaOS",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"external_id": "external.123",
"external_label": "healthy_week_234",
"birth_year": 1989,
"birth_month": 11,
"birth_day": 6,
"sex": "male",
"education_in_years": 19,
"native_locale_country_code": "CA",
"native_locale_language_code": "en",
"meta": {
"whatever_you_want": "for_example_diagnosis_labels"
},
"created_at": "2021-07-13T07:29:49.000Z"
}
}
POST {host}.winterlightlabs.com/api/v1/participants
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
zone_id | string | Required. 21-character guid for participant’s zone. |
external_id | string | (•) Your system’s id for the participant. |
external_label | string | (•) A label for the participant (e.g. healthy control). |
birth_year | integer | (•) A valid birth year. |
birth_month | integer | (•) A valid birth month (starting with 1 for January). |
birth_day | integer | (•) A valid birth day (starting with 1). |
sex | string | (•) One of “male”, “female” or “other”. |
education_in_years | integer | (•) See the table in the main participant section. |
native_locale_country_code | string | (•) 2-character code for their native locale country (e.g. CA for Canada). |
native_locale_language_code | string | (•) 2-character code for their native locale language (e.g. en for English). |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
All fields marked with a (•) can be marked as required dependent on the project required_participant_fields
value.
Update a Participant
const axios = require('axios');
const subdomain = '...';
const participantId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/participants/${participantId}`,
method: 'PATCH',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
external_id: 'a_new_external_id',
external_label: 'a_new_external_label',
meta: {
whatever_you_want: 'for_example_different_diagnosis_labels',
},
}),
});
This endpoint updates a participant. Only fields that do not affect analysis may be modified after the participant is created.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "ggG305vkzYyAT3dL3yaOS",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"external_id": "a_new_external_id",
"external_label": "a_new_external_label",
"birth_year": 1989,
"birth_month": 11,
"birth_day": 6,
"sex": "male",
"education_in_years": 19,
"native_locale_country_code": "CA",
"native_locale_language_code": "en",
"meta": {
"whatever_you_want": "for_example_diagnosis_labels"
},
"created_at": "2021-07-13T07:29:49.000Z"
}
}
PATCH {host}.winterlightlabs.com/api/v1/participants/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the participant. |
external_id | string | Your system’s id for the participant. |
external_label | string | A label for the participant (e.g. healthy control). |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
Omitting a field will leave it unmodified. Passing null
will nullify it.
Get a single Participant
const axios = require('axios');
const subdomain = '...';
const participantId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/participants/${participantId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves a specific participant.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "ggG305vkzYyAT3dL3yaOS",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"external_id": "external.123",
"external_label": "healthy_week_234",
"birth_year": 1989,
"birth_month": 11,
"birth_day": 6,
"sex": "male",
"education_in_years": 19,
"native_locale_country_code": "CA",
"native_locale_language_code": "en",
"meta": {
"whatever_you_want": "for_example_diagnosis_labels"
},
"created_at": "2021-07-13T07:29:49.000Z"
}
}
GET {host}.winterlightlabs.com/api/v1/participants/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the participant. |
Get all Participants
const axios = require('axios');
const subdomain = '...';
const zoneId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/participants?zone_id=${zoneId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves all participants for the specified zone.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": [
{
"id": "ggG305vkzYyAT3dL3yaOS",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"external_id": "external.123",
"external_label": "healthy_week_234",
"birth_year": 1989,
"birth_month": 11,
"birth_day": 6,
"sex": "male",
"education_in_years": 19,
"native_locale_country_code": "CA",
"native_locale_language_code": "en",
"meta": {
"whatever_you_want": "for_example_diagnosis_labels"
},
"created_at": "2021-07-13T07:29:49.000Z"
}
]
}
GET {host}.winterlightlabs.com/api/v1/participants
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
zone_id | string | Required. 21-character guid for the zone you want participants from. |
Delete a Participant
const axios = require('axios');
const subdomain = '...';
const participantId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/participants/${participantId}`,
method: 'DELETE',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint deletes a participant. You cannot delete a participant once it has samples associated with it.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "ggG305vkzYyAT3dL3yaOS"
}
}
DELETE {host}.winterlightlabs.com/api/v1/participants/{id}
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the participant. |
Samples
The sample resource represents a completed speech task by a participant.
Each sample will have a task (such as “Picture Description”), a stimulus specific to that task (such as “Cookie Theft”), language and transcription mode. The specific combination of task, stimulus, languages and transcription modes you can submit tasks for is determined by the project. You can only submit samples for tasks supported by your project. Attempting to submit an unsupported task will result in a 400 UNSUPPORTED_TASK
error. Please contact your account manager to make changes to your project if necessary.
By default, some of the fields for the sample are marked as optional, but they can be flagged as required in the project’s required_sample_fields
property dependent on the nature of your project.
Fields
An example sample resource:
{
"id": "tIZKtyZ_9_xb-z3sXsUzy",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ggG305vkzYyAT3dL3yaOS",
"locale_country_code": "CA",
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_picnic",
"transcription_mode": "manual",
"sample_state": "success",
"sample_source": "self_administered",
"session_order": null,
"administered_at": "2021-04-04T00:00:00.000Z",
"audio_file_id": "gNw16GBfP3QueX7MgqPJN",
"audio_file_md5": "e579af75b24bc28806c4dc27a4bb3d5b",
"audio_file_duration": 120.24,
"insights": ["v1/features"],
"reports": [
{
"id": "zp8q5-FtyfI8w4934bghR",
"status": "success",
"error_id": null,
"error_source": null,
"features": {
"id": "mviEBibuufW2f4P5L1FbU",
"insight_name": "v1/features",
"insight_type": "features",
"type": "json/ieee-754",
"version": "0.52.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"aggregate_features": {
"id": "EbUxzNxYTk4qm1ymvYM45",
"insight_name": "v1/aggregate_features",
"insight_type": "aggregate_features",
"type": "json/ieee-754",
"version": "0.15.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"transcript": {
"id": "hFLV02yZIRW_SUuQ1rqtd",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "2.0.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"qa_tags": {
"id": "_yL6iH5rAHbMUHkuer-We",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "0.2.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"created_at": "2021-07-28T19:34:16.000Z"
}
],
"external_id": "external-sample-id",
"external_label": null,
"meta": {
"whatever_you_want": "for_example_task_instructions_used"
},
"created_at": "2021-07-15T19:01:30.000Z",
"submitted_at": "2021-07-15T19:01:30.000Z"
}
Name | Type | Description |
---|---|---|
id | string | 21-character guid. |
team_id | string | 21-character guid for sample’s team. |
project_id | string | 21-character guid for sample’s project. |
zone_id | string | 21-character guid for sample’s zone. |
participant_id | string | 21-character guid for sample’s participant. |
locale_country_code | string | 2-character code for their native locale country (e.g. CA for Canada). |
language_id | string | 2-character ISO 639-1 language code (e.g. “en”) |
task_id | string | A machine-readable name for a supported speech task. |
stimulus_id | string | A machine-readable name for a speech task stimulus (if applicable). |
transcription_mode | string | The requested transcription method for the sample. |
sample_state | string | See “Sample States” section below. |
sample_source | string | See “Sample Sources” section below. |
session_order | integer | The session number for the sample (starting with 1). Multiple samples can be submitted for the same session. |
administered_at | date | The date the task was completed by the participant. Used to determine task order. |
audio_file_id | string | 21-character guid to identify the submitted audio file for asset tracking. |
audio_file_md5 | string | A md5 of the submitted audio file. |
audio_file_duration | float | The duration of the submitted audio file in seconds to four digits of precision. |
insights | array | See “Insights” section. |
reports | array | See “Reports” section. |
external_id | string | Your system’s id for the sample. |
external_label | string | A label for the sample. Can be used to store the original filename or a descriptive label (e.g. baseline visit). |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
created_at | date | The date the sample was created. |
submitted_at | date | The date the sample audio was uploaded and the sample was submitted for processing. |
Sample Sources
How and where the Winterlight tasks have been administered affect the quality and nature of the audio. Providing a sample_source
field allows us to potentially compensate for noise or other anomalies in the audio.
Value | Description |
---|---|
self_administered | The participant completed the task themselves without assistance. |
caregiver | The participant completed the task themselves with the aid of a trained caregiver. |
rater_in_person | The task was administered by a rater or other trained professional in-person. |
rater_via_phone | The task was administered by a rater or other trained professional over the phone. |
rater_via_video | The task was administered by a rater or other trained professional during a video call. |
Sample States
You can inspect the sample_state
value to see the status of your sample.
Value | Description |
---|---|
draft | The sample resource was created, but no audio file has been uploaded. |
pending | An audio file has been uploaded and the sample has been submitted for analysis. |
error | An error occurred in the processing or the file was invalid (e.g. no human speech). |
success | The sample has been successfully analyzed and a report was generated. |
The audio_file_id
, audio_file_md5
, and audio_file_duration
values will be null
until an audio file is uploaded and the sample leaves the draft
phase.
If the sample_state
is success
or error
that indicates there is a entry in reports
with your result or cause of the error.
Reports
Once the sample is analyzed its sample_state
will enter the success
or error
state and have one or more report sub-resources. A successful report will have one or more insights attached to it. An insight is a single derived value from the sample (e.g. transcript
, qa_tags
, etc). See the Insights section for more details.
When you call a sample endpoint you will get a truncated result that does not include the insight data due to size constraints. You need to call the report endpoint directly to get the insight results.
Fields
An example successful report resource:
{
"id": "zp8q5-FtyfI8w4934bghR",
"status": "success",
"error_id": null,
"error_source": null,
"features": {
"id": "mviEBibuufW2f4P5L1FbU",
"insight_name": "v1/features",
"insight_type": "features",
"type": "json/ieee-754",
"version": "0.52.0",
"data": "...",
"created_at": "2021-07-28T19:34:16.000Z"
},
"aggregate_features": {
"id": "EbUxzNxYTk4qm1ymvYM45",
"insight_name": "v1/aggregate_features",
"insight_type": "aggregate_features",
"type": "json/ieee-754",
"version": "0.15.0",
"data": "...",
"created_at": "2021-07-28T19:34:16.000Z"
},
"transcript": {
"id": "hFLV02yZIRW_SUuQ1rqtd",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "2.0.0",
"data": "...",
"created_at": "2021-07-28T19:34:16.000Z"
},
"qa_tags": {
"id": "_yL6iH5rAHbMUHkuer-We",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "0.2.0",
"data": "...",
"created_at": "2021-07-28T19:34:16.000Z"
},
"created_at": "2021-07-28T19:34:16.000Z"
}
An example error report resource:
{
"id": "euh9_PxiZowd4vjCY9eJ4",
"status": "error",
"error_id": "WRONG_LANGUAGE",
"error_source": "transcription",
"created_at": "2021-07-28T19:34:16.000Z"
}
Name | Type | Description |
---|---|---|
id | string | 21-character guid. |
status | string | Either “success” or “error”. |
error_id | string | See “Report Errors” section. Null if state is “success”. |
error_source | string | See “Report Errors” section. Null if state is “success”. |
features | object | See “Insights” section. Undefined or null if state is “error”. |
aggregate_features | object | See “Insights” section. Undefined or null if state is “error”. |
transcript | object | See “Insights” section. Undefined or null if state is “error”. |
qa_tags | object | See “Insights” section. Undefined or null if state is “error”. |
created_at | date | The date the report was created. |
Report Errors
Below is a list of possible error_id
and error_source
values. The possible report errors are determined by the transcription method. As a general rule, manual transcription is able to catch a wider range of issues and with more detail because it doubles as a quality assurance step.
Error Id | Error Source | Transcription Modes | Meaning |
---|---|---|---|
UNSUPPORTED_FILE | analysis | all | The audio file was unable to processed (e.g. wav file is 24-bits). |
ADMINISTRATION_ISSUE | transcription | manual | There is explicit commenting on an issue with the task itself in the recording (e.g. picture not showing). |
INAUDIBLE_PARTICIPANT | transcription | manual | This sample cannot be transcribed due to inaudible participant speech. |
INVALID_AUDIO | transcription | manual | The audio is unusable due to a clear issue with the recording itself. |
NO_PARTICIPANT | transcription | manual | This sample cannot be transcribed due to there being no participant in the recording. |
WRONG_LANGUAGE | transcription | manual | The majority of the sample has the participant speaking a different language. |
NO_SPEECH_DETECTED | transcription | asr | The audio has no detectable human speech. |
Children Resources
Create a Sample
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/samples`,
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
participant_id: 'ggG305vkzYyAT3dL3yaOS',
language_id: 'en',
task_id: 'picture_description',
stimulus_id: 'winterlight_picnic',
sample_source: 'self_administered',
session_order: 5,
administered_at: '2021-04-04T00:00:00.000Z',
external_id: '456',
external_label: 'subject-123-456_week-5.mp3',
meta: {
task_instruction: 'What do you see in this picture?',
task_timeout: 360,
},
}),
});
This endpoint creates a new sample. A sample cannot be moved to a different zone once it is created. Creating a sample does not immediately submit it for analysis and will be in the draft
state. You need to call the POST /api/v1/samples/{id}/audio
endpoint afterwards to upload the audio file and submit it.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 201,
"ok": true,
"data": {
"id": "tIZKtyZ_9_xb-z3sXsUzy",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ggG305vkzYyAT3dL3yaOS",
"locale_country_code": "CA",
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_picnic",
"transcription_mode": "manual",
"sample_state": "draft",
"sample_source": "self_administered",
"session_order": 5,
"administered_at": "2021-04-04T00:00:00.000Z",
"audio_file_id": null,
"audio_file_md5": null,
"audio_file_duration": null,
"external_id": "456",
"external_label": "subject-123-456_week-5.mp3",
"insights": ["v1/features"],
"reports": [],
"meta": {
"task_instruction": "What do you see in this picture?",
"task_timeout": 360
},
"created_at": "2021-07-15T19:01:30.000Z",
"submitted_at": null
}
}
Note that locale_country_code
and language_id
refer to the language spoken when completing the assessment and not the participant’s native language.
POST {host}.winterlightlabs.com/api/v1/samples
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
participant_id | string | Required. 21-character guid for sample’s participant. |
locale_country_code | string | Required. 2-character code for locale country (e.g. CA for Canada) when completing the task. |
language_id | string | § Required. 2-character code for locale language (e.g. en for English) when completing the task. |
task_id | string | § Required. A machine-readable name for a supported speech task. |
stimulus_id | string | § A machine-readable name for a speech task stimulus (if applicable). |
transcription_mode | string | § The requested transcription method for the sample. Optional if task supports a single mode. |
insights | array | See “Insights” section. |
sample_source | string | See “Sample Sources” section. |
session_order | integer | (•) The session number for the sample (starting with 1). |
administered_at | date | Required. The date the task was completed by the participant. Used to determine task order. |
external_id | string | (•) Your system’s id for the sample. |
external_label | string | (•) A label for the sample. Can be used to store the original filename or a descriptive label (e.g. baseline visit). |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
All fields marked with a (•) can be marked as required dependent on the project required_sample_fields
value.
All fields marked with a § will be checked against the project’s list of supported tasks.
Submit a Sample
const fs = require('fs');
const axios = require('axios');
const FormData = require('form-data');
const subdomain = '...';
const sampleId = '...';
const apiToken = '...';
const audioFilePath = '...';
const formData = new FormData();
formData.append('audio_file', fs.createReadStream(audioFilePath), {
knownLength: fs.statSync(audioFilePath).size,
});
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/samples/${sampleId}/audio`,
method: 'POST',
headers: {
'Content-Length': formData.getLengthSync(),
Accept: 'application/json',
// Sets the content-type to be "multipart/form-data; boundary={boundary}"
...formData.getHeaders(),
Authorization: `Bearer ${apiToken}`,
},
data: formData,
});
This endpoint uploads the audio file for a sample and submits it for analysis.
Once it is submitted the state will change to pending
and will progress automatically through the subsequent states. You will receive a webhook callback upon every state change. If you try to upload another sample after the initial successful upload you will receive a 400 ALREADY_SUBMITTED
error.
Audio Requirements
The following audio formats are supported:
Ext | Notes |
---|---|
m4a | Common recording audio format from smartphones. |
mp4 | Common recording audio format from smartphones. |
webm | Common recording audio format from internet browsers. |
wav | 24-bit is not supported. |
mp3 | |
ogg | |
oga | |
opus |
The following errors can be encountered when trying to upload a file:
Status | Error Code | Description |
---|---|---|
400 | DURATION_EXCEEDED_LIMIT | Duration longer than supported by the project. |
400 | AUDIO_TOO_SHORT | Duration is under 1 second. |
400 | EMPTY_FILE | File has no data. |
400 | INCOMPLETE_FILE | File is missing parts or is unterminated. |
400 | INVALID_AUDIO | File is corrupt or incorrectly typed. |
400 | MISSING_FILE | No file uploaded. |
413 | FILE_TOO_LARGE | File is larger than 150mb. |
415 | UNKNOWN_FILE_TYPE | Could not identify file type. |
415 | UNSUPPORTED_FILE_TYPE | File type is not supported (see list above). |
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | Yes |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 201,
"ok": true,
"data": {
"id": "tIZKtyZ_9_xb-z3sXsUzy",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ggG305vkzYyAT3dL3yaOS",
"locale_country_code": "CA",
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_picnic",
"transcription_mode": "manual",
"sample_state": "pending",
"sample_source": "self_administered",
"session_order": 5,
"administered_at": "2021-04-04T00:00:00.000Z",
"audio_file_id": "gNw16GBfP3QueX7MgqPJN",
"audio_file_md5": "e579af75b24bc28806c4dc27a4bb3d5b",
"audio_file_duration": 120.24,
"external_id": "456",
"external_label": "subject-123-456_week-5.mp3",
"insights": ["v1/features"],
"reports": [],
"meta": {
"task_instruction": "What do you see in this picture?",
"task_timeout": 360
},
"created_at": "2021-07-15T19:01:30.000Z",
"submitted_at": "2021-07-15T19:01:30.000Z"
}
}
POST {host}.winterlightlabs.com/api/v1/samples/{id}/audio
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
id | string | The id of the sample. |
audio_file | file | Required. The audio recording of the assessment. Must be less than 150mb. |
Update a Sample
const axios = require('axios');
const subdomain = '...';
const sampleId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/samples/${sampleId}`,
method: 'PATCH',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
data: JSON.stringify({
external_id: 'updated_external_id',
external_label: 'updated_external_label',
meta: {
some_other_meta: 'data',
},
}),
});
This endpoint updates a sample. Only fields that do not affect analysis may be modified after the sample is created.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 201,
"ok": true,
"data": {
"id": "tIZKtyZ_9_xb-z3sXsUzy",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ggG305vkzYyAT3dL3yaOS",
"locale_country_code": "CA",
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_picnic",
"transcription_mode": "manual",
"sample_state": "draft",
"sample_source": "self_administered",
"session_order": 5,
"administered_at": "2021-04-04T00:00:00.000Z",
"audio_file_id": null,
"audio_file_md5": null,
"audio_file_duration": null,
"external_id": "updated_external_id",
"external_label": "updated_external_label",
"insights": ["v1/features"],
"reports": [],
"meta": {
"some_other_meta": "data"
},
"created_at": "2021-07-15T19:01:30.000Z",
"submitted_at": null
}
}
PATCH {host}.winterlightlabs.com/api/v1/samples/{id}
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
id | string | Required. 21-character guid for the sample. |
external_id | string | (•) Your system’s id for the sample. |
external_label | string | (•) A label for the sample. Can be used to store the original filename or a descriptive label (e.g. baseline visit). |
meta | object | Any valid object. This will be returned alongside any webhook callback. |
All fields marked with a (•) can be marked as required dependent on the project required_sample_fields
value.
Get a single Sample
const axios = require('axios');
const subdomain = '...';
const sampleId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/samples/${sampleId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves a specific sample.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "tIZKtyZ_9_xb-z3sXsUzy",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ggG305vkzYyAT3dL3yaOS",
"locale_country_code": "CA",
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_picnic",
"transcription_mode": "manual",
"sample_state": "success",
"sample_source": "self_administered",
"session_order": null,
"administered_at": "2021-04-04T00:00:00.000Z",
"audio_file_id": "gNw16GBfP3QueX7MgqPJN",
"audio_file_md5": "e579af75b24bc28806c4dc27a4bb3d5b",
"audio_file_duration": 120.24,
"insights": ["v1/features"],
"reports": [
{
"id": "zp8q5-FtyfI8w4934bghR",
"status": "success",
"error_id": null,
"error_source": null,
"features": {
"id": "mviEBibuufW2f4P5L1FbU",
"insight_name": "v1/features",
"insight_type": "features",
"type": "json/ieee-754",
"version": "0.52.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"aggregate_features": {
"id": "EbUxzNxYTk4qm1ymvYM45",
"insight_name": "v1/aggregate_features",
"insight_type": "aggregate_features",
"type": "json/ieee-754",
"version": "0.15.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"transcript": {
"id": "hFLV02yZIRW_SUuQ1rqtd",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "2.0.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"qa_tags": {
"id": "_yL6iH5rAHbMUHkuer-We",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "0.2.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"created_at": "2021-07-28T19:34:16.000Z"
}
],
"external_id": "external-sample-id",
"external_label": null,
"meta": {
"whatever_you_want": "for_example_task_instructions_used"
},
"created_at": "2021-07-15T19:01:30.000Z",
"submitted_at": "2021-07-15T19:01:30.000Z"
}
}
GET {host}.winterlightlabs.com/api/v1/samples/{id}
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
id | string | The id of the sample. |
Get all Samples
const axios = require('axios');
const subdomain = '...';
const participantId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/samples?participant_id=${participantId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves all samples for the specified participant.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": [
{
"id": "tIZKtyZ_9_xb-z3sXsUzy",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ggG305vkzYyAT3dL3yaOS",
"locale_country_code": "CA",
"language_id": "en",
"task_id": "picture_description",
"stimulus_id": "winterlight_picnic",
"transcription_mode": "manual",
"sample_state": "success",
"sample_source": "self_administered",
"session_order": null,
"administered_at": "2021-04-04T00:00:00.000Z",
"audio_file_id": "gNw16GBfP3QueX7MgqPJN",
"audio_file_md5": "e579af75b24bc28806c4dc27a4bb3d5b",
"audio_file_duration": 120.24,
"insights": ["v1/features"],
"reports": [
{
"id": "zp8q5-FtyfI8w4934bghR",
"status": "success",
"error_id": null,
"error_source": null,
"features": {
"id": "mviEBibuufW2f4P5L1FbU",
"insight_name": "v1/features",
"insight_type": "features",
"type": "json/ieee-754",
"version": "0.52.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"aggregate_features": {
"id": "EbUxzNxYTk4qm1ymvYM45",
"insight_name": "v1/aggregate_features",
"insight_type": "aggregate_features",
"type": "json/ieee-754",
"version": "0.15.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"transcript": {
"id": "hFLV02yZIRW_SUuQ1rqtd",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "2.0.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"qa_tags": {
"id": "_yL6iH5rAHbMUHkuer-We",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "0.2.0",
"created_at": "2021-07-28T19:34:16.000Z"
},
"created_at": "2021-07-28T19:34:16.000Z"
}
],
"external_id": "external-sample-id",
"external_label": null,
"meta": {
"whatever_you_want": "for_example_task_instructions_used"
},
"created_at": "2021-07-15T19:01:30.000Z",
"submitted_at": "2021-07-15T19:01:30.000Z"
}
]
}
GET {host}.winterlightlabs.com/api/v1/samples
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
participant_id | string | Required. 21-character guid for the participant you want samples from. |
Get a single Report
const axios = require('axios');
const subdomain = '...';
const reportId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/samples/reports/${reportId}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves a specific report. Unlike the list of reports found calling a sample endpoint, requesting the report directly also provides the data
values for transcript
, qa_tags
and any insights that you have requested.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | Yes |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | Yes |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": {
"id": "zp8q5-FtyfI8w4934bghR",
"status": "success",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ggG305vkzYyAT3dL3yaOS",
"sample_id": "tIZKtyZ_9_xb-z3sXsUzy",
"error_id": null,
"error_source": null,
"features": {
"id": "mviEBibuufW2f4P5L1FbU",
"insight_name": "v1/features",
"insight_type": "features",
"type": "json/ieee-754",
"version": "0.52.0",
"data": "...",
"created_at": "2021-07-28T19:34:16.000Z"
},
"aggregate_features": {
"id": "EbUxzNxYTk4qm1ymvYM45",
"insight_name": "v1/aggregate_features",
"insight_type": "aggregate_features",
"type": "json/ieee-754",
"version": "0.15.0",
"data": "...",
"created_at": "2021-07-28T19:34:16.000Z"
},
"transcript": {
"id": "hFLV02yZIRW_SUuQ1rqtd",
"insight_name": "v1/transcript",
"insight_type": "transcript",
"type": "json",
"version": "2.0.0",
"data": "...",
"created_at": "2021-07-28T19:34:16.000Z"
},
"qa_tags": {
"id": "_yL6iH5rAHbMUHkuer-We",
"insight_name": "v1/qa_tags",
"insight_type": "qa_tags",
"type": "json",
"version": "0.2.0",
"data": "...",
"created_at": "2021-07-28T19:34:16.000Z"
},
"created_at": "2021-07-28T19:34:16.000Z"
}
}
GET {host}.winterlightlabs.com/api/v1/samples/reports/{id}
Parameter | Type | Description |
---|---|---|
host | string | The zone’s region_host . |
id | string | The id of the report. |
Insights
An insight is any piece of data generated for the use of or as the result of Winterlight speech analysis. Examples of insights include transcripts, speech features or model predictions.
Insights can be found in the report sub-resource and have the following fields:
Name | Type | Description |
---|---|---|
id | string | 21-character guid. This is specific insight for sample. |
insight_name | string | See “Insight Versioning” section. |
insight_type | string | The generic insight type (e.g. “transcript”). |
version | string | See “Insight Versioning” section. |
type | string | See “Insight Data Types” section. |
data | varies | See “Insight Data” section. |
created_at | date | The date the insight was created. |
Requesting Insights
When you request a sample you can provide one or more insights in the sample.insights
field. The insights you can request for a sample is determined by your project’s project.supported_insights
field. By default, every successful report will provide the "v1/transcript"
and if possible, "v1/qa_tags"
insights.
If your project’s project.can_specify_insights
is false
then you should not use sample.insights
field. Samples for that project will always used the insights specified in the project’s project.default_insights
field.
We currently only support the following insights:
Name | Description |
---|---|
"v1/transcript" |
The annotated transcript for the audio sample as JSON. Provide with any v1/* request. Deprecated. |
"v1/qa_tags" |
Tags about the quality of the sample as JSON. Only provided with a v1/* request and when using manual transcription. Deprecated. |
"v1/features" |
Raw features for the audio sample. Provided when explicitly requesting the "v1/features" insight. Deprecated. |
"v1/feature_aggregates" |
Provided when explicitly requesting the "v1/features" insight for picture_description task samples. Deprecated. |
"v2/transcript" |
The annotated transcript for the audio sample as an object. Provide with any v2/* request. |
"v2/qa_tags" |
Tags about the quality of the sample as an object. Only provided with a v1/* request and when using manual transcription. |
"v2/features" |
Raw features for the audio sample that includes norms. Provided when explicitly requesting the "v2/features" insight. |
"v2/feature_aggregates" |
Provided when explicitly requesting the "v2/features" insight for picture_description task samples. |
Insight Versioning
The quality of winterlight’s analysis improves over time and that progression is tracked in the insight_name
and version
fields.
The insight_name
determines the structure of the response for the given insight_type
and affects how you would parse the data (e.g. the type
field could vary across different variants). The insight_name
will not change without notice.
The version
is the semantic version value (e.g. “4.3.10”) of the data
field and will change without notice. An increment in the version represents an improvement of our analysis.
Insight Data Types
Name | Data Type | Notes |
---|---|---|
"object" |
object | |
"json" |
string | |
"json/ieee-754" |
string | See below. |
The "json/ieee-754"
type refers to JSON that has been extended to include IEEE754 is the Standard for Floating-Point Arithmetic symbols of NaN
, Infinity
and -Infinity
. This form of JSON is not in compliance with the JSON specification and cannot be parsed in some languages without an aid of additional library (e.g. json5 for Javascript). However, since it is convenient when working in a mathematical context there are a number of languages that support it natively. For example, this type of json is generated by default via Python’s json.dumps()
function. In the future, we may transition to using fully compliant JSON only.
Insight Data
The data
field is the insight (e.g. speech features, transcript, etc) itself in the format indicated by the type
field.
The data
field is omitted unless you call the report endpoint directly. Note that while the structure or schema of data will stay consistent, the values will change due to advances in our technology or the source being inherently non-deterministic (e.g. manual transcription). Changes in the how values are generated roughly correspond to changes in the version
field.
Note that the data
value can be quite large and if you’re using a SQL database we recommend using the MEDIUMTEXT
column type (up to 1677721 characters string).
Insight - Features
When you request the "v2/features"
insight you will get all the extracted features for the sample. If applicable (e.g. for picture_description
task samples), you will also get the "v2/aggregate_features"
as well.
v2/features
Example “v2/features” insight:
{
"id": "mfcc_mean_0",
"type": "acoustic",
"name": "mfcc_mean_0",
"description": null,
"value": -0.68986894374885,
"value_normalized": -0.68986894374885,
"is_continuous": true,
"norms": {
"mean": 0.0024772348640208926,
"std": 0.0031637458173641156
}
}
Name | Type | Description |
---|---|---|
id | string | A machine-readable id for the feature. |
type | string | How the feature was generated. Either “acoustic” or “text”. |
name | string | A human-readable name for the feature. Currently always the same as its id. |
description | string | A human-readable description for the feature. Currently always null. |
value | number | The feature value. Null if the feature could not be calculated (e.g. there is no speech). |
value_normalized | number | If applicable, this is the feature value divided by a relevant constant (e.g. audio duration). The constant varies feature by feature. If the feature does not have a normalization constant and does not need to be normalized, value_normalized will be the same as value . If value is null, then value_normalized is also null. |
is_continuous | bool | If true, the value has fractional values. Otherwise, it is an integer. |
norms | object | The mean and standard deviation from the norm. This is null if there are no norms for this particular task or language. |
v2/aggregate_features
Example “v2/aggregate_features” insight:
{
"id": "ability_to_express_thoughts_and_needs",
"type": "sample",
"name": "Ability to Express Thoughts and Needs",
"description": "How clearly ideas were expressed, including orderly flow of information and how well the words and sentences are connected. The results are expressed relative to a healthy normative group.",
"value": null,
"value_normalized": null,
"value_percentile": null,
"polarity": 1,
"null_description": "Could not be measured because less than two sentences were detected in the transcript. At least two sentences are required to estimate coherence.",
"norms": {
"mean": 1.0855514018557086e-16,
"std": 0.5202166560856382
}
}
Name | Type | Description |
---|---|---|
id | string | A machine-readable id for the feature. |
type | string | How the feature was generated. Currently always “sample”. |
name | string | A human-readable name for the aggregate feature |
description | string | A human-readable description for the aggregate feature |
value | number | The aggregate feature value created from z-scoring its features. This is null if a feature could not be calculated. |
value_normalized | number | The aggregate value z-scored against the norms. This is null if a feature could not be calculated. |
value_percentile | number | A value between 0 and 100 indicating the value percentile. |
polarity | bool | If 1, a larger value indicates a positive correlation with the attribute being measured. |
null_description | string | If the aggregate feature cannot be calculated, this will specify the reason. |
norms | object | The mean and standard deviation from the norm. This is null if there are no norms for this particular task or language. |
Webhooks
Webhooks allow you to subscribe to different events from our system. For example, it allows you to receive updated features for existing samples automatically without needing to periodically check an endpoint.
If a webhook_url
is defined for a zone, the API will send POST callbacks to the webhook_url
with a x-winterlight-secret={zone.webhook_secret}
header for authentication.
If a webhook event data
would normally be a resource that contains sensitive data, those fields would be omitted. This is to prevent the leaking of sensitive data if webhook_url
is misconfigured. In these cases, you can retrieve the complete resource by calling the resource_url
specified in the event. Note that any sensitive data in the meta
field will not be omitted automatically.
There are the following caveats when it comes to handling webhook events:
- We do not guarantee just-once delivery. We will retry to resend any webhook events that were not successfully received. If the webhook event however is received, but the destination server specified in the
webhook_url
returns a non-success status code for whatever reason, the retry attempt would result in the same event appearing twice. It is important to ensure your webhook handler is idempotent. - We do not guarantee delivery of events. It’s possible that the destination specified in the
webhook_url
is unreachable for the initial request and subsequent retry attempts (up to 3 attempts within an hour). In this scenario you will need to manually fetch the data from the relevant resource. - We do not guarantee delivery of events in the order in which they are generated. Due to the aforementioned retry mechanism, it is possible that older events are received after more recent ones. All webhook events have a
created_at
property of when they were generated and many webhook events will provide aresource_url
which will allow you to subsequently fetch the most up-to-date data.
The callback will always use the following wrapper:
A example of a webhook event:
{
"event_id": "FZI37LUxznExdKuxuZArv",
"event_type": "v1/system.noop",
"zone_id": "JMW5IcFQ6rAJDbRAeuQXR",
"data": "...",
"meta": {
"zone": "...",
"participant": "...",
"sample": "..."
},
"resource_type": "...",
"resource_url": "...",
"created_at": "2020-01-01T12:12:12.000Z"
}
Name | Type | Description |
---|---|---|
event_id | string | A 21-character idempotent event id. |
event_type | string | The type of the event. |
zone_id | string | A 21-character guid of the webhook zone. |
data | object | Dependent on event_type . |
meta | object | The meta objects for the zone, participant and sample. Null if no meta values defined. |
resource_type | string | The type of the resource for the event. Null if not relevant. |
resource_url | string | The https url to get the affected resource. Null if not relevant. |
created_at | date | The date the event was sent. |
When creating a zone you can define a meta
object property. The meta
value will be returned in the callback. This is useful if you want to track a value using your own id for whatever reason. The meta
value is also useful pass along information if you are collaborating directly with Winterlight. There is a meta
value for the zone, participant and samples; and they are merged together in the callback.
Event - Report Created
Example event:
{
"event_id": "FZI37LUxznExdKuxuZArv",
"event_type": "v1/sample.report_created",
"zone_id": "JMW5IcFQ6rAJDbRAeuQXR",
"data": {
"id": "zp8q5-FtyfI8w4934bghR",
"status": "success",
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ggG305vkzYyAT3dL3yaOS",
"sample_id": "tIZKtyZ_9_xb-z3sXsUzy",
"error_id": null,
"error_source": null,
"created_at": "2021-07-28T19:34:16.000Z"
},
"meta": {
"zone": "...",
"participant": "...",
"sample": "..."
},
"resource_type": "report",
"resource_url": "https://api-ca.winterlightlabs.com/api/v1/samples/reports/zp8q5-FtyfI8w4934bghR",
"created_at": "2020-01-01T12:12:12.000Z"
}
Property | Value |
---|---|
Type | v1/sample.report_created |
Trigger | Report created for a sample. |
Meta Values | Zone, Participant, Sample |
This event is sent whenever a report is generated for a sample. The webhook data
value is equivalent to what you receive when you call the report endpoint directly, but the insights will be omitted because it may contain sensitive data.
Audit Logs
Any user request related to user management, creation of new projects/zones or interaction with sensitive data is logged for auditing purposes.
Fields
An example audit entry:
{
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ovpKemJHhn_ePG94YpNpP",
"sample_id": null,
"timestamp": "2021-01-05T20:03:57.000Z",
"location": "172.20.0.1",
"code": 200,
"user_id": "DwP3qnDcHsaB4V6Ti-wb-",
"user_label": "API Token",
"target_user_id": null,
"target_user_label": null,
"is_sensitive": 1,
"resource": "participant",
"action": "list",
"params": {
"sample_ids": ["CwqM6oTRbPStHecXhOiK9"]
}
}
Name | Type | Description |
---|---|---|
team_id | string | 21-character guid for originating team. |
project_id | string | 21-character guid for originating project. |
zone_id | string | 21-character guid for originating zone, if relevant. |
participant_id | string | 21-character guid for originating participant, if relevant. |
sample_id | string | 21-character guid for originating sample, if relevant. |
timestamp | date | The date event was logged. |
location | string | The ip of where the originating request. |
code | number | Status code of the request. |
user_id | string | 21-character guid for the user who made the request. Null if it’s unauthenticated user. |
user_label | string | A label of the user (e.g. “API Token” or “Winterlight Labs”) who did the action. |
target_user_id | string | 21-character guid for the user affected by the request, if relevant. |
target_user_label | string | A meaningful label of the user who was affected by the the action. |
resource | string | The name of the resource being affected by the action. |
action | string | See “Actions” section below. |
params | object | See “Actions” section below. |
Actions and Params
The action
field describes the event that occurred. The params
property is present for some action
s and provides additional context for the action. The list of possible actions are below:
create
: User or Resource Action. The user created another user or resource. If the user created a derivative for a resource (e.g. uploaded an audio file for a sample), params should have aderivative
property or equivalent.read
: Resource Action. The user viewed a resource.update
: Resource Action. The user updated a resource. If the user updated a derivative for a resource (e.g. uploaded an audio file for a sample), params should have aderivative
property or equivalent.delete
: Resource Action. The user deleted a resource. If the user deleted a derivative for a resource (e.g. uploaded an audio file for a sample), params should have aderivative
property or equivalent.list
: Special Action. The user is viewing multiple resource at once as specified in params. Params should only include the one of following arraysparticipant_ids
orsample_ids
. Only the highest-level resource can be declared as an params array and all lower-level resources should declared normally. For example, ifsample_ids
is defined in params, thenproject_id
,zone_id
andparticipant_id
should be set. If not possible to know which resources were accessed due to an error, then{resource}_ids
value can be set to[]
.
Get Team Audit Logs
const axios = require('axios');
const subdomain = '...';
const teamId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/teams/${teamId}/audit-logs`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves the last 100 audit log events for the team, projects, users and zones. This does not include any zone children resource of zones (e.g. participants or samples).
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": [
{
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "KEdbspOB3BY7vbKfUpruJ",
"zone_id": null,
"timestamp": "2021-08-06T00:14:43.000Z",
"location": "172.20.0.1",
"code": 201,
"user_id": "DwP3qnDcHsaB4V6Ti-wb-",
"user_label": "Winterlight Labs",
"target_user_id": null,
"is_sensitive": 0,
"resource": "project",
"action": "create",
"params": null
}
]
}
GET {host}.winterlightlabs.com/api/v1/teams/{id}/audit-logs
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the team. |
Get Zone Audit Logs
const axios = require('axios');
const subdomain = '...';
const zoneId = '...';
const apiToken = '...';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/zones/${zoneId}/audit-logs`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves the last 100 audit log events for the zone and all of its children resources.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": [
{
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ovpKemJHhn_ePG94YpNpP",
"sample_id": "CwqM6oTRbPStHecXhOiK9",
"timestamp": "2021-08-05T19:58:13.000Z",
"location": "172.20.0.1",
"code": 200,
"user_id": "DwP3qnDcHsaB4V6Ti-wb-",
"user_label": "API Token",
"target_user_id": null,
"target_user_label": null,
"is_sensitive": 1,
"resource": "participant",
"action": "read",
"params": null
},
{
"team_id": "vyy5bHHXSbZ2PaNHz4c7f",
"project_id": "FZI37LUxznExdKuxuZArv",
"zone_id": "YEV8qyUpIdcHWonkhau5E",
"participant_id": "ovpKemJHhn_ePG94YpNpP",
"sample_id": null,
"timestamp": "2021-08-05T20:03:57.000Z",
"location": "172.20.0.1",
"code": 200,
"user_id": "DwP3qnDcHsaB4V6Ti-wb-",
"user_label": "API Token",
"target_user_id": null,
"target_user_label": null,
"is_sensitive": 1,
"resource": "participant",
"action": "list",
"params": {
"sample_ids": ["CwqM6oTRbPStHecXhOiK9"]
}
}
]
}
GET {host}.winterlightlabs.com/api/v1/zones/{id}/audit-logs
Parameter | Type | Description |
---|---|---|
host | string | Any valid winterlight region url. |
id | string | The id of the zone. |
Billing
The billing resource gives fine-grained access to API usage costs. Whenever you call an endpoint that has the Can result in invoice charges?
special property, those charges would be appear here.
Fields
An example billing resource:
{
"cost_type": "depression_insight",
"sample_id": "7lu-L-11u3Rqt8p11c9uI",
"project_id": "FZI37LUxznExdKuxuZArv",
"charged_at": "2021-10-29T23:59:59.000Z",
"invoice_date": "2021-10-31T00:00:00.000Z",
"amount": 3.0
}
Name | Type | Description |
---|---|---|
cost_type | string | See “cost types” below. |
sample_id | string | 21-character guid of the sample that incurred the cost. |
project_id | string | 21-character guid of the project that incurred the cost. |
charged_at | date | The date when the cost was incurred. |
invoice_date | date | See “invoice dates” below. |
amount | number | The amount of the cost in the team’s currency. |
Cost Types
Depending on the Winterlight offering that your team has chosen, different uses of the API will incur different costs. The cost_type
field is an enum value that indicates the type of event that incurred the cost. Speak with your Winterlight contact to get more detail on how to interpret these values for your plan.
Invoice Dates
If a cost has already been invoiced to you, the invoice date of the corresponding invoice will be specified. If the cost is still pending an invoice, the invoice_date
will be null
.
Get all Costs
const axios = require('axios');
const subdomain = '...';
const apiToken = '...';
const fromDate = '2021-04-04T00:00:00.000Z';
const toDate = '2021-04-05T00:00:00.000Z';
axios({
url: `https://${subdomain}.winterlightlabs.com/api/v1/billing?from=${fromDate}&to=${toDate}`,
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
This endpoint retrieves all costs that were incurred between from
and to
for the team associated with the given token.
Special Properties
Property | Applicable? |
---|---|
Requires team admin permissions? | No |
Requires region-specific url due to sensitive data? | No |
Can result in invoice charges? | No |
Is activity recorded in audit logs? | No |
Request Parameters
Example response:
{
"status": 200,
"ok": true,
"data": [
{
"cost_type": "depression_insight",
"sample_id": "7lu-L-11u3Rqt8p11c9uI",
"project_id": "FZI37LUxznExdKuxuZArv",
"charged_at": "2021-11-26T23:59:59.000Z",
"invoice_date": null,
"amount": 3.0
},
{
"cost_type": "depression_insight",
"sample_id": "3mZewtCKOWIjjM_DrBULL",
"project_id": "FZI37LUxznExdKuxuZArv",
"charged_at": "2021-10-20T13:02:37.000Z",
"invoice_date": "2021-10-31T00:00:00.000Z",
"amount": 3.0
},
{
"cost_type": "all_features_insight",
"sample_id": "5AA5rNT-2J5ZRbN8IKbjR",
"project_id": "FZI37LUxznExdKuxuZArv",
"charged_at": "2021-10-08T18:51:21.000Z",
"invoice_date": "2021-10-31T00:00:00.000Z",
"amount": 3.0
}
]
}
GET {host}.winterlightlabs.com/api/v1/billing
Parameter | Type | Description |
---|---|---|
host | string | Costs are team-based, so either region host will work. |
from | date | Start date of the range to retrieve costs for. Defaults to 30 days before to . |
to | date | End date of the range to retrieve costs for. Defaults to the current date+time. |
Reference
Status Codes
The Winterlight API uses the following status codes:
Status | Meaning |
---|---|
200 | Success. |
201 | Success and a new resource has been created. |
400 | Bad Request – Your request is invalid. |
401 | Unauthenticated – You need to be authenticated to access this resource. |
403 | Forbidden – Insufficient rights or the action is outright not allowed. |
404 | Not Found – The requested resource does not exist or you do not have permission. |
405 | Method Not Allowed – You tried to access the endpoint with an invalid method. |
413 | Payload Too Large – You attached a file that’s too large. |
415 | Unsupported Media Type - Unsupported content-type header. |
429 | Too Many Requests – You’ve made too many requests in a short period of time |
500 | Internal Server Error – We had a problem with our server. Try again later. |
503 | Service Unavailable – We’re temporarily offline for maintenance. Please try again later. |
Error Codes
In the event of a 400 or 500-type error, there will be an error
property defined in the JSON response explaining the reason using a machine readable string.
Error | Status | Meaning |
---|---|---|
ALREADY_SUBMITTED | 400 | The sample was already submitted with an audio file. |
AUDIO_TOO_SHORT | 400 | The sample duration is under 1 second. |
CANNOT_UPDATE_TASKS | 400 | Supported tasks/stimuli cannot be changed for this project. |
DURATION_EXCEEDED_LIMIT | 400 | The sample duration exceeded the project task max duration. |
EMPTY_FILE | 400 | Uploaded file has no data. |
FAILED_VALIDATION | 400 | Improperly structured request body. See reason property. |
INVALID_REGION_ID | 400 | Tried to create a zone with a region that is not supported by the project. |
FILE_TOO_LARGE | 413 | File is larger than 150 mb. |
FORBIDDEN | 403 | Your request is forbidden. |
INCOMPLETE_FILE | 400 | File is missing parts. |
INCORRECT_REGION | 400 | Sensitive data resource request from the incorrect region. |
INVALID_AUDIO | 400 | File is corrupt or incorrectly typed. |
MISSING_FILE | 400 | No file was provided in the request. |
NOT_AUTHENTICATED | 401 | Your token is invalid. |
NOT_FOUND | 404 | Resource not found or your permission is insufficient. |
SANDBOX_ONLY_PROJECT | 400 | Tried to create a zone in a project that is marked as sandbox only. |
UNEXPECTED_CONTENT_TYPE | 415 | The “content-type” header was inappropriate for the endpoint. |
UNKNOWN_FILE_TYPE | 415 | Could not identify file type. |
UNSUPPORTED_FILE_TYPE | 415 | File type is not supported. |
UNSUPPORTED_LANGUAGE_BY_ZONE | 400 | The sample language is not supported by the zone. |
UNSUPPORTED_TASK | 400 | The sample language, task and stimuli combination is unsupported. |
UNSUPPORTED_TRANSCRIPTION_MODE | 400 | The transcription mode cannot be used for this task + stimulus. |
Valid Country Codes
Code | Country |
---|---|
AF | Afghanistan |
AL | Albania |
DZ | Algeria |
AS | American Samoa |
AD | Andorra |
AO | Angola |
AI | Anguilla |
AG | Antigua and Barbuda |
AR | Argentina |
AM | Armenia |
AW | Aruba |
AU | Australia |
AT | Austria |
AZ | Azerbaijan |
BS | The Bahamas |
BH | Bahrain |
BD | Bangladesh |
BB | Barbados |
BY | Belarus |
BE | Belgium |
BZ | Belize |
BJ | Benin |
BM | Bermuda |
BT | Bhutan |
BO | Bolivia |
BA | Bosnia and Herzegovina |
BW | Botswana |
BR | Brazil |
VG | British Virgin Islands |
BN | Brunei |
BG | Bulgaria |
BF | Burkina Faso |
BI | Burundi |
KH | Cambodia |
CM | Cameroon |
CA | Canada |
CV | Cape Verde |
KY | Cayman Islands |
CF | Central African Republic |
TD | Chad |
CL | Chile |
CN | China |
CX | Christmas Island |
CC | Cocos (Keeling) Islands |
CO | Colombia |
KM | Comoros |
CG | Republic of the Congo |
CK | Cook Islands |
CR | Costa Rica |
CI | Cote d’Ivoire |
HR | Croatia |
CU | Cuba |
CY | Cyprus |
CZ | Czech Republic |
DK | Denmark |
DJ | Djibouti |
DM | Dominica |
DO | Dominican Republic |
EC | Ecuador |
EG | Egypt |
SV | El Salvador |
GQ | Equatorial Guinea |
ER | Eritrea |
EE | Estonia |
ET | Ethiopia |
FK | Falkland Islands (Islas Malvinas) |
FO | Faroe Islands |
FJ | Fiji |
FI | Finland |
FR | France |
GF | French Guiana |
PF | French Polynesia |
GA | Gabon |
GM | The Gambia |
GE | Georgia |
DE | Germany |
GH | Ghana |
GI | Gibraltar |
GR | Greece |
GL | Greenland |
GD | Grenada |
GP | Guadeloupe |
GU | Guam |
GT | Guatemala |
GN | Guinea |
GW | Guinea-Bissau |
GY | Guyana |
HT | Haiti |
VA | Holy See (Vatican City) |
HN | Honduras |
HU | Hungary |
IS | Iceland |
IN | India |
ID | Indonesia |
IR | Iran |
IQ | Iraq |
IE | Ireland |
IL | Israel |
IT | Italy |
JM | Jamaica |
JP | Japan |
JO | Jordan |
KZ | Kazakhstan |
KE | Kenya |
KI | Kiribati |
KP | North Korea |
KR | South Korea |
KW | Kuwait |
KG | Kyrgyzstan |
LA | Laos |
LV | Latvia |
LB | Lebanon |
LS | Lesotho |
LR | Liberia |
LY | Libya |
LI | Liechtenstein |
LT | Lithuania |
LU | Luxembourg |
MK | North Macedonia |
MG | Madagascar |
MW | Malawi |
MY | Malaysia |
MV | Maldives |
ML | Mali |
MT | Malta |
IM | Isle of Man |
MH | Marshall Islands |
MQ | Martinique |
MR | Mauritania |
MU | Mauritius |
YT | Mayotte |
MX | Mexico |
FM | Federated States of Micronesia |
MD | Moldova |
MC | Monaco |
MN | Mongolia |
MS | Montserrat |
MA | Morocco |
MZ | Mozambique |
MM | Myanmar (Burma) |
NA | Namibia |
NR | Nauru |
NP | Nepal |
NL | Netherlands |
AN | Netherlands Antilles |
NC | New Caledonia |
NZ | New Zealand |
NI | Nicaragua |
NE | Niger |
NG | Nigeria |
NU | Niue |
NF | Norfolk Island |
MP | Northern Mariana Islands |
NO | Norway |
OM | Oman |
PK | Pakistan |
PW | Palau |
PS | Palestinian Territory |
PA | Panama |
PG | Papua New Guinea |
PY | Paraguay |
PE | Peru |
PH | Philippines |
PN | Pitcairn Islands |
PL | Poland |
PT | Portugal |
PR | Puerto Rico |
QA | Qatar |
RE | Reunion |
RO | Romania |
RU | Russia |
RW | Rwanda |
KN | Saint Kitts and Nevis |
LC | Saint Lucia |
PM | Saint Pierre and Miquelon |
VC | Saint Vincent and the Grenadines |
SM | San Marino |
ST | Sao Tome and Principe |
SA | Saudi Arabia |
SN | Senegal |
SC | Seychelles |
SL | Sierra Leone |
SG | Singapore |
SK | Slovakia |
SI | Slovenia |
SB | Solomon Islands |
SO | Somalia |
ZA | South Africa |
ES | Spain |
LK | Sri Lanka |
SD | Sudan |
SR | Suriname |
SJ | Svalbard |
SZ | Eswatini |
SE | Sweden |
CH | Switzerland |
SY | Syria |
TW | Taiwan |
TJ | Tajikistan |
TZ | Tanzania |
TH | Thailand |
TG | Togo |
TK | Tokelau |
TO | Tonga |
TT | Trinidad and Tobago |
TN | Tunisia |
TR | Turkey |
TM | Turkmenistan |
TC | Turks and Caicos Islands |
TV | Tuvalu |
UG | Uganda |
UA | Ukraine |
AE | United Arab Emirates |
GB | United Kingdom |
US | United States |
UM | United States Minor Outlying Islands |
UY | Uruguay |
UZ | Uzbekistan |
VU | Vanuatu |
VE | Venezuela |
VN | Vietnam |
VI | Virgin Islands |
WF | Wallis and Futuna |
EH | Western Sahara |
WS | Western Samoa |
YE | Yemen |
CD | Democratic Republic of the Congo |
ZM | Zambia |
ZW | Zimbabwe |
HK | Hong Kong |
MO | Macau |
AQ | Antarctica |
BV | Bouvet Island |
IO | British Indian Ocean Territory |
TF | French Southern and Antarctic Lands |
HM | Heard Island and McDonald Islands |
SH | Saint Helena |
GS | South Georgia and the South Sandwich Islands |
GG | Guernsey |
RS | Serbia |
BL | Saint Barthélemy |
ME | Montenegro |
JE | Jersey |
CW | Curaçao |
MF | Saint Martin |
SX | Sint Maarten |
TL | Timor-Leste |
SS | South Sudan |
AX | Åland Islands |
BQ | Bonaire |
XK | Republic of Kosovo |
Valid Language Codes
Code | Name | Localized Name |
---|---|---|
aa | Afar | Afaraf |
ab | Abkhaz | аҧсуа бызшәа |
ae | Avestan | avesta |
af | Afrikaans | Afrikaans |
ak | Akan | Akan |
am | Amharic | አማርኛ |
an | Aragonese | aragonés |
ar | Arabic | اللغة العربية |
as | Assamese | অসমীয়া |
av | Avaric | авар мацӀ |
ay | Aymara | aymar aru |
az | Azerbaijani | azərbaycan dili |
ba | Bashkir | башҡорт теле |
be | Belarusian | беларуская мова |
bg | Bulgarian | български език |
bh | Bihari | भोजपुरी |
bi | Bislama | Bislama |
bm | Bambara | bamanankan |
bn | Bengali | বাংলা |
bo | Tibetan | བོད་ཡིག |
br | Breton | brezhoneg |
bs | Bosnian | bosanski jezik |
ca | Catalan | Català |
ce | Chechen | нохчийн мотт |
ch | Chamorro | Chamoru |
co | Corsican | corsu |
cr | Cree | ᓀᐦᐃᔭᐍᐏᐣ |
cs | Czech | čeština |
cu | Old Church Slavonic | ѩзыкъ словѣньскъ |
cv | Chuvash | чӑваш чӗлхи |
cy | Welsh | Cymraeg |
da | Danish | dansk |
de | German | Deutsch |
dv | Divehi | Dhivehi |
dz | Dzongkha | རྫོང་ཁ |
ee | Ewe | Eʋegbe |
el | Greek | Ελληνικά |
en | English | English |
eo | Esperanto | Esperanto |
es | Spanish | Español |
et | Estonian | eesti |
eu | Basque | euskara |
fa | Persian | فارسی |
ff | Fula | Fulfulde |
fi | Finnish | suomi |
fj | Fijian | Vakaviti |
fo | Faroese | føroyskt |
fr | French | Français |
fy | Western Frisian | Frysk |
ga | Irish | Gaeilge |
gd | Scottish Gaelic | Gàidhlig |
gl | Galician | galego |
gn | Guaraní | Avañe’ẽ |
gu | Gujarati | ગુજરાતી |
gv | Manx | Gaelg |
ha | Hausa | هَوُسَ |
he | Hebrew | עברית |
hi | Hindi | हिन्दी |
ho | Hiri Motu | Hiri Motu |
hr | Croatian | Hrvatski |
ht | Haitian | Kreyòl ayisyen |
hu | Hungarian | magyar |
hy | Armenian | Հայերեն |
hz | Herero | Otjiherero |
ia | Interlingua | Interlingua |
id | Indonesian | Bahasa Indonesia |
ie | Interlingue | Interlingue |
ig | Igbo | Asụsụ Igbo |
ii | Nuosu | ꆈꌠ꒿ Nuosuhxop |
ik | Inupiaq | Iñupiaq |
io | Ido | Ido |
is | Icelandic | Íslenska |
it | Italian | Italiano |
iu | Inuktitut | ᐃᓄᒃᑎᑐᑦ |
ja | Japanese | 日本語 |
jv | Javanese | basa Jawa |
ka | Georgian | ქართული |
kg | Kongo | Kikongo |
ki | Kikuyu | Gĩkũyũ |
kj | Kwanyama | Kuanyama |
kk | Kazakh | қазақ тілі |
kl | Kalaallisut | kalaallisut |
km | Khmer | ខេមរភាសា |
kn | Kannada | ಕನ್ನಡ |
ko | Korean | 한국어 |
kr | Kanuri | Kanuri |
ks | Kashmiri | कश्मीरी |
ku | Kurdish | Kurdî |
kv | Komi | коми кыв |
kw | Cornish | Kernewek |
ky | Kyrgyz | Кыргызча |
la | Latin | latine |
lb | Luxembourgish | Lëtzebuergesch |
lg | Ganda | Luganda |
li | Limburgish | Limburgs |
ln | Lingala | Lingála |
lo | Lao | ພາສາ |
lt | Lithuanian | lietuvių kalba |
lu | Luba-Katanga | Tshiluba |
lv | Latvian | latviešu valoda |
mg | Malagasy | fiteny malagasy |
mh | Marshallese | Kajin M̧ajeļ |
mi | Māori | te reo Māori |
mk | Macedonian | македонски јазик |
ml | Malayalam | മലയാളം |
mn | Mongolian | Монгол хэл |
mr | Marathi | मराठी |
ms | Malay | Bahasa Malaysia |
mt | Maltese | Malti |
my | Burmese | ဗမာစာ |
na | Nauru | Ekakairũ Naoero |
nb | Norwegian Bokmål | Norsk bokmål |
nd | Northern Ndebele | isiNdebele |
ne | Nepali | नेपाली |
ng | Ndonga | Owambo |
nl | Dutch | Nederlands |
nn | Norwegian Nynorsk | Norsk nynorsk |
no | Norwegian | Norsk |
nr | Southern Ndebele | isiNdebele |
nv | Navajo | Diné bizaad |
ny | Chichewa | chiCheŵa |
oc | Occitan | occitan |
oj | Ojibwe | ᐊᓂᔑᓈᐯᒧᐎᓐ |
om | Oromo | Afaan Oromoo |
or | Oriya | ଓଡ଼ିଆ |
os | Ossetian | ирон æвзаг |
pa | Panjabi | ਪੰਜਾਬੀ |
pi | Pāli | पाऴि |
pl | Polish | język polski |
ps | Pashto | پښتو |
pt | Portuguese | Português |
qu | Quechua | Runa Simi |
rm | Romansh | rumantsch grischun |
rn | Kirundi | Ikirundi |
ro | Romanian | Română |
ru | Russian | Русский |
rw | Kinyarwanda | Ikinyarwanda |
sa | Sanskrit | संस्कृतम् |
sc | Sardinian | sardu |
sd | Sindhi | सिन्धी |
se | Northern Sami | Davvisámegiella |
sg | Sango | yângâ tî sängö |
si | Sinhala | සිංහල |
sk | Slovak | slovenčina |
sl | Slovenian | slovenski jezik |
sm | Samoan | gagana fa’a Samoa |
sn | Shona | chiShona |
so | Somali | Soomaaliga |
sq | Albanian | Shqip |
sr | Serbian | српски језик |
ss | Swati | SiSwati |
st | Southern Sotho | Sesotho |
su | Sundanese | Basa Sunda |
sv | Swedish | Svenska |
sw | Swahili | Kiswahili |
ta | Tamil | தமிழ் |
te | Telugu | తెలుగు |
tg | Tajik | тоҷикӣ |
th | Thai | ไทย |
ti | Tigrinya | ትግርኛ |
tk | Turkmen | Türkmen |
tl | Tagalog | Wikang Tagalog |
tn | Tswana | Setswana |
to | Tonga | faka Tonga |
tr | Turkish | Türkçe |
ts | Tsonga | Xitsonga |
tt | Tatar | татар теле |
tw | Twi | Twi |
ty | Tahitian | Reo Tahiti |
ug | Uyghur | ئۇيغۇرچە |
uk | Ukrainian | Українська |
ur | Urdu | اردو |
uz | Uzbek | Ўзбек |
ve | Venda | Tshivenḓa |
vi | Vietnamese | Tiếng Việt |
vo | Volapük | Volapük |
wa | Walloon | walon |
wo | Wolof | Wollof |
xh | Xhosa | isiXhosa |
yi | Yiddish | ייִדיש |
yo | Yoruba | Yorùbá |
za | Zhuang | Saɯ cueŋƅ |
zh | Chinese | 中文 |
zu | Zulu | isiZulu |