Skip to main content

Official typed Python SDK for the Jinkō clinical trial simulation platform (jinko.ai) — script models, trials, virtual populations, and results.

Project description

Jinkō Python SDK

Jinkō is a complete solution for clinical trial simulation and protocol design optimization, developed by Nova In Silico. It combines mechanistic ("white-box") modeling, virtual populations, in-silico trials, and analytics in a collaborative platform used by modelers, scientists, and trial managers to accelerate drug development and de-risk clinical decisions.

The Jinkō Python SDK is the official, typed Python client for the Jinkō API. It lets you script, automate, and integrate Jinkō workflows — from browsing project items and editing computational models, to running trials on virtual populations and retrieving simulation results — directly from Python.

Main features

  • QSP model development — Create, edit, and version quantitative systems pharmacology models with typed APIs for parameters, events, reactions, and compartments
  • Virtual population management — Work with patient populations and generators for trial simulation at scale
  • In-silico trial orchestration — Design protocols, run simulations, and analyze outcomes to optimize trial designs before clinical execution
  • Collaborative project navigation — Browse folders, search across model libraries, and manage versioned assets in team environments
  • Results analytics — Extract simulation summaries, tabular data, and visualizations with optional pandas integration
  • Programmatic workflows — Automate repetitive modeling tasks, batch operations, and integrate with existing R&D pipelines

Learn more about the platform at doc.jinko.ai.

Installation

pip install jinko-sdk

Requirements:

  • Python 3.12+
  • A Jinko API key
  • A target Jinko project id

Setup and authentication

The SDK reads configuration from environment variables by default:

export JINKO_API_KEY="..."
export JINKO_PROJECT_ID="..."
export JINKO_BASE_URL="https://api.jinko.ai"  # optional

For local developer convenience, keep secrets in a local .env and load them in your shell (for example with direnv allow if you use direnv).

You can also pass values explicitly:

from jinko import JinkoClient

client = JinkoClient(
    api_key="...",
    project_id="...",
    base_url="https://api.jinko.ai",  # optional
    timeout=30.0,
)

Validate credentials early:

check = client.auth.check()
print(check.status, check.user_email)

Quickstart

from jinko import JinkoClient

client = JinkoClient()

model = client.get_model("cm-...")
print(model.name)

trial = client.create_trial(model, name=f"{model.name} - smoke run")
trial.run()
trial.wait_until_completed(timeout=600, poll_interval=5.0)

summary = trial.results.summary()
print(summary.get("status"))

Core concepts

  • JinkoClient: primary user-facing entrypoint
  • types.ProjectItem: common typed metadata envelope (sid, type, core_id, folders, version, ...)
  • Domain wrappers (Model, Trial, Vpop, ...): typed objects with behavior methods
  • Page[T]: paginated list() result (items, next_cursor, has_next)
  • iter(): auto-paginated iterator for bulk traversal

Most user-facing resources expose a client-level pattern:

  • list_<types>(...) -> Page[T]
  • iter_<types>(...) -> Iterator[T]
  • get_<type>(sid, revision=None)
  • create_<type>(...) or create_raw_<type>(...) when available
  • delete(sid)
  • .versions on bound typed items

Public client surface

Project-wide services

  • client.folders: folder CRUD and folder-tree exploration
  • client.raw: authenticated low-level HTTP escape hatch
  • client.delete(sid): delete any project item by SID

Typed project item methods

  • client.list_models(...), client.iter_models(...), client.get_model(...)
  • client.list_trials(...), client.iter_trials(...), client.get_trial(...)
  • client.list_calibrations(...), client.iter_calibrations(...), client.get_calibration(...)
  • client.list_output_sets(...), client.iter_output_sets(...), client.get_output_set(...)
  • client.list_protocol_designs(...), client.iter_protocol_designs(...), client.get_protocol_design(...)
  • client.list_scorings(...), client.iter_scorings(...), client.get_scoring(...)
  • client.list_vpops(...), client.iter_vpops(...), client.get_vpop(...)
  • client.list_vpop_generators(...), client.iter_vpop_generators(...), client.get_vpop_generator(...)
  • client.list_assertions(...), client.iter_assertions(...), client.get_assertion(...)
  • client.list_data_tables(...), client.iter_data_tables(...), client.get_data_table(...)
  • client.list_documents(...), client.iter_documents(...), client.get_document(...)
  • client.list_raw_files(...), client.iter_raw_files(...), client.get_raw_file(...)
  • client.list_references(...), client.iter_references(...), client.get_reference(...)
  • client.list_subsampling_designs(...), client.iter_subsampling_designs(...), client.get_subsampling_design(...)
  • client.list_trial_visualizations(...), client.iter_trial_visualizations(...), client.get_trial_visualization(...)

Exploring a project

1) Start broad: project-items search

models_page = client.list_models(name="PK")
for model in models_page:
    print(model.sid, model.type, model.name)

Use iter() when you want all pages:

all_trial_sids = [trial.sid for trial in client.iter_trials()]

2) Explore folders and folder trees

print(client.folders.tree())

root = client.folders.get_by_name("Program A", exact_match_only=True)
if root:
    print(client.folders.tree(root=root, max_depth=2, include_project_items=True))

You can also list by folder:

modeling_folder = client.folders.get_by_name("Modeling", exact_match_only=True)
if modeling_folder:
    models = client.list_models(folder=modeling_folder, limit=25)

3) Fetch typed resources and inspect content

model = client.get_model("cm-...")
content = model.content()  # typed model interface
print(content.model.modelName)

