Kernel API

Programmatic access to your studies, datasets, and analysis pipelines.

Overview

The Kernel API is a REST API for listing the datasets in a study and running analysis pipelines against them. All requests are made over HTTPS to a single host:

https://api.kernel.com

Access to this API requires a subscription plan that includes Kernel Cloud API Access. If your organization is not on such a plan, API requests will be rejected. Contact Kernel to upgrade your plan.

Requests and responses are JSON. Every route requires an API key (see Authentication). Throughout this document, a dataset corresponds to a single recording session, and timestamps are floating-point seconds since the Unix epoch (UTC).

Authentication

An Organization Owner can generate an API key on the Organization Settings page in the Kernel portal. Treat this key like a password — anyone with it has access to your organization's studies and datasets.

The key looks like api_key_production.<uuid> — copy it exactly as shown on the settings page. Pass it in the Authorization header on every request:

http
Authorization: api_key_production.5e9c1e0a-1b23-4c56-8def-0123456789ab

In the examples below, set your key once and reuse it:

python
import requests

api_key = "YOUR_API_KEY"
base_url = "https://api.kernel.com"
headers = {"Authorization": api_key}

A missing or invalid API key returns 401 Unauthorized. A key only grants access to studies owned by the organization it was issued for.

Requests & errors

A few rules apply across every route:

  • All IDs (study_id, dataset_id, pipeline_batch_id) must be valid UUIDs. A malformed ID returns 400 Bad Request.
  • pipeline_name must be one of the available pipelines. An unknown name returns 404 Not Found.
  • Request bodies accept only the documented fields. Any unexpected field returns 400 Bad Request.
  • pipeline_params is an object of boolean flags. For batch runs, unknown flag names or non-boolean values are rejected with 400 Bad Request.
  • A dataset that does not belong to the given study returns 400 Bad Request; a missing study or dataset returns 404 Not Found.

List studies

Return all studies in an organization.

GET /api/v1/organization/{org_id}/studies

Path parameters

NameTypeDescription
org_idstring (uuid) requiredYour organization's UUID. The API key must belong to this organization.

Response

FieldTypeDescription
studiesarrayAll studies in the organization. Each item contains the fields below.
studies[].idstring (uuid)Study UUID. Use this as study_id in the other routes.
studies[].namestringHuman-readable study name.
studies[].is_completebooleanWhether the study has been marked complete.
json
{
  "studies": [
    {
      "id": "96a09389-1079-49f5-9df0-fdbbf357d07d",
      "name": "Resting-state fNIRS cohort",
      "is_complete": false
    },
    {
      "id": "b4c1f0e2-8a77-4e39-9c15-2d6a1f4e7b8c",
      "name": "Pilot study 2025",
      "is_complete": true
    }
  ]
}

Example

python
import requests

api_key = "YOUR_API_KEY"
org_id = "d2f4a1b8-6c3e-4a90-8b17-5e9c0a2f3d61"

response = requests.get(
    f"https://api.kernel.com/api/v1/organization/{org_id}/studies",
    headers={"Authorization": api_key},
)
response.raise_for_status()

studies = response.json()["studies"]
open_studies = [study for study in studies if not study["is_complete"]]
print(open_studies)

List datasets

Return all dataset IDs and metadata for a study, newest first.

GET /api/v1/study/{study_id}/datasets

Path parameters

NameTypeDescription
study_idstring (uuid) requiredThe study's UUID.

Response

FieldTypeDescription
datasetsarrayList of datasets, newest first. Each item contains the fields below.
datasets[].idstring (uuid)Dataset UUID. Use this as dataset_id in the pipeline routes.
datasets[].metaobjectFree-form metadata. Possible keys include name, description, experiment, number, invalid.
datasets[].participantobjectParticipant info: id (uuid), participant_id (human-readable, e.g. S014), created_at (float), active (bool), pending (bool), status (string).
datasets[].created_datefloatCreation time, seconds since epoch.
datasets[].started_atfloatRecording start, seconds since epoch.
datasets[].stopped_atfloatRecording stop, seconds since epoch.
json
{
  "datasets": [
    {
      "id": "85f2c077-2d11-4fb5-acaf-5149db0922c6",
      "meta": {
        "name": "Session 2",
        "description": "Resting-state, eyes closed",
        "experiment": "resting_state",
        "number": "2"
      },
      "participant": {
        "id": "4ae9d4da-b6cb-4fb0-8636-8c6b44d0e808",
        "participant_id": "S014",
        "created_at": 1749556800.0,
        "active": true,
        "pending": false,
        "status": "enrolled"
      },
      "created_date": 1750939200.0,
      "started_at": 1750939230.0,
      "stopped_at": 1750939830.0
    }
  ]
}

