OncoKB reader service: API reference
Research use only. Answers are read from oncokb.org with logged-in web accounts and are not for clinical reporting
without review. Every annotation carries "research_only": true. The terms that apply are in the guide.
This document describes version 4.0.0 with its default backend, wire: the service makes the same JSON calls the
oncokb.org pages make, with a plain HTTP client. There is no browser. The old browser backend still exists as a fallback;
what differs there is listed in Browser backend.
Base URL ($B in the examples) |
https://3-105-9-242.sslip.io, once TLS is on; see the note below |
API key ($K in the examples) |
Ask the service owner |
| Version prefix | /api/v1 |
| Formats | JSON; multipart for uploads; TSV for one report download |
| Try it in a web page | /docs (press Authorize, paste the key) |
| Machine-readable spec | /openapi.json, also committed as docs/openapi.json |
| Which endpoint for which assay | / (the guide) |
TLS. Since 2026-11-10 the server answers on
https://3-105-9-242.sslip.io(plain HTTP redirects). The address is a Lightsail static IP, so it does not change when the instance is stopped and started.
Contents
- Quick start
- Conventions
- Endpoints at a glance
- Annotate one variant
- The annotation response
- Batch
- Sample
- Reference data
- Jobs
- Lab files
- Artifacts
- Operations endpoints
- Accounts and usage
- Error codes
- Warnings
- Limits
- Client examples
- Browser backend
Quick start
export B=https://3-105-9-242.sslip.io
export K=<your key> # ask the service owner
curl -s $B/ready # can it answer?
curl -s -X POST $B/api/v1/annotate \
-H "X-API-Key: $K" -H 'Content-Type: application/json' \
-d '{"gene":"IDH1","alteration":"R132S","tumor_type":"AML"}'
Conventions
Authentication
Send X-API-Key: <key> on every /api/v1/* and /admin/* call. A missing or wrong key gets 401 UNAUTHORIZED.
/health, /ready, /, /reference, /docs and /openapi.json are open. There is one shared key for all callers and
for the admin endpoints; there are no per-user keys. If the service was started without ONCOKB_SVC_API_KEY, no key is
checked at all.
Headers
| Header | Direction | Meaning |
|---|---|---|
X-API-Key |
request | The service key. Required on /api/v1/* and /admin/* |
Content-Type: application/json |
request | For JSON bodies. Uploads use multipart/form-data |
X-Request-ID |
request, optional | Your own id for this call: 1-64 characters from A-Z a-z 0-9 . _ - |
X-Request-ID |
response | Your id if it was acceptable, otherwise a generated 32-character one |
Every answer has an X-Request-ID. The service logs one line per request with that id, the method, the path, the
status and the time taken. The query string is not logged. Quote the id when reporting a problem.
Browsers on other origins can call the API only if the owner listed the origin in ONCOKB_SVC_CORS_ORIGINS. By default
no origin is allowed.
HTTP status
| HTTP | Meaning | Body status |
|---|---|---|
| 200 | An answer, including "OncoKB has nothing on this" | annotated, not_curated, not_found |
| 202 | Job accepted | running |
| 401 | Missing or wrong key | error |
| 404 | No such job, file, gene, account or route | error |
| 405 | Wrong HTTP method | error |
| 409 | Report asked for before the job finished, or the job failed | error |
| 413 | Upload over the limit | error |
| 422 | The request cannot be answered as sent; do not retry unchanged | invalid |
| 500 | Bug in the service | error |
| 503 | oncokb.org could not be read; see errors[].retryable |
error |
A 200 does not mean OncoKB curated the variant. Always read status.
status |
HTTP | Meaning |
|---|---|---|
annotated |
200 | OncoKB has an oncogenicity call for this variant (with germline: a pathogenicity call, or the variant is curated) |
not_curated |
200 | The gene is in OncoKB; OncoKB has no call for this variant ("Unknown Oncogenic Effect") |
not_found |
200 | OncoKB does not annotate the gene, the alteration sits on another transcript, or a genomic change did not map to a protein change |
invalid |
422 | Input rejected, by this service or by OncoKB; see errors[].code |
error |
503 | oncokb.org could not be read, or its answer could not be used; see errors[].retryable |
Error body
Every 4xx and 5xx has the same shape:
{"status": "invalid",
"errors": [{"code": "UNKNOWN_TUMOR_TYPE", "message": "'AMLL' is not an OncoTree code or name", "field": "tumor_type",
"suggestions": ["AML (Acute Myeloid Leukemia)", "TAML (Therapy-Related Acute Myeloid Leukemia)"]}]}
errors[].code is stable; program against it, not against message. Only code is always present: message,
field, retryable, suggestions and hint appear when they apply. An annotation call whose body passed the schema
check also returns client_ref. Errors raised outside annotation (401, 404, 405, 409, 413, and the 422s of the sample,
upload and account endpoints) also carry the older detail field: the same object as errors[0], or a plain string
for an unknown route or a wrong method.
Where an answer comes from
A lookup is answered from the first of these that applies:
- The Cancer Gene List. A gene OncoKB does not annotate is answered locally with
GENE_NOT_ANNOTATED_BY_ONCOKB. Nothing is sent to oncokb.org. The service does this only while it holds oncokb.org's own gene list for the data version in use (cancer_gene_list.currentin/health); otherwise the lookup is sent. - The store. The service keeps the JSON oncokb.org sent for each lookup. A stored answer is reused for as long as
OncoKB's data version is unchanged, and for at most 45 days. Nothing is sent to oncokb.org;
provenance.cachedistrue. - oncokb.org. One HTTP GET on one account.
provenance.cachedisfalseandprovenance.wire_bytessays what it cost.
What is stored is the site's JSON, not the response. Each response is built again on every request, so the same stored
lookup can be returned with a different detail, and a fix to the response builder needs no new download. The store key
is the gene, the alteration, the reference genome and the tumour type: the same variant under another tumour type is
another lookup. Two identical lookups that arrive at the same time share one download.
Measured on 2026-11-10 (OncoKB data v7.7): one lookup is 1.3-49 KB gzip on the wire, 4.6 KB on average over 81 myeloid-panel lookups. A 40-finding solid-tumour sample with tumour types took 668 KB in total (16.5 KB per lookup) and 17.3 s on one account; the same 40 again took 0.07 s and no bytes.
Retrying
Retry only when errors[].retryable is true, with a growing wait (for example 5 s, 20 s, 80 s). Before it answers 503
the service has already made up to 4 attempts: it moves to another account after a 429, a 5xx or a 403, repeats once on
the same account after a failed connection, and logs in again once after a 401. When every account has answered 429 or
5xx (always the case with one account), it waits out the shortest account interval and tries again. An answer over the
size limit and a 400 from oncokb.org are not tried again. A failed download stores nothing, so a retry asks oncokb.org
again.
Endpoints at a glance
| Method | Path | Purpose | Key |
|---|---|---|---|
| POST | /api/v1/annotate |
One variant | yes |
| GET | /api/v1/annotate |
One variant, query string (no genomic input) | yes |
| POST | /api/v1/annotate/batch |
Up to 100 variants, answered inline | yes |
| POST | /api/v1/sample |
All findings of one sample (up to 500), with a summary | yes |
| GET | /api/v1/info |
OncoKB data version in use | yes |
| GET | /api/v1/genes |
The genes OncoKB annotates | yes |
| GET | /api/v1/genes/{symbol} |
One gene, optionally with its curated alterations | yes |
| POST | /api/v1/jobs |
Up to 20,000 variants, in the background | yes |
| GET | /api/v1/jobs/{id} |
Progress; paged results | yes |
| DELETE | /api/v1/jobs/{id} |
Delete a finished job | yes |
| POST | /api/v1/oncomine |
Upload Ion Reporter TSV exports | yes |
| POST | /api/v1/vcf |
Upload a GRCh38 VCF | yes |
| GET | /api/v1/jobs/{id}/report |
File job report, JSON | yes |
| GET | /api/v1/jobs/{id}/report.tsv |
File job report, TSV | yes |
| GET | /api/v1/artifacts/pdf/{name} |
Download a PDF made by the browser backend | yes |
| POST | /admin/cache/purge |
Empty the store | yes |
| GET | /admin/accounts |
The oncokb.org accounts and their state | yes |
| POST | /admin/accounts |
Add or change an account | yes |
| POST | /admin/accounts/reload |
Re-read the accounts file | yes |
| POST | /admin/accounts/{id}/login |
Log an account in now | yes |
| DELETE | /admin/accounts/{id} |
Remove an account | yes |
| GET | /admin/usage |
Requests and bytes per day and account | yes |
| GET | /ready |
Can it read oncokb.org now? (200 / 503) | no |
| GET | /health |
Liveness and full status | no |
| GET | /, /reference, /docs, /openapi.json |
Guide, this reference, Swagger UI, OpenAPI spec | no |
Annotate one variant
POST /api/v1/annotate
Request body
| Field | Type | Default | Meaning |
|---|---|---|---|
gene |
string | none | HGNC symbol, Other Biomarkers, or A::B for a fusion. Required unless genomic_coordinates is sent. A few clinical aliases are mapped (HER2, MLL, C-KIT, C-MET) |
alteration |
string | none | Protein change or named alteration; see Forms of input |
fusion_partner |
string | none | 3' partner when gene is the 5' partner |
copy_number_type |
string | none | Amplification or Deletion (homozygous) |
genomic_coordinates |
object | none | VCF-style position; see Genomic coordinates. Not together with alteration, fusion_partner or copy_number_type |
tumor_type |
string | none | OncoTree code or name (AML, MDS/MPN, Melanoma). Omit for a pan-cancer query; a warning says so |
variant_type |
string | none | snv_indel, fusion, cnv, biomarker or special. Optional check: a value that contradicts the alteration is rejected |
reference_genome |
string | GRCh37 |
GRCh37 or GRCh38 (hg19, b37, hg38 are accepted): the transcript set OncoKB reads a protein change on. Send GRCh38 with protein changes called on MANE Select. Ignored with genomic_coordinates |
germline |
bool | false |
Ask OncoKB's germline annotation (pathogenicity, penetrance, inheritance) instead of the somatic one; see Germline lookups |
client_ref |
string, at most 128 | none | Returned unchanged; use it to match answers to your rows |
options.detail |
string | standard |
summary, standard or full; see Detail levels |
options.force_refresh |
bool | false |
Ignore the stored answer, ask oncokb.org again and store the new answer |
options.generate_pdf |
bool | false |
Browser backend only. The wire backend makes no PDF and adds the warning pdf_not_available:no_browser_in_this_backend |
One of alteration, fusion_partner, copy_number_type or genomic_coordinates is needed, unless gene is written
A::B, which is itself the fusion. One request is one finding: fusion_partner together with an alteration that is
not the fusion itself is rejected with VARIANT_TYPE_CONFLICT; send the fusion and the mutation as two requests.
Unknown fields are rejected. Blank strings count as missing. No field has a clinical default.
detail, force_refresh and generate_pdf may also be sent at the top level; a value under options wins.
Forms of input
| Kind | Example body |
|---|---|
| Protein change | {"gene":"IDH1","alteration":"R132S"} or p.Arg132Ser, c.394C>A:p.Arg132Ser, W288Cfs*12 |
| Named | {"gene":"EGFR","alteration":"Exon 19 in-frame deletions"}, {"gene":"FLT3","alteration":"ITD"} |
| Fusion | {"gene":"BCR","fusion_partner":"ABL1"} or {"gene":"BCR::ABL1"} (5' then 3') |
| Copy number | {"gene":"ERBB2","copy_number_type":"Amplification"} |
| Biomarker | {"gene":"Other Biomarkers","alteration":"TMB-High"} or MSI-High; you apply the threshold |
| Genomic | see below |
A fusion is asked under each partner gene, the 3' partner first; an immunoglobulin partner (IGH, IGK, IGL) is
not asked. The first answer in which OncoKB curates the fusion is returned; failing that, the first annotated one;
failing that, the last one. gene.hugo_symbol names the partner whose answer was returned. query.gene is the partner
asked first, and query.fusion_genes keeps both.
The full normalisation rules (amino-acid forms, named alterations, what is rejected and why) are in the guide.
Genomic coordinates
{"gene": "BRAF", "tumor_type": "MEL",
"genomic_coordinates": {"chromosome": "7", "position": 140753336, "reference": "A", "alternate": "T", "genome_build": "GRCh38"}}
Use this for VCF lines, splice sites, start loss and p.?. It is one lookup: oncokb.org maps the change onto its own
canonical transcript and annotates it in the same answer.
| Field | Type | Meaning |
|---|---|---|
chromosome |
string | 1-22, X, Y, MT; a chr prefix is accepted |
position |
integer, 1 or more | VCF POS, 1-based |
reference, alternate |
string | VCF alleles; one ALT; A/C/G/T only, no symbolic <DEL> |
genome_build |
string | GRCh37 or GRCh38 (hg19, b37, hg38 are accepted); required |
gene, if also given, is a hint and is not sent to oncokb.org. It has two effects. If the hint is a gene OncoKB does
not annotate, the answer is not_found with GENE_NOT_ANNOTATED_BY_ONCOKB and nothing is asked, so send a hint only
when it comes from your own annotation of that position. If OncoKB maps the change to another gene, the answer carries
the warning gene_hint_differs:A->B.
In the response, query.gene and query.alteration hold what OncoKB mapped the change to, query.genomic_change holds
the change as sent to OncoKB (chromosome,start,end,ref,alt and the build), and provenance.resolved_via holds the
oncokb.org genomic-change page for it.
Germline lookups
With germline: true the lookup goes to OncoKB's germline annotation. OncoKB names germline variants by their cDNA
change and matches the name exactly, so:
| Input | What happens |
|---|---|
alteration is a cDNA name, e.g. c.68_69del |
Passed on as it is |
alteration is a protein change |
Normalised and passed on, with the warning germline_lookup_by_protein_change:oncokb_names_germline_variants_by_cdna. It matches only if OncoKB lists the variant under that name |
genomic_coordinates |
OncoKB maps the change itself; query.alteration is the name OncoKB gives it. This is the form that does not depend on naming |
curl -s -X POST $B/api/v1/annotate -H "X-API-Key: $K" -H 'Content-Type: application/json' \
-d '{"gene":"BRCA1","alteration":"c.68_69del","germline":true}'
The response has a germline block.
Query-string form
GET /api/v1/annotate takes the same input as query parameters. It has no genomic_coordinates and no client_ref.
| Parameter | Type | Default |
|---|---|---|
gene, alteration, tumor_type, fusion_partner, copy_number_type, variant_type, reference_genome |
string | none |
germline, generate_pdf, force_refresh |
bool | false |
detail |
string | standard |
curl -s "$B/api/v1/annotate?gene=IDH1&alteration=R132S&tumor_type=AML&detail=summary" -H "X-API-Key: $K"
Status codes
| HTTP | When |
|---|---|
| 200 | annotated, not_curated, not_found |
| 401 | Missing or wrong key |
| 422 | The body fails the schema, the input cannot be normalised, or OncoKB rejected the alteration |
| 503 | oncokb.org could not be read |
Example
Request:
curl -s -X POST $B/api/v1/annotate -H "X-API-Key: $K" -H 'Content-Type: application/json' \
-d '{"gene":"IDH1","alteration":"R132S","tumor_type":"AML","client_ref":"S1-v1"}'
Response, built from oncokb.org's JSON of 2026-11-10 (long texts and lists shortened with ...). This example was
produced against the test stand-in for oncokb.org, which answers at once, hence fetch_ms: 1:
{
"status": "annotated",
"research_only": true,
"warnings": [],
"errors": [],
"provenance": {
"source": "oncokb.org web API (variantAnnotation)",
"page_url": "https://www.oncokb.org/gene/IDH1/somatic/R132S/AML",
"page_title": null,
"oncokb_data_version": "v7.7",
"oncokb_last_data_update": "10/29/2026",
"parser_version": "4.0.0",
"service_version": "4.0.0",
"backend": "wire",
"cached": false,
"retrieved_at": "2026-11-10T09:38:17+00:00",
"cache_age_s": 0,
"wire_bytes": 6623,
"fetch_ms": 1,
"account": "default",
"load_ms": 1,
"cache_stored": true
},
"gene": {
"hugo_symbol": "IDH1",
"gene_summary": "IDH1, a cell metabolism enzyme, is recurrently mutated in various cancer types including acute myelo...",
"gene_type": "ONCOGENE",
"oncogene": true,
"tumor_suppressor": false,
"entrez_gene_id": 3417,
"background": "The IDH1 (isocitrate dehydrogenase 1) protein is an enzyme that catalyzes the oxidative decarboxylat...",
"transcripts": {
"grch37": {"isoform": "ENST00000345146", "refseq": "NM_005896.2"},
"grch38": {"isoform": "ENST00000345146", "refseq": "NM_005896.2"}
}
},
"variant": {
"canonical_alteration": "R132S",
"oncokb_alteration": "R132S",
"variant_summary": "The IDH1 R132S mutation is likely oncogenic.",
"hotspot": true,
"curated_in_oncokb": true,
"vus": false,
"allele_exist": true,
"vue": false,
"consequence": "missense_variant",
"protein_start": 132,
"protein_end": 132,
"last_evidence_update": "07/24/2026",
"match": {"exact_row_present": true, "oncokb_alteration_curated": true, "basis": "exact"}
},
"oncogenicity": {"status": "Likely Oncogenic"},
"mutation_effect": {
"known_effect": "Switch-of-function",
"description": "The IDH1 R132S mutation is located in the catalytic site of the IDH1 protein. This mutation has been...",
"pmids": ["21760534", "29670690", "..."],
"abstracts": []
},
"evidence": {
"highest_sensitive_level": "Level 1",
"highest_resistance_level": null,
"highest_diagnostic_level": "Level Dx2",
"highest_prognostic_level": null,
"highest_fda_level": "Level Fda2",
"oncokb_highest_levels": {"sensitive": "Level 1", "resistance": null, "diagnostic": "Level Dx2",
"prognostic": null, "fda": "Level Fda2"},
"other_tumor_type_levels": [
{"level": "Level 3B", "cancer_type": "Myelodysplastic Syndromes"},
{"level": "Level Fda3", "cancer_type": "Myelodysplastic Syndromes"}
],
"treatments": [
{
"level": "Level 1",
"tier": "standard_care",
"regimen": "Ivosidenib",
"drugs": ["Ivosidenib"],
"matched_alterations": ["R132C", "R132H", "..."],
"match_type": "exact",
"level_associated_cancer_types": ["Acute Myeloid Leukemia"],
"excluded_cancer_types": [],
"in_query_tumor_type": true,
"citation_count": 6,
"pmids": ["29860938", "23393090", "..."],
"abstracts": [
{"abstract": "Dohner et al. Abstract# 7042, ASCO 2022.",
"link": "https://ascopubs.org/doi/abs/10.1200/JCO.2022.40.16_suppl.7042"},
"..."
],
"description": "Ivosidenib is a small molecule inhibitor of mutant IDH1 that is FDA-approved for adult patients with...",
"evidence_id": 26867,
"fda_level": "Level Fda2",
"response": "sensitivity",
"approved_indications": [],
"drugs_detail": [{"name": "Ivosidenib", "ncit_code": "C114383"}]
},
"..."
],
"diagnostic": [
{
"level": "Level Dx2",
"matched_alterations": ["Oncogenic Mutations"],
"match_type": "generic",
"level_associated_cancer_types": ["Acute Myeloid Leukemia"],
"excluded_cancer_types": [],
"in_query_tumor_type": true,
"citation_count": 7,
"pmids": ["22397365", "19657110", "..."],
"abstracts": [],
"description": "This assertion is supported by (PMID: 22417203, 20538800, 22397365, 20097881, 20368543, 19657110, 20...",
"evidence_id": 26814
}
],
"prognostic": [],
"fda": [
{"level": "Level Fda2", "matched_alterations": ["R132S"],
"level_associated_cancer_types": ["Acute Myeloid Leukemia"], "excluded_cancer_types": [], "in_query_tumor_type": true},
{"level": "Level Fda3", "matched_alterations": ["Oncogenic Mutations"],
"level_associated_cancer_types": ["Myelodysplastic Syndromes"], "excluded_cancer_types": [], "in_query_tumor_type": false}
],
"summaries": {
"therapeutic": "The IDH1-targeted inhibitors ivosidenib and olutasidenib are FDA-approved for the treatment of patie...",
"diagnostic": "The presence of an IDH1 R132S mutation supports a diagnosis of acute myeloid leukemia.",
"prognostic": null,
"fda": "Tumor type-specific IDH1 alterations and the corresponding FDA Level of Evidence assigning their cli..."
}
},
"query": {
"gene_input": "IDH1",
"alteration_input": "R132S",
"tumor_type_input": "AML",
"gene": "IDH1",
"alteration": "R132S",
"variant_type": "snv_indel",
"fusion_genes": null,
"oncotree_code": "AML",
"oncotree_name": "Acute Myeloid Leukemia",
"reference_genome": "GRCh37"
},
"artifacts": {"pdf_available": false, "pdf_url": null},
"client_ref": "S1-v1"
}
The annotation response
Which blocks are present
| Situation | Blocks in the body |
|---|---|
annotated, not_curated |
All of them |
not_found with GENE_NOT_IN_ONCOKB or ALTERATION_ON_OTHER_TRANSCRIPT; invalid with ONCOKB_REJECTED_ALTERATION; error with EXTRACTION_FAILED |
All of them. Summaries, oncogenicity and effect are null; the evidence lists are empty |
not_found with GENE_NOT_ANNOTATED_BY_ONCOKB or GENOMIC_CHANGE_NOT_ANNOTATED; every other error |
status, research_only, warnings, errors, provenance, query, artifacts, client_ref |
invalid because this service rejected the input |
status, client_ref, errors |
Top level
| Field | Meaning |
|---|---|
status |
See HTTP status |
research_only |
Always true |
warnings[] |
Strings; see Warnings. They do not change status |
errors[] |
Objects with code and message; see Error codes. Empty for annotated and not_curated |
client_ref |
What you sent, or null |
query
| Field | Meaning |
|---|---|
gene_input, alteration_input, tumor_type_input |
What you sent. With genomic input, gene_input is your hint (an empty string if none) and alteration_input is OncoKB's name for the change, or null |
gene, alteration |
What was asked of OncoKB, after normalisation. For a fusion, alteration is A-B Fusion and gene is the partner asked first (the partner whose entry was used is gene.hugo_symbol). With genomic input, what OncoKB mapped the change to; when it mapped nothing, your hint and an empty string |
variant_type |
snv_indel, fusion, cnv or biomarker |
fusion_genes |
[5' gene, 3' gene] for a fusion, otherwise null |
oncotree_code, oncotree_name |
The tumour type used; null means pan-cancer |
reference_genome |
The build the lookup was made on: GRCh37 or GRCh38 |
genomic_change |
Only with genomic input: {"change": "2,209113112,209113112,C,T", "build": "GRCh37"} |
provenance
| Field | Meaning |
|---|---|
source |
oncokb.org web API (variantAnnotation); oncokb.org web API (variantAnnotation/germline) with germline; OncoKB Cancer Gene List for a gene answered locally; oncokb.org web API on an error |
page_url |
The oncokb.org page a person would open for this lookup, with ?refGenome=GRCh38 for a GRCh38 lookup. The service does not load it. For a genomic change OncoKB could not map: the genomic-change page. null when oncokb.org could not be read and for genes answered locally |
page_title |
Always null on the wire backend |
oncokb_data_version |
The data version in OncoKB's answer, e.g. v7.7 |
oncokb_last_data_update |
Date of that data release, from oncokb.org's /api/v1/info. null until the service has read it |
parser_version, service_version |
The code that built the answer |
backend |
wire or browser |
cached |
true when no request went to oncokb.org for this answer (the store, or the Cancer Gene List) |
cache_age_s |
Seconds since the stored JSON was downloaded; 0 for a fresh download |
retrieved_at |
UTC time this response was built. For a stored answer the download happened cache_age_s earlier |
wire_bytes |
Fresh downloads only: bytes received for this lookup, gzip as sent, plus an estimate of 220 bytes for headers and 5,600 for the handshake when a new connection was opened |
fetch_ms |
Fresh downloads only: milliseconds the HTTP request took |
load_ms |
Same value as fetch_ms; kept for callers written for 3.x |
account |
Fresh downloads only: id of the account that carried the request |
cache_stored |
true on a fresh download: the JSON is now in the store |
shared_with_concurrent_request |
true when this answer reused the download of an identical lookup that was already in flight. fetch_ms and account then describe that one download; wire_bytes is 0, because the bytes are counted on the lookup that downloaded it |
resolved_via |
Only with genomic input: the oncokb.org genomic-change page |
For a fusion asked under two partner genes, wire_bytes, fetch_ms, account and cached describe the lookup whose
answer was returned.
Answers that have a provenance but no gene block (see Which blocks are present) have a
shorter one:
no page_title, oncokb_last_data_update or parser_version, and oncokb_data_version is null unless oncokb.org
answered.
gene
| Field | Meaning |
|---|---|
hugo_symbol |
The gene whose OncoKB entry was read |
gene_summary |
OncoKB's one-paragraph summary |
gene_type |
ONCOGENE, TSG, ONCOGENE_AND_TSG, NEITHER, INSUFFICIENT_EVIDENCE, or null when unknown |
oncogene, tumor_suppressor |
Booleans derived from gene_type; null when gene_type is null |
entrez_gene_id |
NCBI gene id |
background |
OncoKB's long gene text |
transcripts.grch37, transcripts.grch38 |
{isoform, refseq}: OncoKB's canonical Ensembl transcript and RefSeq id per build |
variant
| Field | Meaning |
|---|---|
canonical_alteration |
The alteration as this service normalised it |
oncokb_alteration |
OncoKB's own name for it |
variant_summary |
OncoKB's summary sentence |
hotspot |
OncoKB's hotspot flag |
curated_in_oncokb |
true when OncoKB curates exactly this alteration |
vus |
true when OncoKB lists it as a variant of unknown significance |
allele_exist |
true when OncoKB curates another missense change at the same residue |
vue |
OncoKB's vue flag, passed through unchanged |
consequence |
OncoKB's reading of the change, e.g. missense_variant; null when it gives none |
protein_start, protein_end |
Residue range OncoKB read; null when it gives none |
last_evidence_update |
Date of the latest edit to the evidence used for this answer (MM/DD/YYYY). Not the release date |
alternative |
Only with ALTERATION_ON_OTHER_TRANSCRIPT: {alteration, transcript}, the alteration OncoKB annotates instead |
match.exact_row_present |
true when a treatment, diagnostic or prognostic row has match_type: exact |
match.oncokb_alteration_curated |
Same value as curated_in_oncokb |
match.basis |
exact when the alteration is curated or an exact row is present, generic when the answer rests on group entries only, null unless status is annotated |
oncogenicity, mutation_effect
| Field | Meaning |
|---|---|
oncogenicity.status |
Oncogenic, Likely Oncogenic, Likely Neutral, Inconclusive, Resistance, or Unknown Oncogenic Effect for not_curated. null otherwise, and always null with germline |
mutation_effect.known_effect |
Gain-of-function, Loss-of-function, Switch-of-function, Neutral, Inconclusive or a Likely ... form; null when OncoKB says Unknown |
mutation_effect.description |
OncoKB's text on the biological effect |
mutation_effect.pmids[] |
PubMed ids cited for the effect |
mutation_effect.abstracts[] |
{abstract, link}: conference abstracts cited for the effect |
evidence
| Field | Meaning |
|---|---|
highest_sensitive_level, highest_resistance_level |
Best therapeutic level among the rows with in_query_tumor_type: true |
highest_diagnostic_level, highest_prognostic_level, highest_fda_level |
Same, for those row kinds |
oncokb_highest_levels |
{sensitive, resistance, diagnostic, prognostic, fda}: the highest levels OncoKB itself reports in its answer |
other_tumor_type_levels[] |
{level, cancer_type} for rows outside the query tumour type |
treatments[], diagnostic[], prognostic[], fda[] |
Evidence rows; see below |
summaries.therapeutic, diagnostic, prognostic |
OncoKB's summary texts for the tumour type; null in a pan-cancer query |
summaries.fda |
A fixed sentence explaining the FDA table, when there are FDA rows and a tumour type |
articles[] |
Only with detail=full: {pmid, title, journal, pubDate, authors, reference} for every PubMed article cited by a treatment, diagnostic or prognostic row, sorted by pmid |
In a pan-cancer query (no tumor_type) a row counts as in the query tumour type only when OncoKB wrote it for
All Tumors, All Solid Tumors, All Liquid Tumors or All Pediatric Tumors. The five highest_*_level fields are
therefore usually null; read oncokb_highest_levels and the rows.
Evidence rows
Fields of treatments[], diagnostic[] and prognostic[] rows:
| Field | In | Meaning |
|---|---|---|
level |
all | Level 1, Level 2, Level 3A, Level 3B, Level 4, Level R1, Level R2, Level Dx1-Dx3, Level Px1-Px3 |
matched_alterations[] |
all | The alterations the evidence is written for, limited to those valid on the reference genome asked. In pan-cancer answers a name is followed by the alteration in brackets when the two differ, e.g. Internal Tandem Duplication (572_630ins) |
match_type |
all | exact: the row lists the queried alteration. positional: it lists the residue (V600 for V600E). generic: anything else, usually a group entry such as Oncogenic Mutations, Truncating Mutations or Fusions |
level_associated_cancer_types[] |
all | Tumour types the level is written for |
excluded_cancer_types[] |
all | Tumour types OncoKB excludes from that statement |
in_query_tumor_type |
all | OncoKB's own verdict: true when OncoKB files the evidence under a tumour type it counts as yours. A diagnostic or prognostic row is also true when OncoKB lists it among its implications for your tumour type (an entry filed under a subtype, such as AML with Mutated NPM1 for AML). For pan-cancer queries see above |
citation_count |
all | pmids plus abstracts |
pmids[] |
all | PubMed ids cited by this evidence |
abstracts[] |
all | {abstract, link}: conference abstracts cited by this evidence |
description |
all | OncoKB's text for this evidence |
evidence_id |
all | OncoKB's id of the evidence |
tier |
treatments | standard_care (levels 1, 2, R1) or investigational (3A, 3B, 4, R2) |
regimen, drugs[] |
treatments | The drug combination as one string joined with +, and as a list |
fda_level |
treatments | The FDA level OncoKB assigns to this evidence, e.g. Level Fda2, or null |
response |
treatments | sensitivity or resistance |
approved_indications[] |
treatments | Approved indications as OncoKB lists them; often empty |
drugs_detail[] |
treatments | {name, ncit_code} per drug |
Fields of fda[] rows: level (Level Fda1-Fda3), matched_alterations[] (one name),
level_associated_cancer_types[], excluded_cancer_types[], in_query_tumor_type. There is one row per alteration
and cancer type, with the highest FDA level. FDA rows have no match_type.
Citations and the description of a row come from that row's own evidence. Version 3.2.0 joined them by level and drug, which could mix cancer types.
Order of treatments[]:
- With a tumour type: per drug combination only its highest level is listed. Standard care comes first, then
investigational; each group is sorted by level, then drug name. Rows written for other tumour types are included
with
in_query_tumor_type: false. - Without one: every row, sorted by level, alterations, cancer types, drugs.
Read match_type. A Level 1 reached through a generic row is weaker evidence for your exact variant than the
level alone suggests.
Pass the real diagnosis. The highest_*_level fields cover only the rows for the tumour type you send. When the
diagnosis is not settled, omit tumor_type and read the rows.
germline
Present only when the request had germline: true.
| Field | Meaning |
|---|---|
germline.pathogenicity |
OncoKB's germline pathogenicity call, or null |
germline.penetrance |
OncoKB's penetrance text, or null |
germline.genomic_indicators[] |
{name, description, inheritance_mechanism} |
In a germline answer oncogenicity.status is null, status is annotated when OncoKB gives a pathogenicity call or
curates the variant, and variant.match.basis is exact only when the variant is curated.
artifacts
{"pdf_available": false, "pdf_url": null} on the wire backend, always.
Detail levels
detail |
What you get |
|---|---|
standard (default) |
Everything above except evidence.articles |
full |
standard plus evidence.articles[] |
summary |
standard without the long texts: no description, abstracts, drugs_detail, approved_indications or evidence_id in treatment, diagnostic and prognostic rows; no mutation_effect.description and mutation_effect.abstracts; no gene.background |
summary keeps levels, drugs, cancer types, PubMed ids, gene_summary, variant_summary and evidence.summaries.
For IDH1 R132S in AML the three bodies are about 5 KB (summary), 13 KB (standard) and 17 KB (full) of JSON.
The level changes the response only. It does not change what is downloaded or stored.
Batch
POST /api/v1/annotate/batch
| Field | Type | Meaning |
|---|---|---|
items |
array, 1 to 100 | Each item is an annotate request body |
curl -s -X POST $B/api/v1/annotate/batch -H "X-API-Key: $K" -H 'Content-Type: application/json' \
-d '{"items":[{"gene":"IDH1","alteration":"R132S","tumor_type":"AML","client_ref":"a"},
{"gene":"IDH1","client_ref":"b"},
{"gene":"TTN","alteration":"R100C","client_ref":"c"}]}'
{"counts": {"annotated": 1, "invalid": 1, "not_found": 1},
"results": [{"status": "annotated", "client_ref": "a", "...": "..."},
{"status": "invalid", "client_ref": "b",
"errors": [{"code": "MISSING_ALTERATION", "message": "alteration (or copy_number_type / fusion_partner) is required", "field": "alteration"}]},
{"status": "not_found", "client_ref": "c", "...": "..."}]}
| Field | Meaning |
|---|---|
counts |
Number of results per status |
results[] |
One annotation response per item, in the order sent |
| HTTP | When |
|---|---|
| 200 | The body is valid. Each result has its own status; one bad item never fails the batch |
| 401 | Missing or wrong key |
| 422 | The body fails the schema (INVALID_REQUEST), e.g. more than 100 items |
Items are worked on 64 at a time (ONCOKB_JOB_PARALLEL) and the answer is sent when all are done. For more than 100
variants use a job.
Sample
POST /api/v1/sample annotates every finding of one tumour sample in one call and leads the answer with a summary for
a report.
Request body
| Field | Type | Default | Meaning |
|---|---|---|---|
sample_id |
string, at most 128 | none | Echoed back; never sent to oncokb.org |
tumor_type |
string | none | OncoTree code or name, used for every finding. Omit for pan-cancer |
assay |
string, at most 64 | none | Free label, echoed back |
variants |
array | [] |
Findings; see below |
biomarkers.tmb_high |
bool | none | true: also annotate TMB-High |
biomarkers.msi_high |
bool | none | true: also annotate MSI-High |
options |
object | defaults | detail, force_refresh, generate_pdf as for annotate; applied to every finding. Accepted under options only: at the top level of a sample they are rejected |
Each entry of variants:
| Field | Type | Default | Meaning |
|---|---|---|---|
gene |
string | none | HGNC symbol; A::B for a fusion |
alteration, fusion_partner, copy_number_type, genomic_coordinates |
as for annotate | none | Send one. Two events in one gene (a fusion and a resistance mutation) are two entries |
reference_genome |
string | GRCh37 |
As for annotate |
germline |
bool | false |
As for annotate |
vaf |
number | none | Carried into findings[].vaf unchanged; not sent to oncokb.org |
client_ref |
string, at most 128 | position in variants as a string ("0", "1"...) |
Echoed back |
An entry has no tumor_type, variant_type or options of its own; sending one is rejected with INVALID_REQUEST.
A sample holds 1 to 500 findings, variants and biomarkers together. An empty sample gets 422 EMPTY_SAMPLE; more than
500 gets 422 SAMPLE_TOO_LARGE. An unknown tumor_type gets 422 UNKNOWN_TUMOR_TYPE for the whole sample, before
anything is looked up.
Response
| Field | Meaning |
|---|---|
sample_id, assay |
As sent |
tumor_type |
{input, oncotree_code, oncotree_name}, as resolved for the first finding |
research_only |
Always true |
counts |
Number of findings per status |
summary |
See below |
findings[] |
One short row per finding, in the order sent (variants, then TMB-High, then MSI-High) |
results[] |
The full annotation response of each finding, in the same order |
provenance.service_version |
Version of this service |
provenance.items |
Number of findings |
provenance.answered_from_store |
Findings whose answer needed no request to oncokb.org |
provenance.wire_bytes |
Sum of the findings' provenance.wire_bytes |
provenance.oncokb_data_version |
First data version found among the results |
findings[] rows:
| Field | Meaning |
|---|---|
index |
Position in results[] |
client_ref |
As sent, or the default; TMB-High and MSI-High for the biomarkers |
finding |
Gene and alteration as asked of OncoKB, e.g. IDH1 R132S. For a finding rejected as input: its client_ref |
status |
The finding's annotation status |
oncogenicity, mutation_effect, hotspot |
From the annotation |
pathogenicity |
From the germline block, when the finding was asked with germline |
highest_sensitive_level, highest_resistance_level, highest_diagnostic_level, highest_prognostic_level, highest_fda_level |
From the annotation's evidence |
vaf |
As sent |
errors[] |
Error codes only |
summary:
| Field | Meaning |
|---|---|
actionable_findings[] |
The findings rows that have a sensitive or resistance level in the sample's tumour type, best level first |
oncogenic_findings[] |
Names of the findings that are Oncogenic, Likely Oncogenic or Resistance |
therapies_in_tumor_type[] |
Sensitivity rows in the tumour type, best level first, then by drug name |
resistance_in_tumor_type[] |
Resistance rows (Level R1, R2) in the tumour type |
therapies_in_other_tumor_types[] |
Sensitivity rows written for other tumour types |
resistance_in_other_tumor_types[] |
Resistance rows written for other tumour types |
diagnostic[], prognostic[] |
{level, finding, cancer_types, pmids} for rows in the tumour type |
not_read[] |
The findings rows with status error or invalid: these were not annotated |
Each therapy or resistance row is {regimen, level, response, fda_level, finding, matched_alterations, cancer_types,
pmids}; response is sensitivity or resistance. A drug that appears for two findings is listed once per finding.
Resistance evidence is never listed among the therapies. Without a tumor_type nearly every row lands in the two
..._other_tumor_types lists.
| HTTP | When |
|---|---|
| 200 | The sample was processed. One bad finding never fails the sample; read summary.not_read |
| 401 | Missing or wrong key |
| 422 | EMPTY_SAMPLE, SAMPLE_TOO_LARGE, or the body fails the schema (INVALID_REQUEST) |
Example
curl -s -X POST $B/api/v1/sample -H "X-API-Key: $K" -H 'Content-Type: application/json' -d '{
"sample_id": "S-001", "assay": "myeloid panel", "tumor_type": "AML", "options": {"detail": "summary"},
"variants": [{"gene": "IDH1", "alteration": "R132S", "vaf": 0.31, "client_ref": "v1"},
{"gene": "FLT3", "alteration": "ITD"},
{"gene": "TP53", "alteration": "H368N", "vaf": 0.4},
{"gene": "TTN", "alteration": "R100C"}]}'
Response (lists shortened with ...). In this run IDH1 R132S was already in the store and TTN was answered from the
Cancer Gene List, hence answered_from_store: 2:
{
"sample_id": "S-001",
"assay": "myeloid panel",
"tumor_type": {"input": "AML", "oncotree_code": "AML", "oncotree_name": "Acute Myeloid Leukemia"},
"research_only": true,
"counts": {"annotated": 2, "not_curated": 1, "not_found": 1},
"summary": {
"actionable_findings": [
{"index": 1, "client_ref": "1", "finding": "FLT3 ITD", "status": "annotated", "oncogenicity": "Oncogenic",
"mutation_effect": "Gain-of-function", "hotspot": false, "pathogenicity": null,
"highest_sensitive_level": "Level 1", "highest_resistance_level": null, "highest_diagnostic_level": "Level Dx2",
"highest_prognostic_level": "Level Px1", "highest_fda_level": "Level Fda2", "vaf": null, "errors": []},
{"index": 0, "client_ref": "v1", "finding": "IDH1 R132S", "status": "annotated", "oncogenicity": "Likely Oncogenic",
"mutation_effect": "Switch-of-function", "hotspot": true, "pathogenicity": null,
"highest_sensitive_level": "Level 1", "highest_resistance_level": null, "highest_diagnostic_level": "Level Dx2",
"highest_prognostic_level": null, "highest_fda_level": "Level Fda2", "vaf": 0.31, "errors": []}
],
"oncogenic_findings": ["IDH1 R132S", "FLT3 ITD"],
"therapies_in_tumor_type": [
{"regimen": "Gilteritinib", "level": "Level 1", "response": "sensitivity", "fda_level": "Level Fda2", "finding": "FLT3 ITD",
"matched_alterations": ["D835", "Internal Tandem Duplication", "..."],
"cancer_types": ["Acute Myeloid Leukemia"], "pmids": ["31665578", "28645776", "..."]},
{"regimen": "Ivosidenib", "level": "Level 1", "response": "sensitivity", "fda_level": "Level Fda2", "finding": "IDH1 R132S",
"matched_alterations": ["R132C", "R132H", "..."],
"cancer_types": ["Acute Myeloid Leukemia"], "pmids": ["29860938", "23393090", "..."]},
"..."
],
"resistance_in_tumor_type": [],
"therapies_in_other_tumor_types": [
{"regimen": "Olutasidenib + Azacitidine Regimen", "level": "Level 3B", "response": "sensitivity", "fda_level": "Level Fda3",
"finding": "IDH1 R132S",
"matched_alterations": ["Oncogenic Mutations"], "cancer_types": ["Myelodysplastic Syndromes"], "pmids": ["40457853"]}
],
"resistance_in_other_tumor_types": [],
"diagnostic": [
{"level": "Level Dx2", "finding": "IDH1 R132S", "cancer_types": ["Acute Myeloid Leukemia"], "pmids": ["22397365", "..."]},
{"level": "Level Dx2", "finding": "FLT3 ITD", "cancer_types": ["Acute Myeloid Leukemia"], "pmids": ["18450602", "..."]}
],
"prognostic": [
{"level": "Level Px1", "finding": "FLT3 ITD", "cancer_types": ["Acute Myeloid Leukemia"], "pmids": ["15746041", "..."]}
],
"not_read": []
},
"findings": ["... 4 rows, same fields as actionable_findings ..."],
"results": ["... 4 annotation responses ..."],
"provenance": {"service_version": "4.0.0", "items": 4, "answered_from_store": 2, "wire_bytes": 12456,
"oncokb_data_version": "v7.7"}
}
Reference data
GET /api/v1/info
The OncoKB data version the stored answers belong to. No parameters.
{"service_version": "4.0.0", "parser_version": "4.0.0", "backend": "wire",
"oncokb": {"data_version": "v7.7", "data_date": "10/29/2026", "app_version": "v6.12.0",
"oncotree_version": "oncotree_2025_10_03", "checked_at": "2026-11-10T09:38:17+00:00"},
"cancer_gene_list": {"date": "10/29/2026 (v7.7)", "source": "oncokb.org cancerGeneList (live)", "annotated_genes": 1040,
"current": true}}
| Field | Meaning |
|---|---|
service_version, parser_version, backend |
This service |
oncokb.data_version, oncokb.data_date |
OncoKB's current data release, as last read from oncokb.org |
oncokb.app_version, oncokb.oncotree_version |
oncokb.org's software version and its OncoTree version |
oncokb.checked_at |
UTC time the service last read oncokb.org's /api/v1/info. It reads it every 3 hours, and at once when an answer carries another data version |
cancer_gene_list.date |
Release the gene list belongs to |
cancer_gene_list.source |
oncokb.org cancerGeneList (live), or bundled snapshot until the live list has been read |
cancer_gene_list.annotated_genes |
Number of genes OncoKB annotates |
cancer_gene_list.current |
true when the live list belongs to the data version in use. Only then are genes OncoKB does not annotate answered locally |
Status codes: 200, 401.
GET /api/v1/genes
OncoKB's Cancer Gene List. Nothing is downloaded per call.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
annotated_only |
bool | true |
false also lists the genes that are on the list but that OncoKB does not annotate |
curl -s "$B/api/v1/genes" -H "X-API-Key: $K"
{"source": "oncokb.org cancerGeneList (live)", "list_date": "10/29/2026 (v7.7)", "count": 1040,
"genes": [{"hugo_symbol": "A1CF", "entrez_gene_id": 29974, "gene_type": "ONCOGENE", "oncokb_annotated": true,
"grch37_isoform": "ENST00000373993", "grch38_isoform": "ENST00000373993", "msk_impact": false, "msk_heme": false},
"..."]}
| Field | Meaning |
|---|---|
source, list_date, count |
Where the list comes from, its release, number of rows |
genes[].hugo_symbol, entrez_gene_id, gene_type |
The gene |
genes[].oncokb_annotated |
true when OncoKB annotates the gene |
genes[].grch37_isoform, grch38_isoform |
OncoKB's canonical transcript per build |
genes[].msk_impact, msk_heme |
Membership of those two panels |
Rows are sorted by symbol. Until the live list has been read, the rows come from the bundled snapshot and hold
hugo_symbol and oncokb_annotated only.
Status codes: 200, 401.
GET /api/v1/genes/{symbol}
One gene. The symbol is not case-sensitive, and an alias OncoKB lists resolves to its gene.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
variants |
bool | false |
Also return every alteration OncoKB curates for the gene |
force_refresh |
bool | false |
With variants: ignore the stored tables and download them again |
curl -s "$B/api/v1/genes/BRAF?variants=true" -H "X-API-Key: $K"
{"hugo_symbol": "BRAF", "entrez_gene_id": 673, "gene_type": "ONCOGENE", "oncokb_annotated": true, "aliases": ["BRAF1"],
"transcripts": {"grch37": {"isoform": "ENST00000288602", "refseq": "NM_004333.4"},
"grch38": {"isoform": "ENST00000646891", "refseq": "NM_004333.4"}},
"in_panels": {"msk_impact": true, "msk_heme": true, "foundation_one": true, "foundation_heme": true,
"vogelstein": true, "sanger_cgc": true},
"provenance": {"source": "oncokb.org cancerGeneList (live)", "oncokb_data_version": "v7.7",
"page_url": "https://www.oncokb.org/gene/BRAF", "cached": false, "wire_bytes": 52307},
"annotated_alterations": [
{"alteration": "K601N", "oncogenicity": "Oncogenic", "mutation_effect": "Gain-of-function",
"pmids": ["26732095", "..."], "description": "The class II BRAF K601N mutation is located in the kinase domain..."},
"..."],
"clinical_alterations": [
{"alteration": "V600", "level": "Level 3A", "fda_level": "Level Fda3", "drugs": ["Vemurafenib", "Dabrafenib"],
"cancer_types": ["Histiocytosis"], "excluded_cancer_types": [], "pmids": ["31213430", "..."],
"description": "Vemurafenib is an orally available, small molecule RAF-targeted inhibitor..."},
"..."]}
| Field | Meaning |
|---|---|
hugo_symbol, entrez_gene_id, gene_type, oncokb_annotated, aliases[] |
The Cancer Gene List record |
transcripts |
{isoform, refseq} for grch37 and grch38 |
in_panels |
Booleans: msk_impact, msk_heme, foundation_one, foundation_heme, vogelstein, sanger_cgc |
provenance.source, oncokb_data_version, page_url |
Where the record comes from, and the gene's oncokb.org page |
provenance.cached, provenance.wire_bytes |
Only with variants: whether both tables came from the store, and the bytes downloaded |
annotated_alterations[] |
Only with variants: {alteration, oncogenicity, mutation_effect, pmids, description} |
clinical_alterations[] |
Only with variants: {alteration, level, fda_level, drugs, cancer_types, excluded_cancer_types, pmids, description} |
The record costs no download. With variants=true the two tables are two downloads per gene and OncoKB data version;
after that they come from the store. For a gene OncoKB does not annotate, the tables are left out.
This endpoint needs the live Cancer Gene List. Until the service has read it (a few seconds after a start, and again
after an OncoKB data release), every symbol answers 503 GENE_LIST_NOT_LOADED, which is retryable.
| HTTP | When |
|---|---|
| 200 | The gene is on the list |
| 401 | Missing or wrong key |
| 404 | GENE_NOT_IN_CANCER_GENE_LIST; on the browser backend NOT_AVAILABLE_IN_BROWSER_BACKEND |
| 503 | GENE_LIST_NOT_LOADED (the gene list has not been read yet), or, with variants, oncokb.org could not be read; body {"status": "error", "errors": [...]} |
Jobs
Submit a variant list: POST /api/v1/jobs
| Field | Type | Meaning |
|---|---|---|
items |
array, 1 to 20,000 | Each item is an annotate request body |
Answers at once with HTTP 202:
{"job_id": "8f2c1a0b9d3e4f56", "status": "running", "total": 300, "poll": "/api/v1/jobs/8f2c1a0b9d3e4f56"}
Status codes: 202, 401, 422 (INVALID_REQUEST).
Progress and results: GET /api/v1/jobs/{id}
| Parameter | Type | Default | Meaning |
|---|---|---|---|
offset |
integer | 0 |
First result to return |
limit |
integer | 0 |
Number of results to return, at most 500. With 0, no results are returned |
offset and limit apply to variant jobs only.
| Field | Meaning |
|---|---|
id, kind |
kind is variants, oncomine or vcf |
status |
running, done, failed |
total, done |
Lookups in the job and lookups finished. For file jobs total grows as the file is worked through |
counts |
Finished lookups per annotation status |
submitted_at, finished_at |
UTC |
offset, results[] |
Variant jobs, with limit above 0: annotation responses in submission order. Items not done yet are null |
params |
File jobs: what the job was started with. Oncomine: files (the number of files) and tumor_type. VCF: mode, tumor_type, max_pop_af, min_vaf, min_depth |
log[] |
File jobs: progress lines |
error |
File jobs: why the job failed, otherwise null |
report, tsv |
File jobs, when done: paths of the two report downloads |
curl -s "$B/api/v1/jobs/8f2c1a0b9d3e4f56" -H "X-API-Key: $K" # progress
curl -s "$B/api/v1/jobs/8f2c1a0b9d3e4f56?offset=0&limit=500" -H "X-API-Key: $K" # first page of results
{"id": "8f2c1a0b9d3e4f56", "kind": "variants", "status": "done", "total": 2, "done": 2, "counts": {"annotated": 2},
"submitted_at": "2026-11-10T09:40:02+00:00", "finished_at": "2026-11-10T09:40:04+00:00"}
Poll every few seconds. A restart of the service marks running jobs failed; nothing resumes on its own, so submit the
job again. For file jobs error then reads "service restarted during the job; submit it again".
Status codes: 200, 401, 404 (NOT_FOUND).
Delete: DELETE /api/v1/jobs/{id}
Removes a finished job and its results and answers {"deleted": "<id>"}. An unknown or still running job gets 404
NOT_FOUND_OR_RUNNING. Delete file jobs when you have the report, because they hold patient-derived variants. Finished
jobs older than 30 days are removed when the next job is submitted.
Status codes: 200, 401, 404.
Lab files
Both uploads return a job at once (HTTP 202):
{"job_id": "5b1e77c2a9d04f13", "status": "running", "poll": "/api/v1/jobs/5b1e77c2a9d04f13",
"report": "/api/v1/jobs/5b1e77c2a9d04f13/report", "tsv": "/api/v1/jobs/5b1e77c2a9d04f13/report.tsv"}
Poll poll until status is done or failed, then fetch the report. The uploaded file is deleted when the job
ends. See the guide for what the filters do and why.
Thermo Ion Reporter: POST /api/v1/oncomine
Multipart form:
| Field | Type | Default | Meaning |
|---|---|---|---|
files |
file, repeatable | required | .tsv or .txt exports: Oncomine Myeloid, Comprehensive Plus, Precision |
tumor_type |
string | none | OncoTree code or name, applied to all files. Omit for pan-cancer |
curl -s -X POST $B/api/v1/oncomine -H "X-API-Key: $K" \
-F "files=@011026_1_selected_variants.tsv" -F "files=@011026_2_selected_variants.tsv" -F "tumor_type=AML"
| HTTP | When |
|---|---|
| 202 | Job accepted |
| 401 | Missing or wrong key |
| 413 | FILE_TOO_LARGE: a file is over the upload limit |
| 422 | NOT_A_TSV, UNKNOWN_TUMOR_TYPE, or a missing form field (INVALID_REQUEST) |
A full (unselected) export is filtered the way Ion Reporter does (thermo_like_v1); a lab-selected export is taken as
it is. A protein change that OncoKB rejects on its own transcript is asked again by its hg19 position; the row then
carries the warning oncomine_transcript_differs:A->B.
Illumina VCF: POST /api/v1/vcf
Multipart form:
| Field | Type | Default | Meaning |
|---|---|---|---|
file |
file | required | VCF or gzipped VCF, GRCh38 (Illumina DRAGEN or similar) |
mode |
string | germline |
germline (constitutional WGS / WES) or somatic (tumour VCF) |
tumor_type |
string | none | OncoTree code or name. Omit for pan-cancer |
sample |
string | none | Name of the sample column to read; required when the VCF has several |
max_pop_af |
number, 0 to 1 | 0.01 |
gnomAD filtering allele frequency at or above which a call is listed but not asked |
include_synonymous |
bool | false |
Also keep synonymous calls, UTR calls and calls whose reference base does not match the transcript |
min_vaf |
number, 0 to 1 | 0.0 |
Drop calls below this allele fraction before any lookup, e.g. 0.05. Calls without an allele fraction are kept |
min_depth |
integer, 0 or more | 0 |
Drop calls below this read depth before any lookup. Calls without a depth are kept |
germline_annotation |
bool | true |
With mode=germline: for constitutional (not mosaic) calls whose somatic lookup came back annotated or not_curated, also ask OncoKB's germline annotation |
curl -s -X POST $B/api/v1/vcf -H "X-API-Key: $K" -F "file=@sample.hard-filtered.vcf.gz" -F "mode=germline"
curl -s -X POST $B/api/v1/vcf -H "X-API-Key: $K" -F "file=@tumour.vcf.gz" -F "mode=somatic" \
-F "tumor_type=NSCLC" -F "min_vaf=0.05" -F "min_depth=50"
| HTTP | When |
|---|---|
| 202 | Job accepted |
| 401 | Missing or wrong key |
| 413 | FILE_TOO_LARGE |
| 422 | INVALID_MODE, UNKNOWN_TUMOR_TYPE, BAD_VCF (not a VCF, no sample column, several samples and no sample, unknown sample, a header that names GRCh37 / hg19), or a bad form field (INVALID_REQUEST) |
What the job does: it keeps calls with FILTER PASS or . in the coding sequence (plus 2 bp of splice site) of
OncoKB-annotated genes (HLA and KIR genes are skipped), works out the consequence on the MANE Select transcript, and
removes common gnomAD v4.1 polymorphisms. SNVs are asked by protein change with reference_genome: GRCh38; indels,
multi-base substitutions and splice sites by genomic coordinates; the two TERT promoter hotspots as
Promoter Mutation. A protein change that OncoKB rejects is asked again by coordinates and gets the warning
mane_transcript_differs_from_oncokb.
The job needs the reference files (MANE v1.5 and the gnomAD v4.1 subset) on the server. Without them the job ends
failed and error names the missing file. The job also ends failed, with nothing annotated, when at least 5
coding SNVs, and more than 5 % of all coding SNVs, do not match the GRCh38 reference base: the file is then not on
GRCh38.
Germline caveat. OncoKB's somatic annotation describes what a variant does in a tumour. On a germline genome it means "would be oncogenic if somatic", not inherited risk. The
germline_*columns hold OncoKB's germline annotation where it has one. Germline classification belongs to ClinVar / ACMG.
Report as JSON: GET /api/v1/jobs/{id}/report
| Parameter | Type | Default | Meaning |
|---|---|---|---|
full |
bool | false |
true keeps each variant's complete annotation response as oncokb_full |
Every report starts with job_id, kind and params.
Oncomine report: samples[] and summary[].
In samples[] |
Meaning |
|---|---|
sample |
Run date + position taken from the file name (011026_3), or sample_N. Patient names are never stored |
assay, run, rows |
From the file |
full_export, filter_applied, filter_version, dropped_by_reason |
What the filter did |
tumor_type |
The OncoTree code used |
variants[] |
label, kind, gene, alteration, fusion_partner, copy_number_type, copy_number, vaf, depth, read_counts, oncomine_class, flags[], oncokb, and oncokb_full with full=true |
biomarkers[] |
TMB / MSI from the file header: biomarker, value, status, oncokb_query, oncokb; unit for TMB, qc for MSI |
oncokb is a short form of the annotation: status, oncokb_gene, oncokb_alteration, oncogenicity,
mutation_effect, hotspot, highest_sensitive, highest_resistance, highest_diagnostic, highest_prognostic,
levels_any_tumor[], errors[] (codes), warnings[], page. levels_any_tumor lists every level found in the
treatment, diagnostic and prognostic rows, whatever the tumour type.
vaf is in percent, as in the export. flags[] can hold possible_germline:vaf=N, in_population_databases:af=N,
low_level_amplification:cn=N, single_copy_loss_not_queried:cn=N, splice_site_via_coordinates and
lab_selected_outside_filter:.... A variant that was kept but not asked (a one-copy loss) has oncokb: null.
summary[] has one row per kept variant with the columns of the TSV below.
VCF report:
| Field | Meaning |
|---|---|
mode, tumor_type |
As used |
vcf_records, pass |
Records read, and records with FILTER PASS or . |
scan_counts |
Counters of the scan: records, pass, one per consequence, promoter, below_vaf_or_depth |
population_filter |
{source, max_filtering_af} |
counts.status, counts.oncogenicity |
Calls per annotation status and per oncogenicity |
calls[] |
One row per coding call; see below |
Fields of calls[]: origin, gene, chrom, pos, ref, alt, mane (the MANE Select transcript),
consequence, protein_mane, genotype, vaf, depth, gnomad_class, gnomad_drop, gnomad_filtering_af,
gnomad_af, gnomad_grpmax, gnomad_nhomalt, gnomad_filter, the short annotation fields listed above for oncokb,
and oncokb_full with full=true. Calls for which the germline annotation was asked also have germline_status,
germline_pathogenicity, germline_penetrance and germline_inheritance[].
| Field | Values |
|---|---|
origin |
somatic in somatic mode. In germline mode mosaic (MOSAIC flag or allele fraction below 0.30) or germline |
consequence |
missense, nonsense, stop_lost, start_lost, frameshift, inframe_indel, mnv, splice_site, promoter; with include_synonymous also synonymous, utr, reference_mismatch |
vaf |
Allele fraction from the VCF, 0 to 1 |
gnomad_class |
absent, rare, common (at or above max_pop_af), common_ba1 (at or above 5 %), not_covered (the gnomAD subset on the server does not cover this gene or position, so no frequency was looked up). The suffix _gnomad_qc_failed marks a site that failed gnomAD's own QC; such a call is never dropped |
status |
The annotation status, or not_queried for a call dropped as a population polymorphism. Such a row has errors: ["POPULATION_POLYMORPHISM"], a marker that exists only in these reports |
Rows are ordered: asked calls before not_queried, mosaic calls first, then by oncogenicity, then by gene.
| HTTP | When |
|---|---|
| 200 | The report |
| 401 | Missing or wrong key |
| 404 | NOT_FOUND: no such job, or it is a variant job |
| 409 | NOT_READY: the job is running or failed. errors[0] also has status and error |
Report as TSV: GET /api/v1/jobs/{id}/report.tsv
text/tab-separated-values, sent as an attachment named <job_id>.tsv. The first line holds the column names. A
list is written with commas between its items. A null or missing value is an empty cell. Status codes are the same as for the JSON report.
Oncomine jobs: one row per kept variant of every sample (biomarkers are in the JSON report only). Columns, in order (tab-separated in the file):
sample assay label vaf status oncokb_gene oncokb_alteration oncogenicity mutation_effect hotspot
highest_sensitive highest_resistance highest_diagnostic highest_prognostic levels_any_tumor errors flags
VCF jobs: one row per coding call, including the calls not asked. Columns, in order (tab-separated in the file):
origin gene chrom pos ref alt consequence protein_mane genotype vaf depth
gnomad_class gnomad_filtering_af gnomad_af gnomad_grpmax gnomad_nhomalt
status oncokb_alteration oncogenicity mutation_effect hotspot highest_sensitive highest_resistance
levels_any_tumor germline_pathogenicity germline_penetrance germline_inheritance errors
curl -s $B/api/v1/jobs/5b1e77c2a9d04f13/report.tsv -H "X-API-Key: $K" -o report.tsv
Artifacts
GET /api/v1/artifacts/pdf/{name}
Downloads a PDF of an OncoKB page (application/pdf). Only the browser backend makes PDFs, when a request has
generate_pdf: true; the response then names the file in artifacts.pdf_url. The wire backend never makes one, so on
the wire backend this endpoint answers 404 NOT_FOUND unless the file is left over from the browser backend.
Status codes: 200, 401, 404.
Operations endpoints
GET /ready
For monitors, load balancers and deploys. 200 when the service has started and at least one account can carry a request; otherwise 503. No key needed.
{"ready": true, "reasons": [], "service_version": "4.0.0", "parser_version": "4.0.0", "backend": "wire"}
reasons entry |
Meaning |
|---|---|
engine_not_started |
The service is still starting, or the start failed; it is tried again every 30 s |
login_not_configured |
No oncokb.org account is configured |
no_usable_account |
Accounts exist, but each is disabled, resting after failures, over its daily limit, without token and password, or without a proxy while ONCOKB_REQUIRE_PROXY is on |
no_proxy_configured |
ONCOKB_REQUIRE_PROXY is on and no account has a proxy |
ready: true says an account is available. It does not prove that oncokb.org answers at this moment, and an account
that has yet to log in counts as available.
GET /health
200 while the process runs, whatever the state of oncokb.org, so it proves liveness only. No key needed. Account names, tokens and proxy credentials never appear here.
Example for one account at default pacing. The numbers are illustrative:
{
"status": "ok", "service_version": "4.0.0", "parser_version": "4.0.0", "backend": "wire", "started": true,
"accounts": {"configured": 1, "usable": 1, "states": {"ready": 1}, "inflight": 0, "capacity": 3, "with_proxy": 0,
"requests_per_s_ceiling": 2.5},
"oncokb": {"data_version": "v7.7", "data_date": "10/29/2026", "app_version": "v6.12.0",
"oncotree_version": "oncotree_2025_10_03", "checked_at": "2026-11-10T09:38:17+00:00"},
"lookups": {"lookups": 16, "from_store": 6, "fetched": 12, "shared": 0, "retries": 0, "logins": 0,
"login_failures": 0, "errors": 0, "prefiltered": 3},
"traffic": {"requests": 13, "bytes_down": 125276, "bytes_up": 3525, "mb_total": 0.129, "connections": 2,
"avg_kb_per_request": 9.6, "downloads_cut_short": 1, "connections_retired": 1,
"mb_not_downloaded_thanks_to_store": 0.04, "since": "2026-11-10T09:38:17+00:00"},
"store": {"data_version": "v7.7", "entries": 12, "disk_bytes": 119172, "hits": 6, "misses": 12, "stale": 0,
"stored": 12, "bytes_saved": 39738,
"by_kind": {"va": {"entries": 9, "disk_bytes": 66585, "wire_bytes": 70764}, "...": {}}},
"require_proxy": false,
"cancer_gene_list": {"date": "10/29/2026 (v7.7)", "source": "oncokb.org cancerGeneList (live)", "annotated_genes": 1040,
"current": true},
"last_error": null,
"login_configured": true, "memory_mb": 54, "memory_high_mb": 2600, "jobs_running": 0
}
| Field | Meaning |
|---|---|
status |
Always ok |
service_version, parser_version, backend |
This service |
started |
true once the accounts and the store are loaded |
accounts.configured, accounts.usable |
Accounts in the pool, and those that can carry a request now |
accounts.states |
Accounts per state: ready, needs_login, cooldown, daily_limit_reached, disabled, no_token_no_password |
accounts.inflight |
Requests to oncokb.org in flight now |
accounts.capacity |
Requests the usable accounts may have in flight at once |
accounts.with_proxy |
Accounts that have a proxy |
accounts.requests_per_s_ceiling |
Request starts per second the usable accounts allow at their current intervals |
oncokb |
As in /api/v1/info. Holds only data_version until the service has read oncokb.org's /api/v1/info |
lookups.lookups |
Annotation lookups handled since start, not counting the ones answered from the Cancer Gene List |
lookups.prefiltered |
Lookups answered from the Cancer Gene List |
lookups.from_store, lookups.fetched |
Site documents taken from the store, and downloaded, for lookups and gene tables. A fusion can use two |
lookups.shared |
Lookups that reused a download already in flight |
lookups.retries |
Failed requests after which the service tried again |
lookups.logins, lookups.login_failures |
Logins made and refused since start |
lookups.errors |
Lookups that failed because oncokb.org could not be read |
traffic.requests |
Every HTTP request sent to oncokb.org since start, logins and token checks included |
traffic.bytes_down, traffic.bytes_up, traffic.mb_total |
Bytes received and sent, with an estimate for headers and TLS handshakes |
traffic.connections |
New connections opened |
traffic.avg_kb_per_request |
bytes_down per request; null before the first request |
traffic.downloads_cut_short |
Downloads dropped part-way: answers for unknown genes, and answers over the size limit |
traffic.connections_retired |
Connections closed because a download on them was cut short |
traffic.mb_not_downloaded_thanks_to_store |
What the answers served from the store had cost when first downloaded |
traffic.proxy_cost_usd_est |
Only when ONCOKB_PROXY_USD_PER_GB is set: mb_total priced at that rate |
traffic.since |
Start of these counters (UTC) |
store.data_version |
The OncoKB data version stored answers are checked against |
store.entries, store.disk_bytes |
Stored documents and their compressed size |
store.hits, misses, stale, stored, bytes_saved |
Since start: reads answered, reads with nothing stored, reads of an out-of-date entry, writes, and download bytes avoided |
store.by_kind |
{entries, disk_bytes, wire_bytes} per kind: va (somatic lookups), va_germline, gene_biological, gene_clinical, catalog (the Cancer Gene List) |
require_proxy |
Whether ONCOKB_REQUIRE_PROXY is on |
cancer_gene_list |
{date, source, annotated_genes, current} as in /api/v1/info |
last_error |
What last went wrong and when, e.g. request failed (throttled) at 2026-11-10T09:54:38+00:00, or null. It names no account and no query; per-account detail is in /admin/accounts |
login_configured |
true when at least one account is configured |
memory_mb |
Memory of the service as systemd accounts it (page cache left out); null where that is not available, e.g. on macOS |
memory_high_mb |
The unit's MemoryHigh; null when none is set |
jobs_running |
Background jobs running now |
POST /admin/cache/purge
Empties the store, the stored Cancer Gene List included, and returns {"purged": <number of entries>}. Every later
lookup is downloaded again. This is not needed after an OncoKB data release: the service notices the new data version
and drops the old answers itself. To refresh one answer, send force_refresh instead.
Status codes: 200, 401.
Accounts and usage
The service reads oncokb.org with one or more web accounts. Each account has its own pacing and, optionally, its own
proxy, and always leaves through that proxy. Passwords, tokens and proxy credentials are write-only: no endpoint
returns them. These endpoints exist on the wire backend only; on the browser backend they answer 404
NOT_AVAILABLE_IN_BROWSER_BACKEND.
GET /admin/accounts
{"summary": {"configured": 1, "usable": 1, "states": {"ready": 1}, "inflight": 0, "capacity": 3, "with_proxy": 0,
"requests_per_s_ceiling": 2.5},
"loaded_at": "2026-11-10T09:38:17+00:00",
"accounts": [
{"id": "default", "username": "u***@example.org", "status": "ready", "enabled": true, "proxy": null,
"has_password": true, "has_token": true, "token_expires_at": "2027-05-04T10:12:44Z",
"token_checked_at": "2026-11-10T09:38:20+00:00", "token_renewal": null,
"max_concurrency": 3, "min_interval_s": 0.4, "interval_s": 0.4, "daily_limit": 0, "requests_today": 13,
"inflight": 0, "cooldown_s": 0, "last_login_at": "2026-11-10T09:38:19+00:00", "last_error": null, "note": "",
"totals": {"requests": 13, "ok": 13, "errors": 0, "throttled": 0, "unauthorized": 0, "logins": 1,
"login_failures": 0, "bytes_down": 125276, "bytes_up": 3525}}]}
The values in this example are illustrative. summary is the accounts block of /health. loaded_at is when the
accounts file was last read. Each row:
| Field | Meaning |
|---|---|
id |
Short name used in logs, provenance.account and /admin/usage. The account from ONCOKB_USERNAME is default. An account added without an id gets acct- plus 8 hex characters |
username |
The login e-mail, masked: first letter, ***, domain |
status |
ready; needs_login (no token yet, has a password); no_token_no_password; disabled; daily_limit_reached; cooldown:login_failed, cooldown:forbidden or cooldown:unreachable |
enabled |
As configured |
proxy |
Scheme, host and port of the proxy, without credentials; null when none |
has_password, has_token |
Whether a password is configured and a token is held |
token_expires_at |
Expiry of the token as oncokb.org reports it; null until it has been read |
token_checked_at |
When the expiry was last read (twice a day) |
token_renewal |
A note when the token runs out within 14 days, otherwise null. The service logs in again when the token has run out |
max_concurrency |
Requests this account may have in flight |
min_interval_s |
Configured gap between two request starts |
interval_s |
The gap in force now. It doubles (to at least 1 s, at most 30 s) on a 429 or 5xx and halves with each success until it is back at min_interval_s |
daily_limit |
Requests per UTC day; 0 means no limit |
requests_today |
Requests on this account since 00:00 UTC, logins and token checks included. This is what daily_limit is compared with. A restart does not reset it |
inflight |
Requests in flight on this account |
cooldown_s |
Seconds of rest left; 0 when not resting |
last_login_at |
Last successful login (UTC) |
last_error |
Last failure on this account, e.g. the reason oncokb.org gave for refusing a login |
note |
Free text from the configuration |
totals |
Counters kept across restarts: requests, ok, errors, throttled, unauthorized, logins, login_failures, bytes_down, bytes_up |
An account rests after a refused login (15 minutes), a 403 (1 hour), or when oncokb.org or the proxy cannot be reached
(1 minute; after a login that cannot connect, or after one lookup fails to connect twice). A login also counts as
refused when oncokb.org accepts the password and then rejects the token it hands out. The rest doubles with each
failure in a row, up to 6 hours. A success resets it, and so does POST /admin/accounts/{id}/login.
Status codes: 200, 401, 404 (browser backend).
POST /admin/accounts
Adds an account, or changes a known one, and rewrites the accounts file. The account changed is the one with this
id; without an id, the one with this username. Fields left out of a change keep their stored value.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
login (query) |
bool | true |
Log in at once a new account, or one whose password changed, so a wrong password shows in the answer |
| Body field | Type | Default | Meaning |
|---|---|---|---|
username |
string | required | The oncokb.org login e-mail |
id |
string | acct- plus 8 hex characters |
1-48 characters: letters, digits, dot, dash, underscore |
password |
string | none | Needed to log in and to renew the token |
proxy |
string | none | http://user:pass@host:port, https://..., socks5://... or socks5h://.... The port is required; #, ?, /, @ and : in the proxy password must be percent-encoded |
token |
string | none | A token copied from the oncokb.org account page, to skip the first login |
enabled |
bool | true for a new account |
false keeps the account configured but unused |
max_concurrency |
integer, 1-32 | 3 | Requests in flight at once |
min_interval_s |
number, 0-60 | 0.4 | Gap between two request starts |
daily_limit |
integer, 0 or more | 0 | Requests per UTC day; 0 means no limit |
note |
string, at most 200 | empty | Free text |
The defaults in this table apply to a new account. A change keeps the account's token and counters. A new password
or a new proxy ends a rest period the old one caused. The default account takes its e-mail and password from the
environment: its other settings can be changed here, its login cannot.
curl -s -X POST $B/admin/accounts -H "X-API-Key: $K" -H 'Content-Type: application/json' \
-d '{"id":"lab2","username":"second@example.org","password":"<password>",
"proxy":"http://<user>:<pass>@proxy.example.net:8000","daily_limit":3000}'
{"account": {"id": "lab2", "username": "s***@example.org", "status": "ready", "proxy": "http://proxy.example.net:8000", "...": "..."},
"logged_in": true}
logged_in is true or false after a login attempt, and null when none was made (login=false, a disabled
account, no password, or the account already holds a token and its password did not change). After a refused login
the account's status is cooldown:login_failed and last_error holds oncokb.org's reason.
| HTTP | When |
|---|---|
| 200 | Saved, whether or not the login worked; read logged_in |
| 401 | Missing or wrong key |
| 404 | Browser backend |
| 422 | INVALID_ACCOUNT: bad id, bad proxy URL, an attempt to change the login of default, or the accounts file cannot be written (nothing changed then). Or the body fails the schema (INVALID_REQUEST) |
POST /admin/accounts/reload
Re-reads the accounts file after it was edited by hand. An account already known (same id, same login) keeps its
token, counters and pacing state. New accounts log in on first use. Accounts no longer in the file are removed. The
default account always takes its e-mail and password from the environment, whatever the file says.
{"accounts": 3, "added": ["lab3"], "removed": [], "enabled": 3, "with_proxy": 2}
Status codes: 200, 401, 404 (browser backend), 422 INVALID_ACCOUNTS_FILE (the file does not parse; nothing changed).
POST /admin/accounts/{id}/login
Ends any rest period of the account and logs it in now, even if it holds a token. Use it after fixing a password or a proxy.
{"logged_in": true, "account": {"id": "lab2", "status": "ready", "...": "..."}}
Status codes: 200 (read logged_in), 401, 404 (NOT_FOUND: no such account; or browser backend).
DELETE /admin/accounts/{id}
Removes the account from the pool and from the accounts file.
{"deleted": "lab2", "persisted": true}
persisted is false when the accounts file could not be written: the account is gone from the running service but
still in the file. The default account cannot be deleted here, because it comes from ONCOKB_USERNAME; take it out
of the environment, or disable it with POST /admin/accounts and {"username": "<its e-mail>", "enabled": false}.
Status codes: 200, 401, 404 (NOT_FOUND; or browser backend), 422 (INVALID_ACCOUNT: the default account).
GET /admin/usage
What was sent to oncokb.org, per UTC day and account.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
days |
integer | 30 |
How many days back. A value outside 1 to 366 is brought into that range |
{"days": 30, "requests": 13, "mb_total": 0.129,
"rows": [{"day": "2026-11-10", "account": "default", "requests": 13, "errors": 0, "bytes_down": 125276, "bytes_up": 3525}]}
| Field | Meaning |
|---|---|
days |
As asked |
requests |
Sum of rows[].requests |
mb_total |
Sum of bytes down and up, in MB |
proxy_cost_usd_est |
Only when ONCOKB_PROXY_USD_PER_GB is set: the total priced at that rate |
rows[] |
{day, account, requests, errors, bytes_down, bytes_up}, newest day first |
The rows count every request the service sent to oncokb.org: lookups, gene tables, the data version and gene list, logins, token checks, and the requests that failed. Bytes include the estimate for headers and handshakes, which is what a proxy billed per GB charges for.
Status codes: 200, 401, 404 (browser backend).
Error codes
A code appears in errors[].code. For a single call the HTTP status is the one in the heading. Inside a batch, a
sample or a job, the call itself is 200 and each item carries its own status and errors.
An HTTP error raised without a code of its own gets HTTP_<status>, e.g. HTTP_400.
Codes marked "browser backend only" are never produced by the default wire backend.
HTTP 401
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
UNAUTHORIZED |
Missing or wrong X-API-Key |
no | Send the key |
HTTP 404
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
NOT_FOUND |
No such job, report, file, account or route | no | Check the id and the path |
NOT_FOUND_OR_RUNNING |
Delete refused: unknown job, or it is still running | after the job ends | Poll the job first |
GENE_NOT_IN_CANCER_GENE_LIST |
/api/v1/genes/{symbol}: the symbol is not on OncoKB's Cancer Gene List, or the live list has not been read yet |
no | Check the symbol; see /api/v1/info for the list in use |
NOT_AVAILABLE_IN_BROWSER_BACKEND |
Browser backend only: gene detail, account and usage endpoints need the wire backend | no | Run the service with ONCOKB_BACKEND=wire |
HTTP 405
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
METHOD_NOT_ALLOWED |
Wrong HTTP method for this path | no | See Endpoints at a glance |
HTTP 409
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
NOT_READY |
The report's job is still running, or it failed; the error also has status and error |
yes, while status is running |
Poll the job until done. If it failed, submit it again |
CONFLICT |
Name given to a 409 raised without a code of its own. No endpoint does that today | no | Report it |
HTTP 413
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
FILE_TOO_LARGE |
An uploaded file is over ONCOKB_MAX_UPLOAD_MB (1,024 MB) |
no | Compress the VCF, or split the upload |
HTTP 422: your input (invalid)
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
INVALID_REQUEST |
Body, parameter or form field fails the schema: unknown field, wrong type, too many items, value not allowed | no | See field and message |
AMBIGUOUS_INPUT |
genomic_coordinates together with alteration, fusion or copy number |
no | Send one |
MISSING_GENE |
No gene | no | Add gene |
MISSING_ALTERATION |
No alteration, fusion partner or copy-number call | no | Add one |
INVALID_GENE |
Not a gene symbol | no | Fix the symbol |
INVALID_PROTEIN_CHANGE |
Cannot be read as a protein change | no | Fix it, e.g. R132S |
NEEDS_PROTEIN_CHANGE |
A DNA-only change such as c.394C>A in a somatic lookup |
no | Send the p. form, or genomic coordinates |
NEEDS_GENOMIC_CHANGE |
p.?: splice site or start loss |
no | Send genomic coordinates |
NOT_PROTEIN_ALTERING |
Synonymous | no | Filter these out first |
AMBIGUOUS_ALTERATION |
Covers several OncoKB entries, e.g. FLT3 TKD, KIT exon 11 |
no | Send the exact change |
NEEDS_CNV_CALL |
gain, loss and similar |
no | Send Amplification or Deletion |
INVALID_CNV |
copy_number_type is neither of those |
no | Fix it |
VARIANT_TYPE_CONFLICT |
variant_type or copy_number_type contradicts the alteration, or fusion_partner came with an alteration that is not the fusion |
no | Remove one; send two events as two requests |
INVALID_VARIANT_TYPE |
Not an allowed variant_type. Through the API the schema check answers first, with INVALID_REQUEST |
no | Fix it |
UNKNOWN_TUMOR_TYPE |
Not an OncoTree code, name or known synonym | no | See suggestions (annotation calls), or omit tumor_type |
UNSUPPORTED_BIOMARKER |
HRD, LOH, mutational signatures, MMR status: OncoKB does not annotate them | no | Do not send |
UNKNOWN_BIOMARKER |
variant_type is biomarker and the alteration is neither TMB-High nor MSI-High |
no | Fix it |
INVALID_GENOMIC_CHANGE |
Bad chromosome, alleles or position | no | Fix it; A/C/G/T only, no symbolic alleles |
MISSING_GENOME_BUILD |
genome_build is not GRCh37 or GRCh38 |
no | Send one of the two |
INVALID_REFERENCE_GENOME |
reference_genome is not GRCh37 or GRCh38 |
no | Send one of the two, or omit it |
EMPTY_SAMPLE |
/api/v1/sample without any variant or biomarker |
no | Send at least one finding |
SAMPLE_TOO_LARGE |
/api/v1/sample with more than 500 findings |
no | Use /api/v1/jobs |
INVALID_MODE |
VCF mode is not germline or somatic |
no | Fix it |
NOT_A_TSV |
Oncomine upload whose name does not end in .tsv or .txt |
no | Upload the Ion Reporter export |
BAD_VCF |
Unreadable VCF, no sample column, sample missing or unknown, or a header that says GRCh37 / hg19 |
no | See message |
INVALID_ACCOUNT |
/admin/accounts: the account cannot be used as sent (bad id, bad proxy URL), the default account's login was to be changed or deleted, or the accounts file cannot be written |
no | See message |
INVALID_ACCOUNTS_FILE |
/admin/accounts/reload: the accounts file does not parse. Nothing changed |
no | Fix the file, reload again |
HTTP 422: OncoKB's verdict (invalid)
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
ONCOKB_REJECTED_ALTERATION |
The change does not fit OncoKB's canonical transcript; message is OncoKB's own text |
no | Your transcript probably differs: send genomic coordinates |
HTTP 200: OncoKB has nothing (not_found)
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
GENE_NOT_ANNOTATED_BY_ONCOKB |
The gene is not one OncoKB annotates, by its Cancer Gene List. Answered without a request | no | Nothing to ask |
GENE_NOT_IN_ONCOKB |
oncokb.org itself says it has no such gene | no | Check the symbol |
ALTERATION_ON_OTHER_TRANSCRIPT |
The alteration is not on OncoKB's canonical transcript; OncoKB annotates the one in suggestions and variant.alternative instead |
no | Ask again with the suggested alteration, or send genomic coordinates |
GENOMIC_CHANGE_NOT_ANNOTATED |
OncoKB did not map the genomic change to a protein change in a gene it knows | no | Usually intronic or intergenic |
ALTERATION_NOT_RECOGNISED |
Browser backend only: the page shows no annotation for the alteration | no | Check the name |
HTTP 500
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
INTERNAL |
Bug in the service. Also the per-item error when one item of a batch, sample or job hit a bug | no | Report it with the X-Request-ID |
HTTP 503: oncokb.org could not be read (error)
| Code | Meaning | Retry? | What to do |
|---|---|---|---|
PAGE_LOAD_FAILED |
The request to oncokb.org failed: timeout, connection or proxy failure, an unexpected HTTP status, an answer that is not JSON, or a shared download that was cancelled | yes | Retry with a growing wait |
THROTTLED |
oncokb.org answered 429 or 5xx on every attempt. The service has widened that account's interval | yes | Retry after a longer wait |
SESSION_INVALID |
oncokb.org rejected the account's token (401) and logging in again did not fix it | yes | Retry; if it persists the owner checks /admin/accounts |
LOGIN_REQUIRED |
The account has no token and could not log in | yes, after the owner acts | The owner checks last_error in /admin/accounts |
ACCOUNT_FORBIDDEN |
oncokb.org answered 403 for the account. The account rests for an hour or more | yes | Retry later; the owner checks the account |
RESPONSE_TOO_LARGE |
The answer was larger than ONCOKB_MAX_ANSWER_KB (400 KB) and the download was dropped |
no | Report the query; the owner can raise the limit |
ONCOKB_BAD_REQUEST |
oncokb.org answered 400 to the lookup | no | Check the input; report it if the input looks right |
EXTRACTION_FAILED |
OncoKB's answer has a value the service does not know. Nothing is guessed | no | Report it |
RESOLVED_NAME_UNUSABLE |
OncoKB's name for a genomic change could not be normalised | no | Report it |
PAGE_NOT_RENDERED |
Browser backend only: the page did not finish showing a result | yes | Retry |
GENE_LOOKUP_FAILED |
Browser backend only: the page says "no information" but the gene lookup did not confirm it | yes | Retry |
GENE_LIST_NOT_LOADED |
GET /api/v1/genes/{symbol} only: OncoKB's Cancer Gene List has not been read yet (it is fetched at start and after each data release), so nothing can be said about any gene |
yes | Retry in a few seconds |
NO_ACCOUNT_AVAILABLE |
No account can carry the request: none configured, none usable (disabled, or without token and password), all resting after failures, all over their daily limit, all busy for 300 s, or ONCOKB_REQUIRE_PROXY is on and no account has a proxy. message says which and, for resting or busy accounts, when to retry |
yes; no when no account is configured | Wait the time message names; the owner checks /ready and /admin/accounts |
Warnings
Warnings do not change status, but read them. Some have a detail after a colon.
Wire backend
| Warning | Meaning |
|---|---|
tumor_type_missing:pan_cancer_query |
No tumor_type was sent, so levels are not tumour-specific |
gene_hint_differs:A->B |
OncoKB mapped the genomic coordinates to gene B, not to your hint A |
fusion_partner_not_in_oncokb:GENE |
OncoKB has no entry for this partner gene of the fusion; the answer comes from the other partner. Not added when the answer returned curates the fusion itself |
alteration_normalised_by_oncokb:NAME |
OncoKB rewrote the protein change to NAME before annotating it |
alteration_not_validated:REASON |
OncoKB did not check the protein change against its transcript; REASON is OncoKB's own, e.g. NO_PROTEIN_SEQUENCE |
tumor_type_not_echoed_by_oncokb |
A tumour type was sent, but OncoKB's answer does not repeat it. Check the levels against page_url |
unrecognised_biological_effect:TEXT |
OncoKB's mutation effect is not one of the known values; known_effect is null |
germline_lookup_by_protein_change:oncokb_names_germline_variants_by_cdna |
A germline lookup was made by protein change. OncoKB names germline variants by cDNA change, so "not curated" may only mean the name did not match. Send the c. name or genomic coordinates |
pdf_not_available:no_browser_in_this_backend |
generate_pdf was asked; the wire backend makes no PDF |
oncomine_transcript_differs:A->B |
Reports only: Oncomine's protein change A was rejected by OncoKB and asked again by position; OncoKB reads it as B |
mane_transcript_differs_from_oncokb |
Reports only: the MANE protein change was rejected by OncoKB and asked again by position |
Browser backend only
| Warning | Meaning |
|---|---|
page_not_settled * |
The site's data calls had not stopped when the result was read |
page_data_incomplete:... * |
Named page data did not arrive |
evidence_tab_unread:TAB * |
A pan-cancer evidence tab could not be read |
effect_description_not_expanded * |
The mutation effect text could not be opened |
tile_level_without_row:... * |
A level tile has no matching table row |
fusion_partner_page_empty:GENE * |
One fusion partner's page was empty |
evidence_rows_unparsed:N |
N rows could not be parsed and are not in the answer |
row_section_mismatch:... |
A row's level does not belong to its section |
page_title_does_not_name_query_alteration |
The page is titled for something else; check page_url |
page_tumor_differs:... |
The page heading names another tumour |
effect_description_rejected_menu_text |
Website menu text was refused as a description |
germline_not_available:browser_backend_reads_somatic_pages |
germline was asked; the browser backend returns the somatic answer |
* The result was under-read. It is returned but not cached, so the next request loads the page again.
tumor_type_missing:pan_cancer_query, gene_hint_differs:A->B, unrecognised_biological_effect:TEXT and the two
report warnings exist on both backends.
Limits
| What | Limit |
|---|---|
| Batch | 100 items |
| Sample | 500 findings, variants and biomarkers together |
| Job | 20,000 items |
| Job results page | 500 results |
| Lookups worked on at once per job, batch or sample | 64 (ONCOKB_JOB_PARALLEL; file jobs always 64) |
| Upload | 1,024 MB per file (ONCOKB_MAX_UPLOAD_MB); 1,100 MB per request at nginx |
| Job retention | 30 days (ONCOKB_JOB_RETENTION_DAYS) |
client_ref, sample_id |
128 characters; assay 64 |
| Stored answer | Reused while OncoKB's data version is unchanged, at most 45 days (ONCOKB_CACHE_MAX_AGE_DAYS). While the data version is unknown: 7 days (ONCOKB_CACHE_TTL_S) |
| Pacing per account | 3 requests in flight (ONCOKB_ACCOUNT_CONCURRENCY), 0.4 s between request starts (ONCOKB_MIN_INTERVAL_S), no daily limit (ONCOKB_ACCOUNT_DAILY_LIMIT=0). Each account can override these |
| Fresh lookups | About 2.5 per second per account at the default pacing. Stored answers are immediate |
| Attempts per lookup | 4 (ONCOKB_MAX_ATTEMPTS) |
| Network timeout towards oncokb.org | 30 s without data (ONCOKB_TIMEOUT_S); 15 s to connect |
| Wait for a free account | Up to 300 s while all accounts are busy, then NO_ACCOUNT_AVAILABLE. While all accounts are resting, a lookup waits only if the shortest rest ends within 10 s (direct call) or 240 s (inside a job); otherwise it fails at once |
| Largest answer accepted from oncokb.org | 400 KB on the wire (ONCOKB_MAX_ANSWER_KB) |
| nginx on the deployed server | 30 requests per second per client address with a burst of 200; 600 s to wait for an answer |
| Genome build | VCF upload GRCh38 only; single variants GRCh37 or GRCh38 |
There is no per-client quota inside the service. Lookups beyond what the accounts can carry wait their turn, so one large job slows everyone's fresh single calls. A fresh lookup can wait up to 300 s for a free account before it is sent: set the client timeout above that (the Python example uses 330 s), or submit a job and poll.
Answers that nginx gives itself are HTML, not the JSON error body: 503 when a client exceeds the request rate, 413 for a request over 1,100 MB, 502 while the service restarts, 504 when an answer takes longer than 600 s, and 403 for an address outside the allow-list if the owner set one up.
oncokb.org answers an unknown gene with its whole evidence table (1.48 MB gzip). The service reads answers as a stream and drops such a download within the first 4 KB, by closing the connection it came on; each account keeps a second connection for lookups that may end this way. Genes OncoKB does not annotate are answered locally without a request.
Not supported: TSO500 or other vendors' TSV formats (send a VCF, or single variants), hg19 VCF upload, structural variants and copy number from a VCF (send single calls), HRD, LOH and mutational signatures, and PDFs on the wire backend.
Client examples
Python, standard library only
import json
import os
import time
import urllib.error
import urllib.request
B, K = os.environ["B"], os.environ["K"]
def call(method, path, body=None, timeout=330):
"""Returns (HTTP status, parsed JSON body, X-Request-ID)."""
req = urllib.request.Request(B + path, method=method,
data=json.dumps(body).encode() if body is not None else None,
headers={"X-API-Key": K, "Content-Type": "application/json"})
try:
with urllib.request.urlopen(req, timeout=timeout) as r:
return r.status, json.loads(r.read()), r.headers.get("X-Request-ID")
except urllib.error.HTTPError as e:
raw = e.read()
try:
out = json.loads(raw)
except ValueError: # nginx answered, not the service (e.g. during a restart)
out = {"status": "error", "errors": [{"code": f"HTTP_{e.code}", "retryable": e.code in (502, 503, 504)}]}
return e.code, out, e.headers.get("X-Request-ID")
def annotate(attempts=4, **body):
"""Returns the annotation; raises on input errors; retries only what the service says is retryable."""
for attempt in range(attempts):
code, out, rid = call("POST", "/api/v1/annotate", body)
if code == 200:
return out
retryable = any(e.get("retryable") for e in out.get("errors", []))
if code >= 500 and retryable and attempt < attempts - 1:
time.sleep(5 * 4 ** attempt) # 5 s, 20 s, 80 s
continue
raise RuntimeError(f"HTTP {code}, request {rid}: {out.get('errors')}")
a = annotate(gene="BRAF", alteration="V600E", tumor_type="MEL")
print(a["status"], a["oncogenicity"]["status"], a["evidence"]["highest_sensitive_level"])
# one sample
code, s, rid = call("POST", "/api/v1/sample", {
"sample_id": "S-001", "tumor_type": "NSCLC", "options": {"detail": "summary"},
"variants": [{"gene": "EGFR", "alteration": "L858R", "vaf": 0.31},
{"gene": "MET", "copy_number_type": "Amplification"},
{"gene": "EML4", "fusion_partner": "ALK"}],
"biomarkers": {"tmb_high": True}})
for t in s["summary"]["therapies_in_tumor_type"]:
print(t["level"], t["regimen"], "for", t["finding"])
for f in s["summary"]["not_read"]:
print("not read:", f["finding"], f["errors"])
# a long list
code, job, rid = call("POST", "/api/v1/jobs", {"items": [
{"gene": "IDH1", "alteration": "R132S", "tumor_type": "AML", "client_ref": "row-1"},
{"gene": "ERBB2", "copy_number_type": "Amplification", "tumor_type": "BRCA", "client_ref": "row-2"}]})
while call("GET", job["poll"])[1]["status"] == "running":
time.sleep(5)
results, offset = [], 0
while True:
page = call("GET", f"{job['poll']}?offset={offset}&limit=500")[1]["results"]
if not page:
break
results += page
offset += len(page)
call("DELETE", job["poll"])
File upload, shell
J=$(curl -s -X POST $B/api/v1/vcf -H "X-API-Key: $K" -F "file=@sample.vcf.gz" -F mode=somatic -F tumor_type=NSCLC \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["job_id"])')
until curl -s $B/api/v1/jobs/$J -H "X-API-Key: $K" | grep -qE '"status": ?"(done|failed)"'; do sleep 10; done
curl -s $B/api/v1/jobs/$J/report.tsv -H "X-API-Key: $K" -o report.tsv
curl -s -X DELETE $B/api/v1/jobs/$J -H "X-API-Key: $K"
Checking the service before a run
curl -s -o /dev/null -w '%{http_code}\n' $B/ready # 200: at least one account can carry requests
curl -s $B/api/v1/info -H "X-API-Key: $K" # OncoKB data version in use
Browser backend
ONCOKB_BACKEND=browser runs the 3.x reader: one account, a Chromium tab per lookup. It is a fallback and is not
installed on the deployed server. /ready, /health and provenance.backend say which backend answers. With the
browser backend:
| Area | Difference |
|---|---|
| Accounts | One account, from ONCOKB_USERNAME / ONCOKB_PASSWORD. /admin/accounts* and /admin/usage answer 404 NOT_AVAILABLE_IN_BROWSER_BACKEND |
| Gene detail | /api/v1/genes/{symbol} answers 404 NOT_AVAILABLE_IN_BROWSER_BACKEND. /api/v1/genes and /api/v1/info work; info.oncokb is null |
germline |
Not available: the somatic answer is returned with the warning germline_not_available:browser_backend_reads_somatic_pages |
reference_genome |
GRCh38 opens the page with ?refGenome=GRCh38. The build is not echoed in query |
generate_pdf: true prints the page to an A4 PDF; artifacts.pdf_url names it |
|
provenance |
source is oncokb.org web page; page_title is set; load_ms is the page load time. No wire_bytes, fetch_ms, account, shared_with_concurrent_request |
query |
No reference_genome |
gene |
hugo_symbol, gene_summary, gene_type, oncogene, tumor_suppressor only |
variant |
canonical_alteration, variant_summary, hotspot, curated_in_oncokb, vus, match only |
mutation_effect |
No abstracts |
evidence |
No oncokb_highest_levels, no articles. Rows have no excluded_cancer_types, abstracts, evidence_id, fda_level, response, approved_indications, drugs_detail |
/ready reasons |
browser_not_started, login_not_configured, not_logged_in |
/health |
In place of started, accounts, oncokb, lookups, traffic, store, require_proxy, cancer_gene_list: browser, browser_started, logged_in, worker_tabs, idle_tabs, page_interval_s, session_token, browser_stats |
| Store | A 7-day cache of finished responses in place of the store of site JSON |
| Cost | About 1.9 MB of traffic per lookup and about 350 MB of memory per tab |