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

  1. Quick start
  2. Conventions
  3. Endpoints at a glance
  4. Annotate one variant
  5. The annotation response
  6. Batch
  7. Sample
  8. Reference data
  9. Jobs
  10. Lab files
  11. Artifacts
  12. Operations endpoints
  13. Accounts and usage
  14. Error codes
  15. Warnings
  16. Limits
  17. Client examples
  18. 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:

  1. 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.current in /health); otherwise the lookup is sent.
  2. 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.cached is true.
  3. oncokb.org. One HTTP GET on one account. provenance.cached is false and provenance.wire_bytes says 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[]:

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
PDF 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