Example

python
import requests

api_key = "YOUR_API_KEY"
study_id = "96a09389-1079-49f5-9df0-fdbbf357d07d"

response = requests.get(
    f"https://api.kernel.com/api/v1/study/{study_id}/datasets",
    headers={"Authorization": api_key},
)
response.raise_for_status()

datasets = response.json()["datasets"]
dataset_ids = [dataset["id"] for dataset in datasets]
print(dataset_ids)

Run a pipeline

Start an analysis pipeline for a single dataset.

POST /api/v1/study/{study_id}/dataset/{dataset_id}/pipeline/{pipeline_name}

Path parameters

NameTypeDescription
study_idstring (uuid) requiredThe study's UUID.
dataset_idstring (uuid) requiredThe dataset's UUID.
pipeline_namestring requiredOne of the available pipelines listed below.

Available pipelines

  • analysis_eeg
  • analysis_nirs_epoched
  • analysis_nirs_glm
  • analysis_task
  • qc_eeg
  • qc_nirs_basic
  • qc_nirs
  • qc_syncbox
  • reconstruction
  • pipeline_snirf_gated
  • snirf_hb_moments
  • snirf_moments

Request body (optional)

FieldTypeDescription
pipeline_paramsobject optionalBoolean flags that adjust the pipeline. Supported flags depend on the pipeline; the analysis pipelines accept the flags shown below.
json
{
  "pipeline_params": {
    "skip_channel_pruning": true,
    "skip_artifact_correction": true,
    "skip_global_short_channel_regression": true
  }
}

Response

FieldTypeDescription
job_idstring (uuid)UUID of the pipeline run. Use it to poll status.
json
{
  "job_id": "32ce0eae-8d39-4ff4-ab59-249e034ebb8d"
}

Example

python
import requests

api_key = "YOUR_API_KEY"
study_id = "96a09389-1079-49f5-9df0-fdbbf357d07d"
dataset_id = "85f2c077-2d11-4fb5-acaf-5149db0922c6"
pipeline_name = "analysis_nirs_glm"

response = requests.post(
    f"https://api.kernel.com/api/v1/study/{study_id}/dataset/{dataset_id}/pipeline/{pipeline_name}",
    headers={"Authorization": api_key},
    json={  # optional
        "pipeline_params": {
            "skip_channel_pruning": True,
            "skip_artifact_correction": True,
            "skip_global_short_channel_regression": True,
        }
    },
)
response.raise_for_status()

job_id = response.json()["job_id"]
print(job_id)

Get pipeline status

Get the status of the most recent pipeline run for a dataset, plus signed download URLs for the results once the run has succeeded.

GET /api/v1/study/{study_id}/dataset/{dataset_id}/pipeline/{pipeline_name}/status

Path parameters

NameTypeDescription
study_idstring (uuid) requiredThe study's UUID.
dataset_idstring (uuid) requiredThe dataset's UUID.
pipeline_namestring requiredThe pipeline that was run.

Response

FieldTypeDescription
job_idstring (uuid)UUID of the most recent run.
statusstringJob status. One of the values below.
pipeline_paramsobjectFlags the run was started with (present only if any were set).
signed_urlsobjectPresent only when status is SUCCEEDED. Contains batch_job_id, execution_id, mime_type, urls (asset path → signed download URL), and sizes (asset path → bytes).

SUBMITTEDPENDINGRUNNABLESTARTINGRUNNINGSUCCEEDEDFAILED

json
{
  "job_id": "32ce0eae-8d39-4ff4-ab59-249e034ebb8d",
  "status": "SUCCEEDED",
  "pipeline_params": { "skip_channel_pruning": true },
  "signed_urls": {
    "batch_job_id": "7a1f5478-9cd1-4b35-916c-20372a86eb03",
    "execution_id": "5083918b-5ced-49da-b208-7edffa0f9566",
    "mime_type": "application/vnd.kernel.download",
    "urls": {
      "moments/HbO_moments.snirf": "https://kernel-assets.s3.amazonaws.com/...&X-Amz-Signature=...",
      "qc/qc_report.html": "https://kernel-assets.s3.amazonaws.com/...&X-Amz-Signature=..."
    },
    "sizes": {
      "moments/HbO_moments.snirf": 8734512.0,
      "qc/qc_report.html": 45213.0
    }
  }
}

Example

python
import requests

api_key = "YOUR_API_KEY"
study_id = "96a09389-1079-49f5-9df0-fdbbf357d07d"
dataset_id = "85f2c077-2d11-4fb5-acaf-5149db0922c6"
pipeline_name = "analysis_nirs_glm"