Versioned resources

By default, get(sid) reads the latest revision.

latest = client.get_model("cm-...")
older = client.get_model("cm-...", revision=3)

List version metadata and label snapshots:

versions_page = latest.versions.list(only_labeled=False, first=20)
for version in versions_page:
    print(version.revision, version.label, version.is_latest)

latest.versions.label(revision=3, label="baseline")
latest.versions.unlabel(revision=3)

Models and components

Model.components is the ergonomic typed API for editing components.

model = client.get_model("cm-...")

# Typed read
k_clearance = model.components.get_parameter("k_clearance")

# Immediate multi-field update in one API call
k_clearance.update(formula="CL / V", unit="L/h", description="retuned clearance")

# Typed create (immediate commit)
model.components.create_parameter(id="k_abs", formula=1.2, unit="1/h")

# Event updates are provided as a component->value mapping
model.components.create_event(
    id="dose_start",
    updates={"Dose": 100},
    condition_trigger="t >= 0",
)

# Reaction stoichiometry is also a mapping
model.components.create_mass_action_reaction(
    id="binding",
    reactants={"Drug": 1, "Target": 1},
    products={"Complex": 1},
    k_plus="kon",
    k_minus="koff",
)

When changing several components, batch commits avoid one-request-per-change:

with model.components.batch(version_name="retune") as batch:
    batch.edit_parameter("k_clearance").set_formula("CL2 / V")
    batch.create_parameter(id="k_new", formula=0.8, unit="1/h")

with model.components.batch(version_name="event and kinetics") as batch:
    batch.edit_event("dose_start").set_updates({"Dose": 120})
    batch.edit_reaction("binding").set_general_kinetics(
        reactants={"Drug": 1, "Target": 1},
        products={"Complex": 1},
        rate="kon * Drug * Target - koff * Complex",
    )

You can still use raw OpenAPI component payloads if needed (not recommended, as these types are subject to changes):

from jinko.openapi_types import Parameter, Specifics6

model = model._edit_components_api(
    add=Parameter(id="k_raw", specifics=Specifics6(formula=2.0, unit="1/h")),
    version_name="raw component payload",
)

Trials and result retrieval

Create a trial from typed resources, run it, then consume results:

model = client.get_model("cm-...")
vpop = client.get_vpop("vp-...")
protocol = client.get_protocol_design("pd-...")

trial = client.create_trial(
    model,
    vpop=vpop,
    protocol=protocol,
    name="model-vpop-protocol run",
)
trial.run()
trial.wait_until_completed(timeout=1800)

summary = trial.results.summary()
scalars_csv = trial.results.scalars(["AUC", "Cmax"])  # TabularDownload

# Optional convenience if pandas is installed in your environment
df = scalars_csv.to_dataframe()
print(df.head())

Pagination patterns

list() returns a Page[T] with cursor metadata:

page = client.list_models(limit=20)
print(len(page), page.has_next, page.next_cursor)

if page.has_next:
    next_page = client.list_models(limit=20, after=page.next_cursor)

Use iter() when you want to consume all pages seamlessly.

Raw API escape hatch

Use client.raw.request(...) when an endpoint is not yet wrapped by a typed service. It reuses SDK authentication, project scoping, transport, and error handling.

payload = client.raw.request(
    "GET",
    "/app/v1/auth/check",
)
print(payload)

Example with params + JSON body:

result = client.raw.request(
    "POST",
    "/app/v1/project-item",
    params={"first": 10},
    json_body={"text": "tumor", "type": "Trial"},
    headers={"X-My-Header": "value"},
)

Use this path carefully: prefer typed services whenever available to keep stronger type safety and compatibility.

Error handling

The SDK raises typed exceptions from jinko, including:

  • ConfigurationError
  • AuthenticationError, AuthorizationError
  • NotFoundError, ValidationError, ConflictError
  • RateLimitError, ServerError, TransportError

Minimal example:

from jinko import JinkoClient, NotFoundError

client = JinkoClient()

try:
    client.get_model("cm-does-not-exist")
except NotFoundError as exc:
    print(f"Model not found: {exc}")

Development tests

See tests/README.md.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Contact & references

For support or inquiries, please contact us at oss@jinko.ai

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jinko_sdk-1.1.0.tar.gz (101.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jinko_sdk-1.1.0-py3-none-any.whl (135.5 kB view details)

Uploaded Python 3

File details

Details for the file jinko_sdk-1.1.0.tar.gz.

File metadata

  • Download URL: jinko_sdk-1.1.0.tar.gz
  • Upload date:
  • Size: 101.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Alpine Linux","version":"3.23.4","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for jinko_sdk-1.1.0.tar.gz
Algorithm Hash digest
SHA256 c522d115c113b3deb7757748bca3ef8a9b67d948959891ed63022494d60ff13d
MD5 d8137789a3394b115e42b71318952805
BLAKE2b-256 936612d7e98e82faf571e92df1fd51b1b6838f47dda2796670f7811726f7da72

See more details on using hashes here.

File details

Details for the file jinko_sdk-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: jinko_sdk-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 135.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Alpine Linux","version":"3.23.4","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for jinko_sdk-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 418ffc1d73873e031c6d831412ff203b4ecd5be49616cd9559f2df013bb6d335
MD5 d3ee79976f9e09e33215ae886708ceba
BLAKE2b-256 b726ee414ba32892c96493bccd30e2d37a82ecb490253647c3e247fba1e68ef4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page