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
Optional integrations are installed as extras:
pip install "jinko-sdk[pandas]" # DataFrame helpers
pip install "jinko-sdk[pdf]" # Native PDF quote extraction
Requirements:
- Python 3.11+
- 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,
)
When a credential is neither passed explicitly nor provided through the environment, the SDK prompts for it:
client = JinkoClient()
Validate credentials early:
check = client.auth_check()
print(check.status, check.api_key.role)
Command-line tools
The SDK ships a set of jinko.cli command-line tools for common workflows —
tagging model components, creating protocol designs or Vpops, inspecting
project items, and more. Each previews its changes by default; pass --apply
after reviewing the plan.
python -m jinko.cli.tag_model_components --model-sid cm-... --tag clearance=i::vpop
python -m jinko.cli.create_vpop_from_csv --csv patients.csv --apply
python -m jinko.cli.inspect_protocol_design --protocol-design-sid pd-... --summary
Each tool is also installed as a console script (for example
jinko-tag-model-components) if its directory is on PATH.
Quickstart
from jinko import JinkoClient
client = JinkoClient()
model = client.get_model("cm-...")
print(model.name)
model.rename("Retuned PK model")
model.components.get_parameter("k_clearance").set_formula("CL / V")
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- Client direct methods:
client.get_model(...),client.list_trials(...),client.create_trial(...), ... - Domain wrappers (
Model,Trial,Vpop, ...): typed objects with behavior methods (for examplemodel.rename(...),trial.run()) types.ProjectItemMetadata: common typed metadata envelope (sid,type,core_id, folders, version, ...)Page[T]: paginatedlist()result (items,next_cursor,has_next)iter(): auto-paginated iterator for bulk traversal
Most user-facing resources follow this pattern:
list_<types>(...) -> Page[T]iter_<types>(...) -> Iterator[T]get_<type>(sid, revision=None)create_<type>(...)orcreate_raw_<type>(...)when availabledelete(sid)- rich object methods on returned items (
.versions,rename,set_description,run,wait_until_completed, ...)
The intended SDK usage is:
- enter through
client.<direct_method>(...) - continue through the typed object returned by that method
- use object-level services only when explicitly exposed (for example
model.components)
Folder handling follows a single-folder public interface:
- public filters and create methods accept
folder=with either aFolderobject or folder id string - project-item wrappers expose
.folderfor the common single-folder case .foldersremains available for full API compatibility when an existing item belongs to multiple folders- use
move_to_folder(folder)as the public folder mutator to place an item in one folder, andmove_to_folder(None)to clear folder assignments
Public client surface
Project-wide services
client.folders: folder CRUD and folder-tree explorationclient.raw_request(...): authenticated low-level HTTP escape hatchclient.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_simple_output_sets(...),client.iter_simple_output_sets(...),client.get_simple_output_set(...)client.list_protocol_designs(...),client.iter_protocol_designs(...),client.get_protocol_design(...)client.list_advanced_output_sets(...),client.iter_advanced_output_sets(...),client.get_advanced_output_set(...)client.list_vpops(...),client.iter_vpops(...),client.get_vpop(...)client.list_vpop_designs(...),client.iter_vpop_designs(...),client.get_vpop_design(...)client.list_extracts(...),client.iter_extracts(...),client.get_extract(...)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.folder_tree())
root = client.get_folder_by_name("Program A", exact_match_only=True)
if root:
print(root.tree(max_depth=2, include_project_items=True))
reports = root.find_child("Reports", exact_match_only=True)
children = root.children()
tree_data = root.tree_dict(include_project_items=False)
tree_nodes = root.tree_nodes(include_project_items=False)
For a project-wide structured forest:
tree_nodes = client.folder_tree_nodes()
tree_data = client.folder_tree_dict()
You can also list by folder:
modeling_folder = client.get_folder_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)
folder = model.folder
all_api_folders = model.folders
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="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="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",
)
For unsupported modeling endpoints, use client.raw_request(...) rather than private object internals.
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 for uncovered routes. Prefer typed SDK methods when available.
Error handling
The SDK raises typed exceptions from jinko, including:
ConfigurationErrorAuthenticationError,AuthorizationErrorNotFoundError,ValidationError,ConflictErrorRateLimitError,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
From the repository root, run just test-sdk-unit for unit tests, just test-sdk-e2e for live e2e tests, or just test-sdk-all for both. See tests/README.md for live-test setup.
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
Release files for jinko-sdk 1.12.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jinko_sdk-1.12.1.tar.gz | 467.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jinko_sdk-1.12.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / jinko_sdk-1.12.1.tar.gz
| Download URL | jinko_sdk-1.12.1.tar.gz |
|---|---|
| Size | 467.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c4afb01b4e964866a4b9d62e124c165680813fa0ce4c125f1f5a2023ae2c9f52
|
|
BLAKE2b-256 checksum How to use checksums |
db7c678b5c05ea8b92c1e91eafc89a65f15656ae96b1766f6a88946e99fc7b7c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.16 {"installer":{"name":"uv","version":"0.12.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Alpine Linux","version":"3.24.2","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / jinko_sdk-1.12.1-py3-none-any.whl
| Download URL | jinko_sdk-1.12.1-py3-none-any.whl |
|---|---|
| Size | 592.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bab5d783222301b67d26e50d2776128206c6e5f26d1bfaaaae351f21419fc1e8
|
|
BLAKE2b-256 checksum How to use checksums |
a6a0b2dbdf09b6fe4a020be1b4e63e27bb3d3d3380093e5c15438f136c509371
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.16 {"installer":{"name":"uv","version":"0.12.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Alpine Linux","version":"3.24.2","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|