response = requests.get(
    f"https://api.kernel.com/api/v1/study/{study_id}/dataset/{dataset_id}/pipeline/{pipeline_name}/status",
    headers={"Authorization": api_key},
)
response.raise_for_status()

status = response.json()
print(status["status"])
if status["status"] == "SUCCEEDED":
    for asset_path, url in status["signed_urls"]["urls"].items():
        print(asset_path, url)

Run a batch pipeline

Start the same pipeline for many datasets in a study with a single request. Returns a batch ID you can poll for aggregate progress.

POST /api/v1/study/{study_id}/pipeline/{pipeline_name}/batch

Path parameters

NameTypeDescription
study_idstring (uuid) requiredThe study's UUID.
pipeline_namestring requiredOne of the available pipelines.

Request body

FieldTypeDescription
dataset_idsarray (uuid) requiredDataset UUIDs to process. Must be non-empty; maximum 500 per request.
pipeline_paramsobject optionalBoolean flags applied to every dataset. Unknown flag names or non-boolean values are rejected.
json
{
  "dataset_ids": [
    "85f2c077-2d11-4fb5-acaf-5149db0922c6",
    "168d306d-2334-4340-a4d7-c6171c6cc21c",
    "7ab6093b-9639-4de4-8950-0569351aa0c8"
  ],
  "pipeline_params": {
    "skip_channel_pruning": true,
    "skip_artifact_correction": true,
    "skip_global_short_channel_regression": true
  }
}

Response

FieldTypeDescription
pipeline_batch_idstring (uuid)UUID for tracking the batch run.
json
{
  "pipeline_batch_id": "2425e5de-b37e-4f9e-8305-62433e862a9c"
}

Example

python
import requests

api_key = "YOUR_API_KEY"
study_id = "96a09389-1079-49f5-9df0-fdbbf357d07d"
pipeline_name = "analysis_nirs_glm"

response = requests.post(
    f"https://api.kernel.com/api/v1/study/{study_id}/pipeline/{pipeline_name}/batch",
    headers={"Authorization": api_key},
    json={
        "dataset_ids": [
            "85f2c077-2d11-4fb5-acaf-5149db0922c6",
            "168d306d-2334-4340-a4d7-c6171c6cc21c",
            "7ab6093b-9639-4de4-8950-0569351aa0c8",
        ],
        "pipeline_params": {  # optional
            "skip_channel_pruning": True,
            "skip_artifact_correction": True,
            "skip_global_short_channel_regression": True,
        },
    },
)
response.raise_for_status()

pipeline_batch_id = response.json()["pipeline_batch_id"]
print(pipeline_batch_id)

Get batch pipeline status

Get aggregate progress for a batch run. Once the batch is complete, the response includes a signed URL to a JSON results file with per-dataset statuses and download links.

GET /api/v1/study/{study_id}/pipeline/batch/{pipeline_batch_id}/status

Path parameters

NameTypeDescription
study_idstring (uuid) requiredThe study's UUID.
pipeline_batch_idstring (uuid) requiredThe batch ID returned from the run-batch route.

Response

FieldTypeDescription
pipeline_batch_idstring (uuid)The batch UUID.
completebooleanWhether all jobs have finished.
statsobjectCounts: total, not_analyzable, analyzable, succeeded, failed, pending.
pipeline_paramsobjectFlags the batch was started with (present only if any were set).
results_urlstringPresent only when complete is true. Signed URL to the batch results JSON (expires after 1 week).
json — in progress
{
  "pipeline_batch_id": "2425e5de-b37e-4f9e-8305-62433e862a9c",
  "complete": false,
  "stats": {
    "total": 3,
    "not_analyzable": 0,
    "analyzable": 3,
    "succeeded": 1,
    "failed": 0,
    "pending": 2
  }
}
json — complete
{
  "pipeline_batch_id": "2425e5de-b37e-4f9e-8305-62433e862a9c",
  "complete": true,
  "stats": {
    "total": 3,
    "not_analyzable": 0,
    "analyzable": 3,
    "succeeded": 2,
    "failed": 1,
    "pending": 0
  },
  "results_url": "https://kernel-assets.s3.amazonaws.com/...&X-Amz-Signature=..."
}

Example

python
import time
import requests

api_key = "YOUR_API_KEY"
study_id = "96a09389-1079-49f5-9df0-fdbbf357d07d"
pipeline_batch_id = "2425e5de-b37e-4f9e-8305-62433e862a9c"

while True:
    response = requests.get(
        f"https://api.kernel.com/api/v1/study/{study_id}/pipeline/batch/{pipeline_batch_id}/status",
        headers={"Authorization": api_key},
    )
    response.raise_for_status()
    status = response.json()
    print(status["stats"])

    if status["complete"]:
        print("Results:", status.get("results_url"))
        break
    time.sleep(30)